概要
Javaの罠ともいうべきAPI群をメモ。随時追記・指摘歓迎。
全般に言えるのはJavaDocを読もうということ。(読めばたいていの場合書いてある、ただし分かり易いとは限らない)
API群
String#legnth()
文字列の長さを返す。だが、ここでの長さはUnicodeコード単位の数を指している点に注意。
サロゲートペア文字(下記に例)
𠀋 𡈽 𡌛 𡑮 𡢽 𠮟 𡚴 𡸴 𣇄 𣗄 𣜿 𣝣 𣳾 𤟱 𥒎 𥔎 𥝱 𥧄 𥶡 𦫿 𦹀 𧃴 𧚄 𨉷 𨏍 𪆐 𠂉 𠂢 𠂤 𠆢 𠈓 𠌫 𠎁 𠍱 𠏹 𠑊 𠔉 𠗖 𠘨 𠝏 𠠇 𠠺 𠢹 𠥼 𠦝 𠫓 𠬝 𠵅 𠷡 𠺕 𠹭 𠹤 𠽟 𡈁 𡉕 𡉻 𡉴 𡋤 𡋗 𡋽 𡌶 𡍄 𡏄 𡑭 𡗗 𦰩 𡙇 𡜆 𡝂 𡧃 𡱖 𡴭 𡵅 𡵸 𡵢 𡶡 𡶜 𡶒 𡶷 𡷠 𡸳 𡼞 𡽶 𡿺 𢅻 𢌞 𢎭 𢛳 𢡛 𢢫 𢦏 𢪸 𢭏 𢭐 𢭆 𢰝 𢮦 𢰤 𢷡 𣇃 𣇵 𣆶 𣍲 𣏓 𣏒 𣏐 𣏤 𣏕 𣏚 𣏟 𣑊 𣑑 𣑋 𣑥 𣓤 𣕚 𣖔 𣘹 𣙇 𣘸 𣘺 𣜜 𣜌 𣝤 𣟿 𣟧 𣠤 𣠽 𣪘 𣱿 𣴀 𣵀 𣷺 𣷹 𣷓 𣽾 𤂖 𤄃 𤇆 𤇾 𤎼 𤘩 𤚥 𤢖 𤩍 𤭖 𤭯 𤰖 𤴔 𤸎 𤸷 𤹪 𤺋 𥁊 𥁕 𥄢 𥆩 𥇥 𥇍 𥈞 𥉌 𥐮 𥓙 𥖧 𥞩 𥞴 𥧔 𥫤 𥫣 𥫱 𥮲 𥱋 𥱤 𥸮 𥹖 𥹥 𥹢 𥻘 𥻂 𥻨 𥼣 𥽜 𥿠 𥿔 𦀌 𥿻 𦀗 𦁠 𦃭 𦉰 𦊆 𦍌 𣴎 𦐂 𦙾 𦚰 𦜝 𦣝 𦣪 𦥑 𦥯 𦧝 𦨞 𦩘 𦪌 𦪷 𦱳 𦳝 𦹥 𦾔 𦿸 𦿶 𦿷 𧄍 𧄹 𧏛 𧏚 𧏾 𧐐 𧑉 𧘕 𧘔 𧘱 𧚓 𧜎 𧜣 𧝒 𧦅 𧪄 𧮳 𧮾 𧯇 𧲸 𧶠 𧸐 𧾷 𨂊 𨂻 𨊂 𨋳 𨐌 𨑕 𨕫 𨗈 𨗉 𨛗 𨛺 𨥉 𨥆 𨥫 𨦇 𨦈 𨦺 𨦻 𨨞 𨨩 𨩱 𨩃 𨪙 𨫍 𨫤 𨫝 𨯁 𨯯 𨴐 𨵱 𨷻 𨸟 𨸶 𨺉 𨻫 𨼲 𨿸 𩊠 𩊱 𩒐 𩗏 𩙿 𩛰 𩜙 𩝐 𩣆 𩩲 𩷛 𩸽 𩸕 𩺊 𩹉 𩻄 𩻩 𩻛 𩿎 𪀯 𪀚 𪃹 𪂂 𢈘 𪎌 𪐷 𪗱 𪘂 𪘚 𪚲
を含む場合に期待通りの結果を得られない。
代替コードによる解決
Unicode コードポイントの数を取得するメソッドを使う。
String str = "なんだコレ→𠆢";
int length = str.codePointCount(0, str.length());
文字内にNFD表記の濁点(Macなどで用いられる)が含まれる可能性がある場合は、NFC表記への正規化を行っておかないと、濁点が1文字としてカウントされてしまう可能性がある。
String str = "なんた\u3099コレ→𠆢";
str = java.text.Normalizer.normalize(str, java.text.Normalizer.Form.NFC);
int length = str.codePointCount(0, str.length());
Arrays#asList(T... a)
配列をListにできる便利なヤツ。だが、可変長引数として受け取る(※備考)ので意図した結果(=配列の各要素が入っているリスト)が得られるのはオブジェクト型の配列(Integer[]等)の場合のみ。
プリミティブ型の配列(int[]等)を渡すと、このプリミティブ型の配列オブジェクトが1つ入ったListを返す(=これは普通は意図しない結果ですよね?)
※備考: 可変長引数で受けるということは、そもそも「配列から」というよりは「決まった個数の値から」Listを作る
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
というのが想定された呼び方っぽい(上記はJavaDocのサンプルコードより抜粋)ので、呼べるからといって配列を渡す方が筋違いなのか?
代替コードによる解決
初期化タイミングであれば
Integer[] array = {100, 200, 300};
のようにしてオブジェクト型の配列が作れるのでこれでArrays#asListが使える。
既にプリミティブ型の配列(int[])の変数がある場合にはループを回して変換する。
外部ライブラリによる解決
- Guava: プリミティブ型配列用の変換メソッド(Ints#asList 等)を使う
Arrays#binarySearch
メソッド名(バイナリサーチ(二分探索))が仕様を表しているような気もするが、使うにあたって
- 配列がソート済みでないと結果は保証されない
- 検索対処の値が複数存在する場合どのインデックスが返されるかも保証されない
という点に注意しないと意図しない結果となる。
代替コードによる解決
注意事項が問題になる場合、ループを回して検索するかListであればList#indexOfを使う(効率は良くない)。
外部ライブラリによる解決
- Guava: プリミティブ型配列用の探索メソッド(Ints#indexOf 等)
File#getAbsolutePath(), File#getCanonicalPath()
File#getAbsolutePath()
絶対パスを返す。パスにカレントディレクトリ(./)や親ディレクトリ(../)が含まれている場合、これらはそのまま残るので注意。File#getCanonicalPath()
正規化パスを返す。パスにカレントディレクトリ(./)や親ディレクトリ(../)が含まれている場合、これらを辿って消去してくれるがシンボリックリンクも解決してしまう(Linuxの場合のみ。Windowsでは解決しない)ので注意。あとIOExceptionを投げる可能性があるので面倒
代替コードによる解決
- パスからカレントディレクトリ(./)や親ディレクトリ(../)を消して絶対パスにしたい
- (Linuxでも)シンボリックリンクを解決したくない
という場合、java.nio.file.Pathsを使う。Path#toAbsolutePath()で絶対パスに変換した後、Path#normalize()で冗長な名前要素(カレントディレクトリや親ディレクトリの指定)を削除。
String path = "../sample.txt";
String newPath = Paths.get(path).toAbsolutePath().normalize().toString();
おまけ:Windowsでもシンボリックリンクを解決したい(Windowsではシンボリックを作成する機会自体が少ないと思うケド)
String solvedPath = Paths.get(path).toRealPath();
ただし、ファイルが存在しない場合や入出力エラーが発生した場合はPath#toRealPathがIOExceptionをスローするので注意。
Calendar#get(Calendar.MONTH)
戻り値の範囲は0~11。Calendar.DAY や Calendar.YEARの時と異なり1ずれている。
代替コードによる解決
Java7以前: 戻り値に1加算する。
Java8以降: 新しい日付時刻APIを使うなら LocalDateTime#getMonthValue() で取得できる。
外部ライブラリによる解決
JodaTime: DateTime#getMonthOfYear()