LoginSignup
3
4

More than 5 years have passed since last update.

流れるようなインターフェースで例外処理

Last updated at Posted at 2017-05-05

例外処理を書くのがいつも面倒なので少しアレンジしてみました。

チェック例外を発生させるメソッド
void raiseIOEx1(String s) throws IOException {
    if (s.equals("nagare")) {
        System.out.println("Excellent!");
        return;
    }
    throw new IOException("invalid input :".concat(s));
}

雑ですが上記のようなメソッドがあるとき(なんでIOExceptionなん?とかは置いておいて)

普通の書き方
void usually_try_style() {
    try {
        raiseIOEx1("nagare");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
アレンジした書き方
void nagare_try_style() {
    Try.throwable(this::raiseIOEx1)
            .ifCatch(IOException::printStackTrace)
            .accept("nagare");
}

こんな感じで書けます。

また、値を返すメソッドの場合も以下のように書けます。

チェック例外を発生させるメソッド2
String raiseIOEx2(String s) throws IOException {
    if (s.equals("nagare")) {
        return "Excellent!";
    }
    throw new IOException("invalid input :".concat(s));
}
普通の書き方
void usually_returnable_try_style() {
    try {
        String s = raiseIOEx2("nagare");
        System.out.println(s);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
アレンジした書き方
void nagare_returnable_try_style() {
    Optional<String> s = Try.throwable(this::raiseIOEx2)
            .ifCatch(IOException::printStackTrace)
            .apply("nagare");
    s.ifPresent(System.out::println);

    // or
    Try.throwable(this::raiseIOEx2)
            .ifCatch(IOException::printStackTrace)
            .apply("nagare");
            .ifPresent(System.out::println);
}

業務レベルで使用するのはおすすめできませんが、以下の4クラスを追加することで上記のような記述が可能になります。

public class Try {
    public static <X, A, E extends Exception> ThrowableFunc<X, A, E> throwable(
            ThrowableFunc<X, A, E> f) {
        return f;
    }

    public static <X, E extends Exception> ThrowableSpender<X, E> throwable(
            ThrowableSpender<X, E> s) {
        return s;
    }
}

@FunctionalInterface
public interface ThrowableSpender<X, E extends Exception> {
    void accept(X x) throws E;

    default Consumer<X> ifCatch(ExHandler<E> handler) {
        return (X x) -> {
            try {
                accept(x);
            } catch (Exception e) {
                @SuppressWarnings("unchecked")
                E typedE = (E) e; // is type safe
                handler.handle(typedE);
            }
        };
    }
}

@FunctionalInterface
public interface ThrowableFunc<X, A, E extends Exception> {
    A apply(X x) throws E;

    default Function<X, Optional<A>> ifCatch(ExHandler<E> handler) {
        return x -> {
            try {
                return Optional.of(apply(x));
            } catch (Exception e) {
                @SuppressWarnings("unchecked")
                E typedE = (E) e; // is type safe
                handler.handle(typedE);
            }
            return Optional.empty();
        };
    }
}

@FunctionalInterface
public interface ExHandler<E extends Exception> {
    void handle(E e);
}

コード読んでいただけると分かると思いますがcatchのところで少しズルをしています。

try {
    accept(x);
} catch (E e) {
    handler.handle(e);
}

みたいな感じで書けるようになれば複数例外を捕まえるのもインターフェースだけで記述できるようになり色々捗りそうなんですが、残念です。java9では書けるようになるといいですね。

参考

3
4
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
3
4