例外をスローするJava 8 Lambda関数?


469

Stringパラメータを持ち、を返すメソッドへの参照を作成する方法を知っていますint

Function<String, Integer>

ただし、関数が例外をスローする場合、これは機能しません。たとえば、次のように定義されているとします。

Integer myMethod(String s) throws IOException

この参照をどのように定義しますか?





4
すべてのソリューションは、ランタイム例外をスローするなんらかの方法のように見えますが、それは良いソリューションではないと思います。古いJava forループを使用する方がいい
Nazeel

5
何についてjoolのライブラリ?cf org.jooq.lambda.Uncheckedパッケージ
chaiyachaiya

回答:


402

次のいずれかを行う必要があります。

  • コードの場合は、チェックされた例外を宣言する独自の機能インターフェイスを定義します。

    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    そしてそれを使う:

    void foo (CheckedFunction f) { ... }
  • それ以外の場合はInteger myMethod(String s)、チェック済み例外を宣言しないメソッドでラップします。

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    その後:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    または:

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };

7
実際に拡張することConsumerFunction、デフォルトの方法を使用することもできます-以下の私の答えを参照してください。
jlb

2
これはワンライナーとして実現できると思います。
Ned Twigg、2015年

6
マイナーな最適化:の代わりに(String t) -> myWrappedMethod(t)、メソッドリファレンスthis::myWrappedMethodを使用することもできます。
Clashsoft 2016年

8
それを行うさらに一般的な方法は、この@FunctionalInterfaceパブリックインターフェイスのようなチェックされた関数を定義することですCheckedFunction <T、R、E extends Exception> {R apply(T t)throws E; このようにして、関数がスローする例外を定義し、任意のコードのインターフェイスを再利用することもできます。
Martin Odhelius 16

3
ワオ。Javaは、私が思ったよりも悪いです
user275801

194

Java 8のデフォルトメソッドを使用して、例外を処理する新しいインターフェースで実際に拡張ConsumerFunctionなど)できます

このインターフェースを検討してください(拡張Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

次に、たとえば、リストがある場合:

final List<String> list = Arrays.asList("A", "B", "C");

forEach例外をスローするいくつかのコードでそれを(例えばで)消費したい場合、伝統的にtry / catchブロックを設定します:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

しかし、この新しいインターフェースを使用すると、ラムダ式でインスタンス化でき、コンパイラーは文句を言いません:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

または、キャストしてさらに簡潔にすることもできます!:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

更新エラーと呼ばれるDurianの非常に優れたユーティリティライブラリの一部があるようです。このライブラリを使用すると、この問題をより柔軟に解決できます。たとえば、上記の実装では、エラー処理ポリシー(または)を明示的に定義しましたが、Durianのエラーを使用すると、ユーティリティメソッドの大規模なスイートを介してオンザフライでポリシーを適用できます。それ共有してくれてありがとう、@ NedTwigg!。System.out...throw RuntimeException

使用例:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));

14
つまり、一連のインターフェース(Function、Consumer、Supplierなど)と、エラーを処理するための一連のポリシー(Throwing、System.out.println、...)があります。「ThrowingConsumer、ThrowingFunctionなど」をコピーして貼り付ける必要がなく、あらゆる種類の関数であらゆるポリシーを簡単に使用できる方法があると思います。
Ned Twigg、2015年

1
しばらくしてから...未チェックの例外を使用し、追加の機能インターフェースや新しいライブラリを使用しないことにしました->簡単な道、タイピングが少なくて、配信が速くなりますね。
aliopi 2017

1
これは卑劣な投げ慣用句を使用した改良版です。RuntimeExceptionをCheckExceptionにラップ解除する必要はありません。
myui

62

ドリアンのErrorsクラスは、上記のさまざまな提案の多くの長所を組み合わせていると思います。

ドリアンをプロジェクトに含めるには、次のいずれかを行います。

  • それをつかむjcenterまたはMavenの中心com.diffplug.durian:durian:3.3.0
  • またはちょうどあなたのコードの中に2つだけの小さなクラスをコピー&ペースト:Throwing.javaErrors.java

または、RxJavaを使用することもできます。これは、ストリームに固有のエラー処理が必要であり、パイプラインに例外をスローするものがある場合、おそらく監視可能なストリームである可能性が高いためです。これにより、ライブラリのダウンストリームコンシューマにJava 8が強制されることもありません。
Adam Gent

2
2016年6月以降、ドリアンには新しいバージョンがありません。ショーのストッパーではありませんが、覚えておかなければなりません。
Istvan Devai

9
ドリアンのメンテナーはこちら。何が壊れていますか?ユーザーがバグまたは重要な欠けている機能を見つけた場合は、バグ修正を迅速にリリースします。ライブラリはシンプルなので、バグレポートはありません。したがって、バグ修正をリリースする必要はありません。
Ned Twigg

