20200527のJavaに関する記事は11件です。

Integerメモ

今回はIntegerクラスのメソッドの使い方について学んでいきます。
随時更新予定です。

compare(int x, int y)

2つのint値を数値的に比較します。
x == yの場合は値0、
x < yの場合は0より小さい値、
x> yの場合は0より大きい値

System.out.println(Integer.compare(1, 2));
System.out.println(Integer.compare(2, 2));
System.out.println(Integer.compare(5, 2));
-1
0
1

compareTo(Integer anotherInteger)

2つのIntegerオブジェクトを数値的に比較します。

このIntegerが引数Integerと等しい場合は値0。
このIntegerが引数Integerより小さい数値の場合は0より小さい値。
このIntegerが引数Integerより大きい数値の場合は0より大きい値。

Integer number = new Integer(100);

System.out.println(number.compareTo(10));
System.out.println(number.compareTo(500));
System.out.println(number.compareTo(100));
1
-1
0

decode(String nm)

StringをIntegerにデコードします。

Integer num = Integer.decode("100");
Integer nm = 100;

System.out.println(num + nm);
200

equals(Object obj)

このオブジェクトを指定されたオブジェクトと比較します。

Integer number = new Integer(100);
Integer num = new Integer(100);
Integer nm = new Integer(500);

System.out.println(number == num);
System.out.println(number.equals(num));
System.out.println(number.equals(nm));
false
true
false

parseInt(String s)

文字列の引数を符号付き10進数の整数型として構文解析します。
戻り値がint型

String str = "123";
int i = Integer.parseInt(str);
int sum = i + 100;

System.out.println(sum);
223

valueOf(int i),valueOf(String s)

指定されたint値を表すIntegerインスタンスを返します。
指定されたStringの値を保持するIntegerオブジェクトを返します。
戻り値がInteger型

int i1 = Integer.valueOf(100);
int i2 = Integer.valueOf("100");

System.out.println(i1 + i2);
200
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jarコマンド入門

第5章 成果物をアーカイブする

JARファイルのオプションについて理解するための事前知識として、
まずはJARファイルの仕様について説明します。

JARファイルの構成

JARファイルには、以下の要素を含めることができます。
それぞれの要素について、「sample-root.jar」というJARファイルがあると仮定し、説明します。
スクリーンショット 2020-05-27 15.11.58.png

それぞれの概要について、以下に説明します。

INDEX.LIST

jarコマンドの-iオプションで生成されるファイル。
このファイルが格納されているJARファイルと、それが依存している他のJARファイル内に
格納されているパッケージの位置情報をインデックス化することで、
クラスローダの処理高速化に利用される。

INDEX.LISTのサンプル
JarIndex-Version: 1.0

sample-root.jar
com
com/example
com/example/app
依存しているJARファイルがある場合、その情報も以下に続く...

MANIFEST.MF

マニュフェストファイルは、JARファイルの各種メタ情報を保持するファイルです。
メインセクションと個別セクションから構成され、「属性: 値」のペア方式で設定が可能です。
同じ属性が複数設定された場合は、個別セクションのものが優先されます。

#==========メインセクション==========
# バージョン情報(必須)
Manifest-Version: 1.0
# メイン属性
# 属性: 値

# メインセクションと個別セクションの間は必ず1行空ける
# ===========個別セクション===========
# エントリ別属性
# 属性: 値

以下、マニフェストファイルに設定できる主な属性です。

【メイン属性】

  • Manifest-Version: <バージョン>
    マニフェストファイルのバージョンを定義する。整数およびピリオドしか設定できない。
  • Created-By: <作成者>
    このマニフェストファイルが生成されるJavaのバージョンおよびベンダーを定義する。
    この属性は、jar ツールによって自動生成される
  • Signature-Version: <バージョン>
    jarファイルの署名のバージョンを定義する。
  • Class-Path:
    JARファイル内のクラスローダでは、この属性の値を使って内部検索パスが構築される。
    必要な拡張機能またはライブラリの相対URLを指定する。URL は 1 つ以上の空白で区切る。

その他にも、

  • スタンドアロンアプリケーションに対して定義する属性(Main-Classヘッダなど)
  • アプレットに対して定義する属性
  • 拡張機能の識別のために定義する属性
  • 拡張機能およびパッケージのバージョン管理とシーリング情報のために定義する属性

など、様々な属性が存在する。

【エントリ別属性】

  • Content-Type: <データタイプ>
    JARファイルの特定のファイルのMIMEタイプおよびサブタイプを指定する。
    値は、「タイプ/サブタイプ」の形式の文字列でなければならない。
  • Java-Bean:
    特定のjarファイルエントリが、Java Beansオブジェクトかどうかを定義する。
  • 拡張機能およびパッケージのバージョン管理とシーリング情報のために定義する属性
    メイン属性に同じ。

署名付きJARファイル

sample-root.DSAやsample-root.SFは、署名に関するファイルですが、
今回の記事ではJavaのセキュリティ面に関するツールに言及しないため割愛します。

servicesディレクトリ

外部のJARファイルの機能を利用するためのサービスプロバイダーという機能があり、
外部のJARファイルとのインターフェースとなる具象クラスを格納するディレクトリ。
今回は説明を割愛するため、詳しく知りたい人は以下の記事を参照してください。
参照記事:JARファイル - サービスプロバイダ機能

jarコマンドのオプション

ファイルの操作系のオプション

  • c : 新規作成
  • u : 更新
  • x : ファイル、ディレクトリの抽出
  • t : アーカイブ内容の一覧表示
  • f : JARファイルの指定

