LoginSignup
133
134

More than 1 year has passed since last update.

Javaのパターンメモ

Last updated at Posted at 2018-12-26

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

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パターン

boolean[]やchar[]をStream処理したいときはIntStreamを使う

たとえばcharsがあるとして。

char[] chars;

Arrays.streamにはchar[]を受け取るものがないのでエラ―です。
Stream.ofを使うとchar配列自体を扱うStreamができます。
なので、IntStreamを使ってインデックスを生成しつつmapToObjectします。

IntStream.range(0, chars.length)->mapToObject(i -> chars[i])

int配列ビルダーが欲しいときはIntStream.builder()を使う

var builder = IntStream.builder();
builder.add(2);
builder.add(5);
int[] result = builder.build().toArray();

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

パラメータをもつときにはlombokの@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 UncheckedIOException(ex);
}

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

Guavaの@VisibleForTestingをつけます。JUnitで持ってほしいですね。

@VisibleForTesting
String createId(String seed) {
}
133
134
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
133
134