28

これはJava 8に固有のものではありません。以下と同等のものをコンパイルしようとしています。

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}

15
問題は、「この参照をどのように定義するか」です。。これは実際には質問の答えにはなりません。それは問題が何であるかを明らかにするだけです。
Dawood ibnカリーム

13

免責事項:私はまだJava 8を使用していません。読むだけです。

Function<String, Integer>はスローしないIOExceptionので、その中にコードを入れることはできませんthrows IOException。を必要とするメソッドを呼び出してFunction<String, Integer>いる場合、そのメソッドに渡すラムダはIOException、ピリオドをスローできません。次のようなラムダを書くこともできます(これはラムダ構文だと思いますが、わかりません):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

または、ラムダを渡すメソッドが自分で作成したものである場合は、新しい関数インターフェイスを定義して、次の代わりにそれをパラメータータイプとして使用できますFunction<String, Integer>

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}

インターフェースの前に@FunctionalInterfaceアノテーションを追加してください。そうしないと、ラムダで使用できなくなります。
Gangnus 2015年

13
@Gangnus:@FunctionalInterface注釈をラムダで使用できるようにする必要はありません。ただし、健全性チェックにはお勧めです。
Tanmay Patil 2016

9

サードパーティのlib(Vavr)を使用しても構わない場合は、

CheckedFunction1<String, Integer> f = this::myMethod;

エラーを処理する、いわゆるTryモナドもあります。

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

詳しくはこちらをご覧ください。

免責事項:私はVavrの作成者です。



6

ただし、以下のようにスローする独自のFunctionalInterfaceを作成できます。

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

次に、以下に示すように、ラムダまたは参照を使用して実装します。

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}

6

あなたはできる。

@marcgを拡張し、必要に応じUtilExceptionてジェネリック<E extends Exception>を追加します。これにより、コンパイラーは、Java 8のストリームでネイティブにチェック済み例外をスローできるかのように、もう一度スロー句とすべてを強制的に追加します。

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}

5

ラムダ内のClass.forNameとClass.newInstanceでこの問題が発生したため、次のようにしました。

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

ラムダの中で、Class.forName( "myClass")。newInstance()を呼び出す代わりに、uncheckedNewInstanceForName( "myClass")を呼び出しました


4

関数ラッパーを使用する別の解決策は、すべてがうまくいった場合、成功などの結果のラッパーのインスタンスを返すか、失敗などのインスタンスを返すことです。

明確にするためのコード:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

簡単な使用例:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());

4

この問題も私を悩ませてきました。これが私がこのプロジェクトを作成した理由です。

それを使用すると、次のことができます。

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDKで定義されている39のインターフェースの合計には、そのようなThrowing同等のものがあります。これらはすべて@FunctionalInterfaceストリームで使用されるsです(ベースStreamだけでなくIntStreamLongStreamおよびDoubleStream)。

そして、それぞれが非スロー対応を拡張するので、ラムダで直接使用することもできます。

myStringStream.map(f) // <-- works

デフォルトの動作では、スローするラムダがチェック例外をThrownByLambdaExceptionスローすると、チェック例外を原因としてがスローされます。したがって、それをキャプチャして原因を取得できます。

他の機能も利用できます。


ここで示唆したように、私は本当にアイデアのように、私はあなたがスロー可能オブジェクトは、ジェネリック作らたい:javaspecialists.eu/archive/Issue221.html、例えば:@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }-この方法は、ユーザーがキャッチする必要はありませんThrowableが、特定のではなく、例外をチェックします。
ゾルタン2015