マニュフェスト系のオプション

  • M : マニフェストファイルを作成しない
    • cまたはuの場合 : マニフェストファイルを作成しない
    • uかつマニフェストファイルが存在する場合 : マニフェストファイルを削除する
  • m : 指定したマニフェストファイルの属性ペアを追加する
    • 同名の属性が存在する場合 : 指定したマニフェストファイルの属性ペアで上書きする
    • 同名の属性が存在しない場合 : 指定したマニフェストファイルの属性ペアを追加する

その他のオプション

  • v : jarコマンドが行なった操作や格納されているファイルの一覧などの詳細情報を表示する
  • 0 : ZIPによる圧縮をしないでJARファイルを生成する
  • i : 指定したJARファイルにINDEX.LISTを作成する
  • -C <ディレクトリ> <対象>: 一時的にディレクトリを移動する
    処理中にディレクトリに移動するため、jarコマンドを実行したカレントディレクトリから
    ではなく引数に渡したディレクトリからの相対パスで対象を指定できる
  • -J<オプション> : JREにオプションを渡す。渡すことができるオプションはjavaコマンドのもの

jarコマンドの実例集

※オプション内の[v0M]などの表記は必須ではないが使用可能なオプションです。

作成(cオプション)

# inputfiles以下のリソースでjarfileという名前のJARファイルを作成する
jar c[v0M]f jarfile [-C dir] inputfiles [-Joption]
# inputfiles以下のリソースでjarfileを作成し、
# manifestに値を追記する(削除はしない)
jar c[v0]mf manifest jarfile [-C dir] inputfiles [-Joption]

【mオプションとfオプションの記載順について】
mオプションとfオプションの記載順は決まっていないが、
cmfならばmanifest jarfile、cfmならjarfile manifestというように、
後続の引数の順番を合わせる必要がある。

更新(uオプション)

# inputfiles以下のリソースで、変更のあった箇所のみをjarfileに反映し、更新する
jar u[v0M]f jarfile [-C dir] inputfiles [-Joption]
# inputfiles以下のリソースで変更のあった箇所のみをjarfileに反映し、
# manifestの更新を行う(値の追加もしくは削除)
jar u[v0]mf manifest jarfile [-C dir] inputfiles [-Joption]

抽出(xオプション)

# jarファイル内の全てのディレクトリとファイルを抽出(解凍)する
# inputfilesを指定した場合は、指定した対象以下を抽出する
jar x[v]f jarfile [inputfiles] [-Joption]

一覧表示(tオプション)

# jarファイル内の全てのディレクトリとファイルを一覧表示する
# inputfilesを指定した場合は、指定した対象以下を一覧表示する
jar t[v]f jarfile [inputfiles] [-Joption]

インデックスの作成(iオプション)

# 指定したjarfileにINDEX.LISTを作成する
jar i jarfile [-Joption]

実行

以下、最初のフォルダ構成です。
スクリーンショット 2020-05-27 18.00.56.png

JARファイルの作成

JARファイルを指定して(f)、詳細な情報を出力し(v)、
java-sample.jarというJARファイルを新規作成(c)します。

# カレントディレクトリは/java-sampleです
$ jar cvf java-sample.jar .
マニフェストが追加されました
.DS_Storeを追加中です(=6148)(=411)(93%収縮されました)
lib/を追加中です(=0)(=0)(0%格納されました)
lib/commons-lang3-3.10.jarを追加中です(=523372)(=481881)(7%収縮されました)
src/を追加中です(=0)(=0)(0%格納されました)
src/com/を追加中です(=0)(=0)(0%格納されました)
src/com/example/を追加中です(=0)(=0)(0%格納されました)
src/com/example/app/を追加中です(=0)(=0)(0%格納されました)
src/com/example/app/UseCommons.javaを追加中です(=647)(=286)(55%収縮されました)
src/com/example/app/StrFactory.classを追加中です(=308)(=234)(24%収縮されました)
src/com/example/app/UseCommons$CommonsHelper.classを追加中です(=592)(=398)(32%収縮されました)
src/com/example/app/StrFactory.javaを追加中です(=115)(=101)(12%収縮されました)
src/com/example/app/UseCommons.classを追加中です(=732)(=441)(39%収縮されました)

カレントディレクトリにjava-sample.jarが作成されます。
スクリーンショット 2020-05-27 18.07.51.png

JARファイルの一覧表示

# カレントディレクトリは/java-sampleです
$ jar tf java-sample.jar
META-INF/
META-INF/MANIFEST.MF
.DS_Store
lib/
lib/commons-lang3-3.10.jar
src/
src/com/
src/com/example/
src/com/example/app/
src/com/example/app/UseCommons.java
src/com/example/app/StrFactory.class
src/com/example/app/UseCommons$CommonsHelper.class
src/com/example/app/StrFactory.java
src/com/example/app/UseCommons.class

JARファイルの解凍

java-sample直下で実行すると既存のファイルと解凍されたファイルが混じるので、
unzipというフォルダを作成し、そこへ解凍します。

# カレントディレクトリは/unzipです
$ jar xf ../java-sample/java-sample.jar

unzip直下にJARファイルの解凍結果が展開されます。
スクリーンショット 2020-05-27 18.12.10.png

メインページに戻る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javaコマンド入門

第4章 コードを実行する

Javaアプリケーションの種類

javaコマンドによるアプリケーションの実行について説明する前に、
Javaのアプリケーションにはどういったものがあるのかを見ていきます。

