Javaのパターンメモ

個人的なメモなので、雑に適当に追加されていくかもしれないし放置されるかもしれない

Arrays.asListよりもList.of

JDK9以降では、Arrays.asListよりもList.ofを使うほうがいいです。
Arrays.asListが返すListは単に配列のラッパで、サイズ固定だけど要素の変更が可能です。一方、List.ofが返すListは要素の変更もできずimmutableになります。

n -> new int[n]はint[]::new

これ、なかなか謎構文に見えるけど、そういうもんです。
new String(data)String::newと書けるのと同じで。

FunctionalInterfaceのフィールドを使わない

final Function<String, Price> CONVERT_STRING_TO_PRICE = 
  str -> str.substring(0, str.length() - 1).transfer(Price::of);

というフィールドを定義して

return inputs.stream()
  .map(CONVERT_STRING_TO_PRICE)
  .collect(toList());

のように使うことがあります。

けどこれは、普通にメソッドを定義して、

Price stringToPrice(String str) {
  return str.substring(0, str.length() - 1).transfer(Price::of);
}

メソッド参照を使うほうがいいです。

return inputs.stream()
  .map(Converters::stringToPrice)
  .collect(toList());

JavaDocでのコメントも適切に書けるし、高階関数よりもメソッドのほうが読みやすいです。
また、結局ラムダはメソッド定義とメソッド参照にコンパイルされるので、ちょっと無駄になります。

Optionalをフィールドに使わない

Serializableではないなどあるので、@Nullableなどをつけて普通の値を使うほうがいいです。

Streamを戻り値に使わない

Stream自体を操作するメソッドじゃない限りはStreamを戻り値にしないほうがいいです。
基準としてはStream<T>は返していいけど、Stream<String>など具体的な型を返すものはあまりよくない
もしくはFiles.linesのように、I/Oが入って「ストリーム処理」をしたい場合など。

Streamパターン

anyMatch

for (var a : list) {
  if (condition(a)) {
    return true;
  }
}
return false

return list.stream().anyMatch(this::condition);

allMatch

for (var a : list) {
  if (!condition(a)) {
    return false;
  }
}
return true

return list.stream().allMatch(this::condition);

noneMatch

for (var a : list) {
  if (condition(a)) {
    return false;
  }
}
return true

return list.stream().noneMatch(this::condition);

OptionalにStreamやListをいれない

Optionalは要素0か1の特殊なコレクションなので、StreamやListをさらに囲む必要はなくStream.of()やemptyList()で対応できるはず

if

正常系と異常系

thenに正常系、elseに異常系を

if (cond) {
  proc
} else {
  error
}

ただし異常系が1行でreturn/throwするときは異常系をifに入れて早期脱出を。

if (!cond) {
  throw error
}
proc

!(aa && bb)

!(aa && bb)のように大きくカッコでくくって反転は避けたほうがよさげ

if (!(hasValue && isValid)) {
  error
}

よりは

if (!hasValue || !isValid) {
  error
}

のほうが、結果を脳にキャッシュしなくていい。
ただし、elseがつくなら

if (!hasValue || !isValid) {
  error
} else {
  proc
}

よりは

if (hasValue && isValid) {
  proc
} else {
  error
}

のほうが反転がなくてよい。
この場合は正常系をthenにという方針にも従ってる。
あと、こういった論理の反転はIDEがやってくれるはずなので手でやらないほうが吉。

enum

パラメータをもつときには@AllArgsConstructor@Getterをつける。
@Valueenumに使えない。

@AllArgsConstructor
@Getter
enum Hoge {
  A("a-desu"),
  B("b-dayo");

  private String message;
}

Integer.valueOfはIntegerを返す

IntegerLongvalueOfはラッパーオブジェクトを返す。
なのでこのようなコードは無駄がある

int n = Integer.valueOf(str);

プリミティブとして使いたい場合はparseIntを使う

int n = Integer.parseInt(str);

IOExceptionを非検査例外にするにはUncheckedIOExceptionを使う

catch (IOException ex) {
  throw new UncehckedIOException(ex);
}

テストのためにpackage privateを使うときはVisibleForTestingをつける

@VisibleForTesting
String createId(String seed) {
}
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away