@Zoltánでも、毎回例外を宣言するのは面倒です。また、いつでも、たとえば.doApply()の代わりに.apply()を使用してcatch ThrownByLambdaExceptionするだけで、元の例外が原因になります(またはを使用できますrethrow(...).as(MyRuntimeException.class)
fge

これを回避する方法はあると思います。
Ned Twigg、2015年

@NedTwigg私もずっと前にこれを解決しました。私はThrowing.runnable()、他の人も使用できるようになりました。常に連鎖機能があります
2015

連鎖機能はとてもクールです!私のコメントは、ThrowingRunnableに一般的な例外があるべきかどうかについてでした。Zoltanは、あなたのライブラリがジェネリックパラメーターとして引数を持つことができるかどうか尋ねました、そしてあなたはそれを使うのは面倒だと言いました。私のリンクはいくつかのコード行へのリンクであり、例外を一般的なものにする方法の1つを示しています。私がそれを誤解しない限り、ライブラリの例外は一般的ではありません(これを一般的にしてもあまり実用性がないため、これは合理的な設計上の選択です)。
Ned Twigg、2015年

4

すでに多くの素晴らしい回答がここに投稿されています。別の視点で問題を解決しようとするだけです。その2セントだけです。どこか間違っている場合は訂正してください。

FunctionalInterfaceのスロー句はお勧めできません

次の理由により、これはスローIOExceptionを強制するのにはおそらく良い考えではないと思います

  • これは、Stream / Lambdaのアンチパターンのように見えます。全体のアイデアは、提供するコードと例外の処理方法を呼び出し元が決定することです。多くのシナリオでは、IOExceptionはクライアントに適用できない場合があります。たとえば、クライアントが実際のI / Oを実行する代わりにキャッシュ/メモリから値を取得している場合。

  • また、ストリームでの例外処理は本当に恐ろしいものになります。たとえば、APIを使用すると、コードは次のようになります

               acceptMyMethod(s -> {
                    try {
                        Integer i = doSomeOperation(s);
                        return i;
                    } catch (IOException e) {
                        // try catch block because of throws clause
                        // in functional method, even though doSomeOperation
                        // might not be throwing any exception at all.
                        e.printStackTrace();
                    }
                    return null;
                });

    醜いですね。さらに、最初のポイントで述べたように、doSomeOperationメソッドは(クライアント/呼び出し元の実装に応じて)IOExceptionをスローする場合とスローしない場合がありますが、FunctionalInterfaceメソッドのthrows句のため、常にトライキャッチ。

このAPIがIOExceptionをスローすることが本当にわかっている場合はどうすればよいですか

  • 次に、おそらく、FunctionalInterfaceを一般的なインターフェイスと混同しています。このAPIがIOExceptionをスローすることがわかっている場合は、おそらくデフォルト/抽象動作も知っています。次のようにインターフェイスを定義し、ライブラリを(デフォルト/抽象実装で)デプロイする必要があると思います

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    }

    しかし、クライアントにはtry-catchの問題がまだ残っています。ストリームでAPIを使用する場合でも、恐ろしいtry-catchブロックでIOExceptionを処理する必要があります。

  • 次のように、デフォルトのストリームフレンドリーAPIを提供します。

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    
        default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
            try {
                return Optional.ofNullable(this.myMethod(s));
            } catch (Exception e) {
                if (exceptionConsumer != null) {
                    exceptionConsumer.accept(e);
                } else {
                    e.printStackTrace();
                }
            }
    
            return Optional.empty();
        }
    }

    デフォルトのメソッドは、コンシューマオブジェクトを引数として取り、例外を処理します。クライアントの観点から見ると、コードは次のようになります

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());

    いいですね もちろん、Exception :: printStackTraceの代わりにロガーやその他の処理ロジックを使用することもできます。

  • https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function-と同様のメソッドを公開することもでき ます。以前のメソッド呼び出しからの例外を含む別のメソッドを公開できることを意味します。欠点は、APIをステートフルにすることです。つまり、スレッドセーフを処理する必要があり、最終的にはパフォーマンスヒットになります。ただし、考慮すべきオプションです。


チェックされた例外をチェックされていない例外に変換したり、例外を飲み込んだりすることは、Stream発生した例外のどの要素を認識するのかわからないので、同意しない。したがって、私は例外ハンドラーを持ち、無効な結果をフィルターに掛けるという考えが気に入っています。MyAmazingAPIは実質的にaであることに注意してくださいFunctionalInterface(したがって、@ FunctionalInterface アノテーションを追加できます)。また、を使用する代わりに、デフォルト値を使用することもできますOptional.empty()
ジュリアンクロネッグ

4

卑劣なスローイディオムCheckedException、ラムダ式のバイパスを可能にします。CheckedExceptionでのaのラップは、RuntimeException厳密なエラー処理には適していません。

これはConsumer、Javaコレクションで使用される関数として使用できます。

ここにジブの答えのシンプルで改良されたバージョンがあります

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}

これは、ラムダを再スローでラップするだけです。それはあなたのラムダに投げられたものをCheckedExceptionException投げます。

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}

ここで完全なコードと単体テストを見つけてください


3

これにはETを使用できます。ETは、例外の変換/変換用の小さなJava 8ライブラリです。

ETでは次のようになります。

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslatorインスタンスはスレッドセーフであり、複数のコンポーネントで共有できます。FooCheckedException -> BarRuntimeException必要に応じて、より具体的な例外変換ルール(など)を構成できます。他に使用可能なルールがない場合、チェックされた例外は自動的にに変換されRuntimeExceptionます。

(免責事項:私はETの作成者です)


2
あなたはこのライブラリの作成者のようです。よると、SOルール、あなたがしなければならないあなたの答えであなたの所属を開示しています。このライブラリを書いたことを明示的に回答に追加してください(他のET関連の回答についても同じです)。
Tagir Valeev、2015