以下、Javaアプリケーションの大まかな分類です。
説明もざっくりしているので、気になった方はご自身で調べてください。

  • コンソールアプリ
    PromptやTerminalなど、コンソールから対話方式で利用するアプリ。
  • デスクトップアプリ
    1端末内で完結しているアプリ。GUIと言われることもある。
  • Webアプリ
    Webサーバとクライアント間の通信により処理を行うアプリ。
  • Androidアプリ
    Android向けのデスクトップアプリ。(ものの例えです)
  • 組み込み系プログラム
    家電など、ハードウェアに直接組み込まれたプログラム。

javaコマンドでは主に、コンソールアプリやデスクトップアプリの実行を行います。

javaコマンドの概要

javaコマンドを実行すると、Javaアプリケーションが起動します。
javaツールはまずJREを起動し、コマンドで指定されたクラスをロードします。
ロードされたクラスのmainメソッドが呼び出されることにより、mainメソッド内で呼び出される
他のクラスを順次ロードしながら、アプリケーションが実行されていきます。

mainメソッドを持つクラスの指定方法には、
クラスを直接指定する方法と、JARファイルを指定する方法があります。

mainメソッドの規約

mainメソッドはpublicでstaticであること、引数にString型の配列を取ること、
戻り値を返さないことを満たしたメソッドである必要がある。

mainメソッド
    public static void main(String[] args) {
        // 何らかの処理
    }

javaコマンドの基本構成

# java [ options ] class [ argument ... ]
$ java HelloWorld "args1" "args2"

上記の例では、HelloWorldクラスのmainメソッドが呼び出され、mainメソッドの引数argsには
"args1"と"args2"が格納されたString型の配列が渡されます。

クラスファイルの実行

クラスファイルの実行には、完全指定のクラス名を指定する必要があります。
上記の例ではパッケージ構成を取っていなかったため、
パッケージを指定しなくても実行できましたが、パッケージ構成をとっている場合には
パッケージを指定した完全指定でクラス名を指定する必要があります。

# カレントディレクトリは/src
# /srcをパッケージルートとし、HelloWorldが/src/com/example/app直下にある場合
$ java com.example.app.HelloWorld

JARファイルの実行

JARファイルを指定する場合、JARファイルにアーカイブされたクラスファイルから
mainメソッドを持つ起動クラスを特定するため、マニフェストファイルのMain-Classヘッダを
設定する必要があります。ここら辺の詳細は、以下の記事がわかりやすかったです。

参照記事:JARファイル入門 @hiwm0126

JARファイルの起動には、JARファイルの配置先を指定します。(絶対パス、相対パスどちらも可)
また、起動クラスにJARファイルを指定する場合は-jarオプションを付与する必要があります。

# カレントディレクトリは/(ルート)
# /lib/jars/sample-app.jarを実行する
$ java -jar /lib/jars/sample-app.jar

javaコマンドのオプション

主要なオプション

  • -classpath(または-cp) <パス>
    ユーザクラスの検索先を指定する。
    複数選択時はセミコロン(Windows)、またはコロン(Unix)で区切る。
  • -jar <パス>
    起動クラスにJARファイルを指定する。パスにはJARファイルの配置先を指定する。
  • -version
    Javaのバージョン情報を表示する。
  • -D<プロパティ名>=<値>
    Javaのシステムプロパティを設定する。設定した値は以下のように取得できる。
$ java -Dsun.boot.class.path="/sample/path" SampleApp
SampleAppクラス
// 設定した値「/sample/path」が取得できる
System.getProperty("sun.boot.class.path");

アサーション系のオプション

Javaのアサーションの有効、無効を設定するオプションです。
アサーションは、デフォルトでは無効になっています。

  • -enableassertions(または-ea):<適用範囲>
    アサーションを有効にする。適用範囲の指定には、以下の種類がある。
    • <パッケージ名>...
      指定したパッケージとそのサブパッケージで有効になる。
    • ...
      カレントディレクトリのデフォルトパッケージ(無名パッケージ)で有効になる。
    • <クラス名>
      指定したクラスで有効になる。
    • 引数なし
      システムクラスを除く全てのクラスで有効になる。
  • -disableassertions(または-da):<有効範囲>
    アサーションを無効にする。適用範囲の指定は、-enableassertionsオプションと同じ。
  • -enablesystemassertions(または-esa)
    全てのシステムクラスのアサーションを有効にする。
  • -disablesystemassertions(または-dsa)
    全てのシステムクラスのアサーションを無効にする。

デバッグ系のオプション

  • -verbose:{keyword list}
    コンマで区切られたキーワードリストにより指定された情報を通知する。
    • class
      クラスがロードされるタイミングで、クラスに関する情報を表示する。
    • gc
      ガーベジコレクションが動くたびに起動を通知する。
    • jni
      ネイティブメソッドの使用、Java Native Interfaceアクティビティの情報を通知する。

HotSpot系のオプション

HotSpotとは、JVMに組み込まれている処理高速化のための技術の総称。
JITコンパイラ(実行時コンパイラ)の一種で、一定回数以上実行されたメソッドのみを
コンパイルするなど、処理最適化のための仕組みが用意されている。

HotSpotにはJava HotSpot Client VM(クライアント版)とJava HotSpot Server VM(サーバ版)の
2種類があり、それぞれ以下の特徴がある。

  • クライアント版
    コンパイル対象を重要なクラス、メソッドに絞り、高速なロードを重視する。
  • サーバ版
    全体的にコンパイルするのでロードは遅くなるが、最適化を重視する。

以下は、利用するHotSpotを指定するためのオプションです。

  • -client
    Java HotSpot Client VMを選択して起動する。
  • -server
    Java HotSpot Client VMを選択して起動する。

