|
その他のJavaメモ
文法・API関連
環境関連
文法・API関連
配列をリストに変換する
配列をリストに変換するには、java.utils.Arrays#asList()を使います。
String[] files = {"a.txt", "b.txt", "c.txt"};
List fileList = Arrays.asList(files);
|
また、ArrayListを次のように一行で初期化する書き方もあります。
List<String> params = Arrays.asList("1", "2", "3");
|
リストを配列に変換する
その逆は java.util.collections#toArray()を使います。
String[] files = fileList.toArray(new String[fileList.size()]);
|
配列やリストをログ出力のために簡易に文字列に整形する
最も簡単な方法を集めてみました。
String[] arr = //...
System.out.println(Arrays.toString(arr));
String[][] d2arr = //...
System.out.println(Arrays.deepToString(d2arr));
List alist = //...
// リストは単純にtoString()で行ける
System.out.println(alist.toString());
// 配列のリスト
List blist = //...
System.out.println(Arrays.deepToString(blist.toArray()));
|
ただしこれらは改行などの整形は行わず、1行に表示するだけなので、
見やすく凝った整形にしたい場合は外部ライブラリを使うか、自分でループして記述する必要があります。
リストの要素を削除しながらループする
一例として、次のように作ったListから、空欄の要素を全て削除したいです。
List<String> a = new ArrayList<String>();
a.add("Taro");
a.add("");
a.add("Jiro");
a.add("");
a.add("");
a.add("Saburo");
a.add("Shiro");
a.add("");
a.add("Goro");
|
まず駄目な例から。これだと、連続する""の内、後ろの方が残ってしまいます。
つまり要素の削除によって後ろの要素が前に詰まるため、ループを飛ばされる要素が出てしまいます。
for (int i = 0; i < a.size(); i++) {
if(a.get(i).equals("")) {
a.remove(i);
}
}
|
これに対して主な方法は3つあります。まず最初の例は、当然ながら末尾の要素から逆向きにループする方法。
これなら飛ばされる要素が出る問題は起きません。
for (int i = a.size()-1; i > 0; i--) {
if(a.get(i).equals("")) {
a.remove(i);
}
}
|
2つ目の方法。これも当然ながら、削除するたびループカウンタも--する方法。
ただしループ内にループカウンタを操作するのはトリッキーなので、バグの混入に注意がいりそうです。
for (int i = 0; i < a.size(); i++) {
if(a.get(i).equals("")) {
a.remove(i--);
}
}
|
最後がIterator経由で削除する方法。可読性が良く堅牢な方法と言えます。
これだと前方方向にループしながら、要素が飛ぶことも回避できます。
Iterator<String> iter = a.iterator();
while(iter.hasNext()) {
String s = iter.next();
if(s.equals("")) {
iter.remove();
}
}
|
ファイルのパス区切りを正規化する
ファイルのパスを文字列処理していて、UNIXのパス区切り("/")
と Windowsのパス区切り("\")が混ざってしまった場合、
これをプラットフォームのパス区切り文字に統一する簡単な方法です。
String s = "\usr\home/data/temp";
System.out.println(new File(s).getCanonicalPath());
|
ディレクトリとファイル名を連結してパスを作る
これでok
String filePath = new File(dirPath, fileName).getPath();
|
doubleを小数点以下指定桁で四捨五入するには?
"DecimalFormatで文字列にする"というのは無しで、本当にdoubleを四捨五入する方法です。
ちなみに、Math.round()は常に整数に丸めようとするので、今回の目的には使えません。
// vを小数点3桁で四捨五入し、小数点以下2桁のdoubleにする。
double v2 = new BigDecimal(v).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
|
文字列をbooleanに変換するには?
Java APIを読んで慌てて使うと間違えやすいのですが、
「Boolean.getBoolean(String)」メソッドでは、文字列をbooleanには変換できません。
これは引数のシステムプロパティの値がtrueどうかを返すメソッドです。
上記目的のためには、「Boolean.valueOf(String).booleanValue()」とするのが正解です。
String.compareTo()の返す値はどっちがどっちだっけ?
int result = str1.compareTo(str2);
|
は、「str1の方が大きければ正の値」=「str2の方が小さければ正の値」です。
同じ文字列なら0です。
staticメソッドはオーバーライドできないの?
できません。
基底クラスと派生クラスの両方で同じ名前のstaticメソッドを定義できますが、
それはオーバーライドではありません。Overrideアノテーションをつけるとエラーになります。
環境関連
システムプロパティをコマンドライン以外の場所で共通設定する
システムプロパティは一例で「java -Duser.language=ja」のようにjavaのコマンドラインに-Dオプションで付与できますが、
毎回指定しなくても共通の場所で定義すれば効くようにしたい。
というときは、
export JAVA_TOOL_OPTIONS="-Duser.language=ja -Duser.country=JP"
|
のような行を個人単位なら~/.bashrcか~/.bash_profile、
全ユーザー共通なら/etc/profile.d/java-cmdline.sh (名前は任意です)というファイルに記入すればOKです。
設定されたかを確認するには次のような簡単なJavaプログラムを作り、
public class ListSystemProperties {
public static void main(String[] args) {
System.getProperties().forEach((key, value) -> {
System.out.println(key + ": " + value);
});
}
}
|
コンパイルして実行すればOKです。
または最近のjavaはコンパイルしなくても.javaソースのまま実行できますよ。
ちなみに、標準出力に設定の一覧を出力するだけでいいなら、以下の1行でokです。
System.getProperties().list(System.out);
|
実行しているJavaVMのデフォルトエンコーディングを得る
String encoding = System.getProperty("file.encoding");
|
この値は"windows-31j"だったり"UTF-8"だったり、UNIXのSJISだと"PCK"だったりします。
ものすごくニッチな用途としては、「全角ハイフン」の文字化け問題を解決するために、
エンコーディングがSJISの環境に限り\uFF0Dを\u2212に変換するとかの判定に使えます。
ロード済のあるクラスが、どこに置かれたJarファイルからロードされたのかを知るには?
MyCustomPredicate o = new MyCustomPredicate();
ClassLoader classLoader = o.getClass().getClassLoader();
URL classURL = classLoader.getResource("jp/co/my/custom/MyCustomPredicate.class");
System.out.println(classURL.toString());
classURL = classLoader.getResource("org/apache/commons/collections/Predicate.class");
System.out.println(classURL.toString());
|
ClassLoader#getResource()を使えば可能です。
このときクラスのパッケージ階層は、リソースとして指定するので、
.ではなくスラッシュ/で区切ることと、".class"もつける必要があることに要注意。
なお上のPredicateのように、インターフェースの.classファイルも調べることができます。
上記の結果は、
「jar:file:/C:/usr/java/lib/commons-collections-3.2.jar!/org/apache/commons/collections/Predicate.class」
のような形式で得られます。
WindowsでのCLASSPATHのうっかり1
set CLASSPATH=".\classes;C:\the\path\of\aaa.jar;C:\the\path\of\bbb.jar"
java sample.SampleMain
|
を実行するとNoClassDefFoundErrorが出て延々悩みました。
CLASSPATHは引用符で全体を囲んだら駄目です。つけないのが正解。
set CLASSPATH=.\classes;C:\the\path\of\aaa.jar;C:\the\path\of\bbb.jar
java sample.SampleMain
|
WindowsでのCLASSPATHのうっかり2
set CLASSPATH=C:\Wintools\groovy-3.0.5\lib\groovy-3.0.5.jar
set CLASSPATH=%CLASSPATH%;D:\usr\java\lib\poi4\*.jar
|
を実行するとNoClassDefFoundErrorが出て延々悩みました。(2回目)
ワイルドカードは「*.jar」や「*.JAR」と書いては駄目です。必ず「*」と書かないと効きません。
set CLASSPATH=C:\Wintools\groovy-3.0.5\lib\groovy-3.0.5.jar
set CLASSPATH=%CLASSPATH%;D:\usr\java\lib\poi4\*
|
jarコマンドでwarファイルを作る
コマンドラインの例です。
cd \temp
jar cvf webapp01.war -C C:/usr/java/projects/webapp01 .
|
java.lang.IncompatibleClassChangeError?
この珍しいエラーには、2回別々の原因で出会ったことがあります。
- あるインターフェースAと、それを参照するクラスBを作り、それぞれコンパイルしました。
- Aをインターフェースから抽象クラスに変更し、Aだけをコンパイルしました。
-
Bをインスタンス化するか、またはObjectからキャストして初めてそのどれかのメソッドをコールしようとすると、
このエラーが出ました。
もう1つは、クラスローダが何種類かあるTomcatで、
クラスAがクラスBに、クラスBがインターフェースCに依存している状態で、
クラスローダ1がAとCをロードし、クラスローダ2がBをロードしてしまったような場合です。
The hierarchy of the type *** is inconsistent
このエラーは、クラスAを作ってaaa.jarに含めていて、
Aを継承して作ったクラスBをbbb.karに含めていて、
Bを継承してクラスCを作ろうとしているとき、
aaa.jarがclasspathに含まれていないと発生します。
VMのメモリ使用状況を確認するには
次のようにして、JavaVMの空きメモリ容量、総メモリ容量、使用可能な最大容量を取得できます。
(maxMemoryは定義されていない場合は取得できないこともあるらしい)
long free = Runtime.getRuntime().freeMemory();
long total = Runtime.getRuntime().totalMemory();
long max = Runtime.getRuntime().maxMemory();
|
JUnitで、例外が想定通りに発生したかどうかを検証するには
JUnitについてはメモページがまだないのでここでtipsを。
これは逆に、fail()メソッドを使って、例外が発生「しなかったら」
テストが失敗するように書けばOKです。
try {
int result = targetObj.targetMethod("argumenttt");
fail();
} catch(IllegalFormatException ex){
// 例外が予想通りに発生した。
}
|

(first uploaded 2004/05/03 last updated 2025/09/23, URANO398)
|