LoginSignup
0
0

More than 3 years have passed since last update.

stream中にエラーハンドリングできなくてこまるやつ

Posted at

例外catchしてくださいって怒られるやつ

ぐぬぬ一行で書けない...

っていうのをどうにか綺麗に書くためのやつです

準備

準備.java
    /** --------------------準備-------------------- */
    /** 例外を投げるインターフェース */
    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つを実装していきます

内部の処理の実装

内部.java
    /** --------------------具体的な処理の実装-------------------- */
    /** メイン処理 */
    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投げるようにしました
それじゃ実行していきましょう

実行

実行.java
    /** --------------------実行-------------------- */
    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を吐くケースが複数あるなら
こういった実装をした方がきれいにまとまるとかありそうです

これをメソッドでやってみる

これでしょ.java
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

やっぱ準備段階でメソッドは増えまくるんですよねぇ

例外吐いた場合の挙動が同じなら使った方が綺麗ですけども...

うーむ、難しい...

0
0
0

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
0
0