個人的なメモなので、雑に適当に追加されていくかもしれないし放置されるかもしれない
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
をつける。
@Value
はenum
に使えない。
@AllArgsConstructor
@Getter
enum Hoge {
A("a-desu"),
B("b-dayo");
private String message;
}
Integer.valueOfはIntegerを返す
Integer
やLong
のvalueOf
はラッパーオブジェクトを返す。
なのでこのようなコードは無駄がある
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) {
}