ネイティブエージェントライブラリ系のオプション

Javaには、Java以外でコーディングしたプログラムを利用する仕組みがあり、
Java Virtual Machine Tool Interface(JVMTI)を介してエージェント(JVMTIのクライアント)と
やり取りすることで利用が可能となる。
このエージェントが、Java以外の言語で実装された各種ツールである。

以下のオプションは、これらのネイティブエージェントライブラリを利用するためのオプションである。

  • -agentlib:<ライブラリ名>=<オプション>
    ネイティブエージェントライブラリを指定し、ロードする。
  • -agentpath:<ライブラリのフルパス>=<オプション>
    フルパスでネイティブエージェントライブラリを指定し、ロードする。

実行

それでは、サンプルコードを実行していきます。

サンプルコードでは、Nullもしくは空文字が渡されると"NG"を、
それ以外の場合は引数の文字列を返すメソッドの処理結果を3件出力しているので、
"NG"、"NG"、"Hello World!"の3行が出力されるはずです。

# カレントディレクトリは/java-sample/srcです
$ java -cp /java-sample/lib/commons-lang3-3.10.jar:/java-sample/src com.example.app.UseCommons
# 以下、出力結果です
NG
NG
Hello World!

メインページに戻る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javacコマンド入門

第3章 ソースコードをコンパイルする

Javaにおけるコンパイルとは

コンパイルとは、平たく言えば人間にわかるように書かれたソースコードを
機械が理解できる機械語に翻訳する作業です。

Javaのコンパイルの仕組みは独特で、javacコマンドはソースコードを
Javaバイトコード(中間コード)というものにコンパイルします。

なぜ、機械語に変換しないのかというと、
Javaの基本理念「Write once, run anywhere.」の実現のためです。
ソースコードを直接機械語に変換してしまうと、コンパイルされた機械語は
コンパイルを実行した環境に「依存」するようになりますが、
JVMにはJavaバイトコードを機械語に変換する機能が実装されているため、
JVMさえ導入すればどのような環境であってもJavaを実行できるようになります。
つまり、「ソースコードを一度書いてしまえば、環境が異なっても実行できる」のです。

javacコマンドの概要

javacを実行した際のコンパイルは、以下のような動きで行われます。

  1. 指定したクラスを解析し、依存関係のある型を検索する
  2. 検索で該当した型をコンパイルする

ここで重要になるのが、「1. 型の検索」です。
Javaは、コンパイルの際、指定したクラスが必要とする全ての型の情報を必要とします。
必要とする型には、具体的には以下のものがあります。

  • ソースコードで使用されているクラス、インターフェース
  • 使用クラスで暗黙的に継承、実装されているクラス、インターフェース

ここで注意するのが、暗黙的に継承、実装されているクラス群です。
例えばjava.util.ArrayListクラスをコンパイルするには、ArrayListが継承する
Serializable, Iterable, Collection などのインターフェースの情報も必要としますが、
ソースコードにそれらの情報は現れません。

検索の順序

型の検索対象にはいくつかの領域があり、それらを検索していく順序は決まっています。
検索対象の領域には以下のものがあります。(検索される順序で並んでいます)

  • ブートストラップ・クラス
    JDKのコアAPI(例:java.lang.*)などを含むクラス群です。
    一般的には<JAVA_HOME>/libに配置されています。
  • 拡張機能クラス 拡張用ディレクトリに配置されたクラス群です。
    一般的には<JAVA_HOME>/lib/extに配置します。
    ※Java8以降では廃止された仕様のため、利用できません。
  • ユーザクラス
    CLASSPATH環境変数、または-classpathオプションに設定されたパスに配置します。
    上記を設定していない場合は、カレントディレクトリが設定されます。

上記の検索順序は、
実行時にクラス情報をメモリへとロードするクラスローダにおいても同じです。
クラスローダの詳細については「クラスローダとは」を参照してください。

javacを実行すると、上記の順序で検索が行われ、
同じ型が複数検出された場合は検索の優先度が高い領域の情報が使用されます。

検索結果に対する挙動

コンパイル時、型の検索で見つかるファイルは状況によって
クラスファイル、ソースファイル、またはその両方である場合があります。
javacの行う処理は、見つかったファイルの種類や状況によって以下の3つに分かれます。

【クラスファイルのみが見つかった場合】
 コンパイルは行わず、クラスファイルをそのまま使用する

【ソースファイルのみが見つかった場合】
 ソースファイルをコンパイルし、生成したクラスファイルを使用する

【両方が見つかった場合】
 〜クラスファイルがソースファイルより古い場合〜
  ソースファイルをコンパイルし、最新の状態で生成したクラスファイルを使用する
 〜上記以外の場合〜
  コンパイルは行わず、クラスファイルをそのまま使用する

クロスコンパイル

開発をしていると、Java2 SDKを使っているので、javacはJava2 SDKの
ブートストラップクラスに対してコンパイルを行うが、Java 2 SDK ではなく JDK 1.4 の
ブートストラップクラスを使用したいというような場合も発生します。

こういった場合は、-target 1.4オプションにより、1.4 VM と互換性のあるクラスファイル
を生成し、-bootclasspathおよび-extdirsを使ってJDK 1.4 のブートストラップクラス
に対してコンパイルを行うように指定します。

このように、バージョンなどをまたいだコンパイルを行う機能を
クロスコンパイルと言います。

javacコマンドのオプション

Javaのコンパイルについて一通りの用語を理解したところで、
各種設定、指定を行うためのオプションについて見ていきます。

