##例外catchしてくださいって怒られるやつ
ぐぬぬ一行で書けない...
っていうのをどうにか綺麗に書くためのやつです
##準備
/** --------------------準備-------------------- */
/** 例外を投げるインターフェース */
private static interface Throwable<T, S> {
S apply(T t) throws NullPointerException, NumberFormatException, Exception;
}
/** 例外に応じて実行する関数を切り替えるメソッド */
private static <T, S> Function<T, S> switchFunction(Throwable<T, S> tf, BiFunction<Exception, T, S> npe,
BiFunction<Exception, T, S> nfe, Function<Exception, S> other) {
return v -> {
try {
return tf.apply(v);
} catch (NullPointerException e) {
return npe.apply(e, v);
} catch (NumberFormatException e) {
return nfe.apply(e, v);
} catch (Exception e) {
return other.apply(e);
}
};
}
例外を投げられるFunctionを作りまして
とあるFunctionを実行しようとしたときに例外がでたらこっちのFunctionにするーっていうメソッドを作ります
- やりたい処理
- ぬるぽならこの処理
- NumberFormatExceptionならこの処理
- その他ならこの処理
の4つを実装していきます
##内部の処理の実装
/** --------------------具体的な処理の実装-------------------- */
/** メイン処理 */
private static final Throwable<String, Integer> tf = v -> {
if (v.equals("5")) {
return Integer.parseInt(v);
} else if (v.equals("999")) {
throw new NullPointerException();
} else if (v.equals("ddd")){
throw new NumberFormatException();
} else {
throw new IOException();
}
};
/** ぬるぽの時の処理 */
private static final BiFunction<Exception, String, Integer> npe = (e, v) -> {
e.printStackTrace();
return 0;
};
/** 数値変換だめなときの処理 */
private static final BiFunction<Exception, String, Integer> nfe = (e, v) -> {
e.printStackTrace();
return v.length();
};
/** その他の例外時の処理 */
private static final Function<Exception, Integer> other = e -> {
e.printStackTrace();
return 1;
};
今回は全パターンみたいので強制的にException投げるようにしました
それじゃ実行していきましょう
##実行
/** --------------------実行-------------------- */
public static void main(String[] args) {
Arrays.asList("5", "ddd", "999", "0").stream().map(switchFunction(tf, npe, nfe, other))
.forEach(System.out::println);
}
5
java.lang.NumberFormatException
at test1.Test1.lambda$0(Test1.java:35)
at test1.Test1.lambda$4(Test1.java:18)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.forEach(Unknown Source)
at test1.Test1.main(Test1.java:55)
3
java.lang.NullPointerException
at test1.Test1.lambda$0(Test1.java:33)
at test1.Test1.lambda$4(Test1.java:18)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.forEach(Unknown Source)
at test1.Test1.main(Test1.java:55)
0
java.io.IOException
at test1.Test1.lambda$0(Test1.java:37)
at test1.Test1.lambda$4(Test1.java:18)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.forEach(Unknown Source)
at test1.Test1.main(Test1.java:55)
1
想定通りですね
##弱点
まぁ見てわかる通り、実装できるFunctionの引数、戻り値の型が
せっかくジェネリクスでとってるのに、全部一致してないとダメってことですね
現実的な実装だと困るケースも出てきそうです
っていうかこんなにFunction重ねるとなんか重くなりそうです...いいのかこれ
実行部分、内部の処理が綺麗に分かれているので
可読性はめっちゃ高いんじゃないでしょうか
けどね、うん 準備長すぎな
一連のstreamに対する中間操作でどうしてもExceptionを吐くケースが複数あるなら
こういった実装をした方がきれいにまとまるとかありそうです
##これをメソッドでやってみる
public class Test7 {
private static <T>void switchMethod(T t) {
try {
s1(t);
} catch (NumberFormatException e) {
s2(t);
}
}
private static <T>void s1(T t) throws NumberFormatException{
System.out.println(Integer.parseInt((String) t));
}
private static <T>void s2(T t) {
System.out.println(t + "すうちむり");
}
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("a", null, "2"));
list.stream().forEachOrdered(Test7::switchMethod);
}
}
aすうちむり
nullすうちむり
2
やっぱ準備段階でメソッドは増えまくるんですよねぇ
例外吐いた場合の挙動が同じなら使った方が綺麗ですけども...
うーむ、難しい...