2
こんにちはタギル、ヒントをありがとう。答えを更新しました。
micha

2

私がやっていることは、例外の場合にユーザーが実際に必要な値を提供できるようにすることです。だから私はこのようなものを持っています

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}

そして、これは次のように呼び出すことができます:

defaultIfThrows(child -> child.getID(), null)

1
これは、この考え方を拡張したものであり、「デフォルト値」戦略(回答のように)と「デフォルト値を必要としない "Rethrow RuntimeException"戦略」を区別します。
Ned Twigg、2015年

2

私が提供しているライブラリであるcyclops-reactでサードパーティのライブラリを使用しても構わない場合は、FluentFunctions APIを使用して

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);

ofCheckedはjOOλCheckedFunctionを受け取り、参照をソフト化して標準(チェックされていない)JDK java.util.function.Functionに戻します。

または、FluentFunctions APIを介して、キャプチャした関数を引き続き使用できます。

たとえば、メソッドを実行するには、最大5回再試行し、書き込み可能なステータスをログに記録します。

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");

2

デフォルトでは、Java 8 関数は例外をスローすることを許可していません。複数の回答で提案されているように、それを達成するための多くの方法があります。1つの方法は次のとおりです。

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

次として定義:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

そして、追加しthrowsたりtry/catch、呼び出し元のメソッドで同じ例外。


2

チェックされた例外を伝播するカスタムの戻り値の型を作成します。これは、機能インターフェースのメソッドの「例外をスローする」をわずかに変更して、既存の機能インターフェースをミラーリングする新しいインターフェースを作成する代わりになります。

定義

CheckedValueSupplier

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

CheckedValue

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

使用法

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();

どうしたの?

チェック例外をスローする単一の機能インターフェースが作成されます(CheckedValueSupplier)。これは、チェックされた例外を許可する唯一の機能的なインターフェイスになります。他のすべての機能インターフェイスはCheckedValueSupplier、チェックされた例外をスローするコードをラップするために利用します。

CheckedValueクラスは、チェック例外をスロー任意のロジックを実行した結果を保持します。これにより、コードがのインスタンスにCheckedValue含まれる値にアクセスしようとする時点まで、チェックされた例外の伝播が防止されます。

このアプローチの問題。

  • 私たちは今、最初にスローされた特定のタイプを効果的に隠す「例外」をスローしています。
  • CheckedValue#get()が呼び出されるまで例外が発生したことを認識していません。

消費者他

一部の機能インターフェース(Consumer例えば)は、戻り値を提供しないため、別の方法で処理する必要があります。

消費者の代わりに機能

1つのアプローチは、ストリームを処理するときに適用される、コンシューマーの代わりに関数を使用することです。

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior

エスカレート

または、いつでもにエスカレーションできますRuntimeException。内からのチェック済み例外のエスカレーションをカバーする他の回答がありますConsumer

消費しないでください。

機能的なインターフェイスをすべて避けて、古き良きforループを使用してください。


2

unchecked()複数のユースケースを処理するという、多重定義されたユーティリティ関数を使用しています。


いくつかの使用例

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

支援ユーティリティ

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

0

提供されているソリューションのいくつかは、Eの汎用引数を使用して、スローされる例外のタイプを渡します。

さらに一歩進んで、例外のタイプを渡すのではなく、次のように例外のタイプのコンシューマを渡します...

Consumer<E extends Exception>

Consumer<Exception>アプリケーションの一般的な例外処理のニーズをカバーする、再利用可能なバリエーションをいくつか作成する場合があります。


0

私は一般的なことをします:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

使用法:

 Lambda.handle(() -> method());

0

使用Jool Libraryまたはが言うjOOλ libraryからJOOQ。これは、チェックされていない例外処理インターフェイスを提供するだけでなく、Seqクラスに多くの便利なメソッドを提供します。

また、最大16個のパラメーターを持つ機能インターフェースも含まれています。また、さまざまなシナリオで使用されるタプルクラスを提供します。

Jool Gitリンク

具体的には、org.jooq.lambda.fi.util.functionパッケージのライブラリ検索で。Checkedが先頭に追加されたJava-8のすべてのインターフェースが含まれています。参考のために以下を参照してください:-

ここに画像の説明を入力してください


0

私は、それらをキャッチしたり、ラップしたりする必要なしにRuntimeException Java例外をどこにでも投げる一般的な魔法を備えた小さなlibの作者です。

使用法: unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

ソース:https : //github.com/qoomon/unchecked-exceptions-java


-7
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

3
あなたの作品にコメントしてもいいですか?コードのみの回答はあまり役に立ちません。
ファントマックス2015年

@Franky <code>/<code>::)の代わりに4スペースを使用してプレゼンテーションを修正できます
AdrieanKhisbe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.