主要なオプション

  • -encoding <文字コード>
    ソースファイルの文字コードを指定する。デフォルトでは Javaプラットフォームのコンバータ(ソースコード↔︎Javaバイトコードの変換を行う)
    に設定されているエンコードを使用する。
  • -sourcepath <パス>
    ソースファイルの配置先を指定する。デフォルトではユーザクラスパスが指定されている。
  • -d <パス>
    クラスファイルの配置先を指定する。デフォルトではユーザクラスパスが指定されている。
  • -classpath(もしくは-cp) <パス>
    ユーザクラスの検索先を指定する。
    複数選択時はセミコロン(Windows)、またはコロン(Unix)で区切る。
  • -source <バージョン>
    ソースコードに関して、特定のJDKバージョンのみ受け入れを許可する。

デバッグ系のオプション

  • -verbose
    このオプションを指定しない場合、コンソールには指定したクラス以外の
    型の検索で見つかったクラスに関するコンパイル情報などは出力されない。
    verboseオプションの指定により、それらの詳細な情報を見ることができる。
  • -g
    ローカル変数を含むすべてのデバッグ情報を生成する。
    デフォルトでは、行番号およびソースファイル情報だけが生成される。
  • -g:{keyword list}
    コンマで区切られたキーワードリストにより指定されたデバッグ情報だけを生成する。
    • none
      デバッグ情報を出力しない
    • source
      ソースファイルのデバッグ情報
    • lines
      行番号のデバッグ情報
    • vars
      局所変数のデバッグ情報

クロスコンパイル系のオプション

  • -target <バージョン>
    指定されたバージョンのVM上で動作するクラスファイルを生成する。
    デフォルトでは、JDK5 VMと互換性のあるクラスファイルを生成する。
    ただし、-source 1.4 以下のオプションが使用されている場合のみ、デフォルトは1.4となる。
    javac でサポートされているバージョンは次のとおり。
    • 1.1
      JDK 1.1 以降の VM で実行するクラスファイルを生成。
    • 1.2
      JDK 1.2 より前の VM 上では動作しないクラスファイルを生成。
    • 1.3
      JDK 1.3 より前の VM 上では動作しないクラスファイルを生成。
    • 1.4
      JDK 1.4 より前の VM 上では動作しないクラスファイルを生成。
    • 1.5
      JDK 5 の VM のみと互換性のあるクラスファイルを生成。
    • 5
      1.5 と同義。
  • -bootclasspath <パス>
    指定されたブートクラスに対してクロスコンパイルを行う。ユーザクラスパスと同様に、
    ブートクラスパスの複数のエントリはセミコロンまたはコロンで区切る。
    ブートクラスパスには、ディレクトリ、JARアーカイブ、ZIPアーカイブを指定できる。

実行

UseCommons.javaの実行には、以下の情報が必要です。

  • メインメソッドを持ったクラス(UseCommons.java)
  • 実行クラス内で使用されているクラス情報(StrFactory.java、commons-lang3-3.10.jar)

上記の情報を集めるため、javacコマンドは以下の情報を必要とします。

  • 実行するクラスであるUseCommonsの配置場所
  • 実行クラス内で使用されているStrFactoryとcommons-lang3-3.10.jarへのクラスパス
    • StrFactoryが配置されているパッケージのパッケージルート
    • commons-lang3-3.10.jarの配置場所
      ※JARファイルとクラスファイルでは指定方法が違うため、設定内容の表記が若干違います

具体的なコマンドは以下の通りです。

# カレントディレクトリは/java-sample/src
$ javac -cp /java-sample/lib/commons-lang3-3.10.jar:/java-sample/src com/example/app/UseCommons.java

以下はクラスパスの指定です。

# JARファイルのクラスパス指定(ファイルまで指定する)
/java-sample/lib/commons-lang3-3.10.jar
# クラスファイルのクラスパス指定(ファイルまで指定しない)
/java-sample/src
# 上記のように、複数のクラスパスを指定する場合は:(Windowsの場合は;)で連結する
-cp /java-sample/lib/commons-lang3-3.10.jar:/java-sample/src

最後に実行するクラスを指定します。

# 例ではカレントディレクトリからの相対パスで指定している
com/example/app/UseCommons.java

以下、実行結果です。
スクリーンショット 2020-05-25 21.23.45.png

見ると、xxx.javaと同名のxxx.classファイルが作成されています。
また、UseCommons内に定義されたクラスに関しては、UseCommons$CommonsHelper.class
のように、クラス名$インナークラス名.classの形式のファイルが作成されます。

javacコマンドのその他の使用例

複数ファイルのコンパイル

正規表現を使用すると、複数ファイルをコンパイルできます。
この場合、対象となるクラスが必要とするクラスへのクラスパスを
全て設定しておく必要があります。

# multipleディレクトリ内のクラス全てをコンパイルする
javac multiple/*.java
# multipleディレクトリ内の〜Targetというクラス全てをコンパイルする
javac multiple/*Target.java

ソースファイルとクラスファイルの格納先を分ける

今までの例だと、同じディレクトリにクラスファイルが作成されるため、
JARファイルの作成時に余計な手間がかかる上、フォルダが整頓されず見づらくなります。
そういう時は、-dオプションでクラスファイルの格納先を、-sourcepathでソースファイルの
格納先を指定することができます。

# 実行すると、src直下に.javaファイルが、classes直下に.classファイルが格納される
javac -sourcepath src -d classes /src/com/example/app/Sample.java

クロスコンパイル

以下の例は、前提条件としてJava2 SDKが設定されたプラットフォームを想定しています。
以下のコマンドを実行すると、Java2 SDKのJava2プラットフォームAPIではなく、
JDK1.4のコアAPIを使用してコンパイルが行われるようになります。

補足:-bootclasspathの設定値について
-bootclasspathにはディレクトリのほかJARファイルやZIPファイルなどが
指定できるため、独自にブートストラップクラスをまとめて格納したJARファイルを
作成しておくと、複数のエントリを指定する手間が減ります。

# -target 1.4:JDK1.4以上と互換性のあるクラスファイルを生成する
# -bootclasspath <パス>:指定したパスにあるブートストラップクラスを使用してコンパイルを行う
javac -target 1.4 -bootclasspath <ブートストラップクラスのアーカイブ配置先> Sample.java

補足:ブートストラップクラスの格納先の確認方法
ブートストラップクラスの格納先は、
システムプロパティsun.boot.class.pathに設定されています。

コマンド行引数ファイル

javacにはコマンド行引数ファイルという、ファイルを使用して
複数クラスと複数オプションを指定する仕組みがありますが、これを使いこなす
コストを考えるとビルドツールを勉強した方がいいと思うので割愛します。

メインページに戻る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【弊社新人に向けて】開いたら必ず閉じよう

何が言いたいの?

開いたら必ず閉じようということです。
ファイルが開きっぱなしになっていると、場合によってはファイルの読み書きが行えなくなります。
それでは困りますね。

例えば?

FileReaderクラスやFileWriterクラスを用いて、テキストファイルを読み書きする場合などです。
昔はBufferdReaderクラスなんかを使っていましたが、今どきはScannerクラスなるものが使われているようですね。

実際にテキストファイルの内容を読み込み、内容をコンソールに出力するプログラムを以下に示します。

サンプルプログラム
import java.io.File;
import java.util.Scanner;

public class FileOpenTest {
    public static void main(String[] args) {
        try {
            // テキストファイルを開く
            Scanner scanner = new Scanner(new File("F1歴代チャンピオン一覧.csv"));

            // 1行ずつ読み込み、コンソールに出力
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }

            // テキストファイルを閉じる
            scanner.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
出力内容
1950年,ジュゼッペ・ファリーナ,アルファロメオ,-
1951年,ファン・マヌエル・ファンジオ,アルファロメオ,-
1952年,アルベルト・アスカリ,フェラーリ,-
1953年,アルベルト・アスカリ,フェラーリ,-
1954年,ファン・マヌエル・ファンジオ,マセラティ/メルセデス,-
1955年,ファン・マヌエル・ファンジオ,メルセデス,-
1956年,ファン・マヌエル・ファンジオ,フェラーリ,-
1957年,ファン・マヌエル・ファンジオ,マセラティ,-
1958年,マイク・ホーソーン,フェラーリ,ヴァンウォール
1959年,ジャック・ブラバム,クーパー・クライマックス,クーパー
(内容はwikipediaより借用)

無事、テキストファイルの読み込みに成功しました?:clap:

では終わりません

ほとんどの場合、読み込んだ行に対して何らかの加工を行います。

何らかの処理
            // 1行ずつ読み込み、何らかの処理を行う
            while (scanner.hasNextLine()) {
                anyProcess(scanner.nextLine());
            }

もし、この処理内で例外が発生したらどうなるでしょう。
今回の場合try文で処理全体を囲っているので、catchブロックへ処理が移ります。

例外を補足
        } catch (Exception e) {
            e.printStackTrace();
        }

これで無事に例外を補足し、エラーログを出力することができました?:clap:

ではありません

一つ忘れていることがあります。
例外が発生したらcatchブロックへ処理が移る...

そうです。
ファイルが閉じられていません?

        try {
            // テキストファイルを開く
            Scanner scanner = new Scanner(new File("歴代チャンピオン一覧.csv"));

            // 1行ずつ読み込み、何らかの処理を行う
            while (scanner.hasNextLine()) {
                anyProcess(scanner.nextLine());  // エラーが発生
            }

            // テキストファイルを閉じる
            scanner.close();                     // 実行されない!!

        } catch (Exception e) {
            e.printStackTrace();                 // ここまで処理が飛んでしまう
        }

どうすればいいの

何がなんでもファイルを閉じたい...
そこでfinallyブロックの登場です。

finallyブロックは、処理にエラーがあったか無かったかに関わらず必ず実行されます。
finallyブロックを追加したコードを以下に示します。

finally ブロックを追加
import java.io.File;
import java.util.Scanner;

public class FileOpenTest {
    public static void main(String[] args) {

        // try文のブロックの外に変数を宣言する
        Scanner scanner = null;

        try {
            // テキストファイルを開く
            scanner = new Scanner(new File("歴代チャンピオン一覧.csv"));

            // 1行ずつ読み込み、何らかの処理を行う
            while (scanner.hasNextLine()) {
                anyProcess(scanner.nextLine());
            }

            // テキストファイルを閉じる
            scanner.close();

        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            // テキストファイルを閉じる
            if (scanner != null) {
                scanner.close();
            }
        }
    }
}

まず、try文のブロックの外側にScannerクラスの変数を宣言します。
try catch finallyは、それぞれ異なるスコープと見なされるためです。
tryブロックの中で宣言された変数は、finallyブロックから参照することができないのです。

その後、実際にファイルを閉じていきます。
この時、scannar変数がnullかどうかの判定を忘れてはいけません。
scannar変数は宣言時にnullを格納しています。

初期値には null を設定
        // try文のブロックの外に変数を宣言する
        Scanner scanner = null;

nullに対してメソッドの呼び出しを実行すると、これまた別の例外が発生してしまいます。

書いてる途中で知ってしまった

try-with-resources文なるものがあるようです
どう考えてもこっちの方が便利ですよね。C#Usingみたい。
参考:Oracleのサイト

まとめ

少々ばかり内容が古臭い気がしますが...まあ良いでしょう。
開いたら閉じる。便器のフタと同じです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Bootでテストがコマンドラインから実行できない問題を解決

動作環境

java 1.8
Spring Boot 2.2.4
JUnit4

プロジェクト構造

  • 初学者のため構造が雑なのはご容赦下さい
 src
│   ├── main
│   │    └── 省略
│   │
│   └── test
│       └── java
│           └── com
│               └── testTool
│                   ├── TestToolApplicationTests.java
│                   └── web
│                       ├── controller
│                       │   └── TestToolControllerTest.java
│                       └── service
│                           └── TestToolServiceTest.java

問題点

  • $ mvn test のコマンドを打てばsrc/test配下のjavaファイルがすべて実行されると思っていた。
  • しかし実行されたのはTestToolApplicationTests.javaのみであった
  • どうやらsrc/test/web配下に存在するjavaファイルは読み込まれていないみたいだ
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.028 s
[INFO] Finished at: 2020-05-27T15:42:18+09:00
[INFO] ------------------------------------------------------------------------

解決策

  • pom.xmlに下記を追加
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- ここから追加 -->
            <plugin> 
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
                <dependencies>
                    <dependency>
                        <groupId>org.apache.maven.surefire</groupId>
                        <artifactId>surefire-junit4</artifactId>
                        <version>2.22.0</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <includes>
                        <include>**/*.java</include>
                    </includes>
                </configuration>
            </plugin>
            <!-- ここまで追加 -->
        </plugins>
</build>

結果

  • 実行できた
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.559 s
[INFO] Finished at: 2020-05-27T16:39:06+09:00
[INFO] ------------------------------------------------------------------------

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

formatter-maven-pluginを使用したenumのフォーマット方法(Java)

概要

formatter-maven-plugin を使用してenumのコードの自動フォーマットを行います。

実現したいフォーマット

実行前

public enum Answer {

  YES(1),NO(2),MAYBE(3);
}

実行後

public enum Answer {

  YES(1),
  NO(2),
  MAYBE(3);
}

設定箇所

設定ファイル(xml)の alignment_for_enum_constants の値を 49 にすることで上記フォーマットをかけることができました。

    <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSlで,Vue.jsによるアンドロイドアプリ開発環境を構築しようとしたときにハマった

備忘録

【Vue.js】WSL 上で Vue.js を用いた Android アプリを開発する
こちらを用いて,よっしゃ開発環境作るどーーと意気込んでいたら…

sudo $ANDROID_HOME/tools/bin/sdkmanager "tools" "emulator" "platform-tools" "platforms;android-28" "build-tools;28.0.3" "extras;android;m2repository" "extras;google;m2repository"

Error: Could not find or load main class com.android.sdklib.tool.sdkmanager.SdkManagerCli

とのエラーが出た.調べていると,JDKが8よりも新しいものを使うとうまくいかないとのこと.この段階で最新版のjava14を入れていた.
入れなおしてもう一度!

としたが変わらなかった.いろいろ探しまくった結果,以下でsdkmanagerのバージョンを古くするといけた.

エラー:メインクラスcom.android.sdklib.tool.sdkmanager.SdkManagerCli #5304が見つからないか、読み込めませんでした

https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
結局これでダウンロードしたtoolsに置き換えるとうまくいった.

めっちゃ悩んだのにあっけない…
というか,最新のを使う方法はないんでしょうか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのロゴを調べた話(そしてわからなかった話)

謎ロゴとの出会い

先日、YouTubeでプログラミング関係の動画を見ていたらJavaScriptの話題とともにこんな画像が出てきました。

これを見て僕は「あちゃー、JavaとJavaScriptを混同しちゃってるのね:sweat_smile: 初心者よくある、どんまい:hand_splayed:」と思い、コメント欄に「JavaとJavaScriptは別物ですよ?」と書き込み、送信ボタンを押そうとしたその瞬間、突然嫌な予感がしてその手を止めました。

(いや、動画内で一瞬表示させるためにJavaのアイコンとテキストを組み合わせてロゴを作ったとは思えないし、このロゴは本当に存在しているのでは…?)

ググってみたら案の定、素材として配布されているロゴでした。

スクリーンショット 2020-05-27 12.17.56.png

JavaScriptの公式ロゴ

現在、JavaScriptに公式ロゴは存在しません。(そもそも現在の「公式」というのがEcma InternationalなのかMozillaなのかJavaScriptの商標を持っているSun/Oracleなのかという話もあるのですが)
よく見かける、黄色地に黒文字でJSと書かれているロゴは「JS Logo By The Community」です。
盾っぽいロゴはW3CによるHTML5のロゴに合わせて同じスタイルでCSS3とJSが作られたものだと思われます。(W3CがCSS3のアイコンを提供しているにもかかわらず、別でCSS3の盾デザインが存在しているので、その流れでJSも作られたのではと思っているのですが、ソース無しなので自信ないです)

なのでこの謎ロゴが存在する理由として以下のものが考えられます。

  1. 過去にいずれかの公式だったもの(あるいはそれを加工したもの)
  2. JavaScriptコミュニティ向けなど何かしら真面目な理由で作られたもの
  3. Java≠JavaScriptのパロディとして作られたもの

1はかなり大穴ですが、Java人気にあやかってLiveScriptがJavaScriptに名前を変えたくらいなので、当時はJavaに合わせたロゴにしていたという可能性は捨てきれません。

謎ロゴの出自を探る

謎ロゴ自体の出自がわかれば話は簡単なのですが、画像検索をしてみても素材配布サイトばかりヒットしてなかなか情報が出てきません。
代わりにJavaScriptの歴史を紹介するスライド記事コミュニティカレッジのコース紹介などで登場しているのを発見しました。
やっぱり過去に公式ロゴだったのでは?という気持ちが出てきます。

JavaScriptの過去のロゴを探す

NetscapeのJavaScriptドキュメント(Internet Archive)やEcma International、Mozilla、Google Booksで初期のJavaScriptの洋書、YouTubeのNetscape利用動画などを当たってみましたが、JavaScriptのロゴは謎ロゴ含めて全く登場しません。
アメリカ合衆国特許商標庁の商標検索では図案付きのJavaの商標(Serial Number 76495912)は見つかったもののJavaScriptの商標(Serial Number 75026640)には図案がありませんでした。

いかがでしたか?

JavaScriptの謎ロゴについて調査してみましたが、結局わかりませんでした。
このロゴを知っているよ!という方がいましたら、ぜひコメント欄で情報をお寄せください。

謝辞

もともとはQiitadonに何気なく投稿した謎ロゴの話ですが、ユーザーの皆さんの協力があってこの記事がまとまりました。
一緒に調査してくれた方、⭐で後押しをしてくれた方、ありがとうございます。
(もし記事に事実誤認やつまらないジョークが含まれていた場合、その責は私にあります)

おまけ

謎ロゴが載ってる謎ページ
http://computerprogrammingsteppingstone.weebly.com/java-script.html
白背景に白文字の怪しさもさることながら、さらに新しい謎ロゴが登場して調査団を混乱させる。
新しい謎ロゴはGoogleの画像検索では類似画像が見つからないものの、Bingの画像検索に突っ込んだところ機械的に作られたロゴらしいと判明するが、それでもやっぱり存在が謎すぎる…
スクリーンショット 2020-05-27 14.00.49.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GradleのArtifactとはなんぞや

毎回忘れるのでメモ。

Artifactとはなんぞや

該当プロジェクトが、一意に参照できるようにするためのもの。
プロジェクトの名前やライブラリの名前になることが多いと思う。

javaのライブラリ管理はドメイン名と Artifact で行われており、それぞれをつなげたのものファイル名にする。
そのため、example.com というドメインを所持している会社の foo-library というライブラリを配布する場合、

com/
└── example
    └── foo-library

といった形になる。
また、Gradleの設定ファイルであるbuild.gradleには、ドメイン部分の

group = 'com.example'

が記載される。

じゃあNameってなんなん

Gradleでは、複数のプロジェクトを1つのプロジェクトファイルにまとめることができる。
その際に使用するalias。
なので、単一プロジェクトではArtifactと同じで良いと思う。

参考

Artifactについて

Artifact
A file or directory produced by a build, such as a JAR, a ZIP distribution, or a native executable.

Artifacts are typically designed to be used or consumed by users or other projects, or deployed to hosting systems. In such cases, the artifact is a single file. Directories are common in the case of inter-project dependencies to avoid the cost of producing the publishable artifact.
https://docs.gradle.org/current/userguide/dependency_management_terminology.html#sub:terminology_artifact

複数プロジェクトをまとめる方法について

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カウンターアプリ1号

とりあえず、自分の中でまとまった内容から追記していきます。

Javaファイル

MainActivity.java
package com.example.counterapp1;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
        implements View.OnClickListener{
    int number;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv =findViewById(R.id.textView);

        ((Button)findViewById(R.id.button1)).setOnClickListener(this);
        ((Button)findViewById(R.id.button2)).setOnClickListener(this);
        ((Button)findViewById(R.id.button3)).setOnClickListener(this);
    }

    private  void onClickButton1(){
        number =number+1;
        ((TextView)findViewById(R.id.textView))
                .setText(number+"");
    }

    private  void onClickButton2(){
        number = number-1;
        ((TextView)findViewById(R.id.textView))
                .setText(number +"");
    }

    private  void onClickButton3(){
        number =0;
        ((TextView)findViewById(R.id.textView))
                .setText(number+"");
    }

    @Override
    public void onClick(View v){
        switch (v.getId()){
            case R.id.button1:
                onClickButton1();
                break;

            case R.id.button2:
                onClickButton2();
                break;

            case R.id.button3:
                onClickButton3();
                break;
        }
    }


}

レイアウトのxmlファイル

avtivity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="300dp"
        android:text="@string/defaultNumber"
        android:textSize="100sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.434" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginStart="57dp"
        android:text="@string/btn1_txt"
        android:textSize="40sp"
        app:layout_constraintBaseline_toBaselineOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginEnd="60dp"
        android:layout_marginBottom="312dp"
        android:text="@string/btn2_txt"
        android:textSize="40sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />


    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginTop="83dp"
        android:text="@string/btn3_txt"
        android:textSize="40sp"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/group2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <androidx.constraintlayout.widget.Group
        android:id="@+id/group3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="20dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="20dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

文字のリソースのxml

strings.xml
<resources>
    <string name="app_name">CounterApp1</string>
    <string name="defaultNumber">0</string>
    <string name="btn1_txt">+</string>
    <string name="btn2_txt">-</string>
    <string name="btn3_txt">0</string>
</resources>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む