Java 8:Lambda-Streams、例外付きのメソッドでフィルター


168

Java 8のLambda式を試してみるのに問題があります。通常は問題なく動作しますが、今ではをスローするメソッドがありIOExceptionます。次のコードを確認すると最適です。

class Bank{
    ....
    public Set<String> getActiveAccountNumbers() throws IOException {
        Stream<Account> s =  accounts.values().stream();
        s = s.filter(a -> a.isActive());
        Stream<String> ss = s.map(a -> a.getNumber());
        return ss.collect(Collectors.toSet());
    }
    ....
}

interface Account{
    ....
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
    ....
}

問題は、コンパイルされないことです。これは、isActive-およびgetNumber-Methodsの起こり得る例外をキャッチする必要があるためです。しかし、以下のようにtry-catch-Blockを明示的に使用しても、例外をキャッチしないため、コンパイルされません。したがって、JDKにバグがあるか、これらの例外をキャッチする方法がわかりません。

class Bank{
    ....
    //Doesn't compile either
    public Set<String> getActiveAccountNumbers() throws IOException {
        try{
            Stream<Account> s =  accounts.values().stream();
            s = s.filter(a -> a.isActive());
            Stream<String> ss = s.map(a -> a.getNumber());
            return ss.collect(Collectors.toSet());
        }catch(IOException ex){
        }
    }
    ....
}

どうすればそれを機能させることができますか?誰かが私に正しい解決策を教えてくれますか?




4
シンプルで正しい答え:ラムダ内の例外をキャッチします。
Brian Goetz、2015年

回答:


211

ラムダをエスケープするに、例外をキャッチする必要があります。

s = s.filter(a -> { try { return a.isActive(); } 
                    catch (IOException e) { throw new UncheckedIOException(e); }}});

ラムダは、作成した場所では評価されず、JDKクラス内のまったく関係のない場所で評価されるという事実を考慮してください。つまり、そのチェックされた例外がスローされるポイントであり、その場所では宣言されていません。

チェックされた例外をチェックされていない例外に変換するラムダのラッパーを使用することで、これに対処できます。

public static <T> T uncheckCall(Callable<T> callable) {
  try { return callable.call(); }
  catch (RuntimeException e) { throw e; }
  catch (Exception e) { throw new RuntimeException(e); }
}

あなたの例は次のように書かれます

return s.filter(a -> uncheckCall(a::isActive))
        .map(Account::getNumber)
        .collect(toSet());

私のプロジェクトでは、この問題をラップせずに扱います。代わりに、コンパイラによる例外のチェックを効果的に拒否するメソッドを使用します。言うまでもなく、これは注意して処理する必要があり、プロジェクトのすべての人は、宣言されていない場所にチェック例外が表示される場合があることに注意する必要があります。これは配管コードです:

public static <T> T uncheckCall(Callable<T> callable) {
  try { return callable.call(); }
  catch (Exception e) { return sneakyThrow(e); }
}
public static void uncheckRun(RunnableExc r) {
  try { r.run(); } catch (Exception e) { sneakyThrow(e); }
}
public interface RunnableExc { void run() throws Exception; }


@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

と宣言していなくIOExceptionても、あなたの顔に投げ込まれることを期待できますcollect。で最も、すべてではないが、現実の例あなただけとにかく、例外を再スローし、一般的な失敗とそれを処理したいと思います。それらのすべての場合において、明快さまたは正確さにおいて何も失われません。実際にその場で例外に対応したい他のケースに注意してください。開発者は、コンパイラーがそこIOExceptionにキャッチするものがあることをコンパイラーに認識させず、そのような例外をスローできないと信じ込んだために、コンパイラーがキャッチしようとすると実際に文句を言うでしょう。


4
NettyIOが「卑劣な投げ」をするのを見たことがあるので、椅子を窓の外に投げたかったのです。「何?どこから例外リークがチェックされたのですか?」これは、私が見た卑劣なスローの最初の合法的なユースケースです。プログラマーとしては、卑劣なスローが可能であることを示すために警戒する必要があります。たぶん、チェックされた例外をサポートする別のストリームインターフェイス/ Implを作成する方が良いでしょう
kevinarpe 2015

8
正気なAPIは、宣言されていないチェック済み例外をクライアントに配信するべきではありません。ただし、API 内では、チェックされた例外がリークする可能性があるという理解があります。それらが一般的な失敗の単なる別の兆候であり、捕獲されて卸売りで処理されようとしている限り、害を及ぼすことはありません。
Marko Topolnik、2015

5
@kevinarpeこれが卑劣なスローが悪い考えである正確な理由です。コンパイラを短絡すると、将来のメンテナを混乱させることになります。
するThorbjörnRavnアンデルセン

29
ルールが気に入らないからといって、法律を自分の手に委ねることは良いことではありません。プログラムの透明性と保守性のはるかに重要な考慮事項よりもコードライターの利便性が優先されるため、あなたのアドバイスは無責任です。
Brian Goetz、2015年

34
@brian何かがルールであるからといって、それが良いアイデアであるとは限りません。しかし、私の答えの2番目の部分を「アドバイス」と呼んでいることに驚いています。私が解決策として提案することと、FYIとして興味のある読者に何を提供するのかを明確な免責事項で明確に示したからです。
Marko Topolnik、2015年

29

ラムダで静的な痛みを伝播することもできるので、全体が読みやすく見えます。

s.filter(a -> propagate(a::isActive))

propagateここではjava.util.concurrent.Callableパラメータとして受け取り、呼び出し中にキャッチされた例外をに変換しRuntimeExceptionます。Guavaにも同様の変換メソッドThrowables#propagate(Throwable)があります。

このメソッドはラムダメソッドチェーンに不可欠であると思われるので、いつか人気のあるライブラリの1つに追加されることを期待します。そうしないと、この伝播動作がデフォルトになります。

public class PropagateExceptionsSample {
    // a simplified version of Throwables#propagate
    public static RuntimeException runtime(Throwable e) {
        if (e instanceof RuntimeException) {
            return (RuntimeException)e;
        }

        return new RuntimeException(e);
    }

    // this is a new one, n/a in public libs
    // Callable just suits as a functional interface in JDK throwing Exception 
    public static <V> V propagate(Callable<V> callable){
        try {
            return callable.call();
        } catch (Exception e) {
            throw runtime(e);
        }
    }

    public static void main(String[] args) {
        class Account{
            String name;    
            Account(String name) { this.name = name;}

            public boolean isActive() throws IOException {
                return name.startsWith("a");
            }
        }


        List<Account> accounts = new ArrayList<>(Arrays.asList(new Account("andrey"), new Account("angela"), new Account("pamela")));

        Stream<Account> s = accounts.stream();

        s
          .filter(a -> propagate(a::isActive))
          .map(a -> a.name)
          .forEach(System.out::println);
    }
}

22

このUtilExceptionヘルパークラスを使用すると、次のようにJavaストリームでチェック済みの例外を使用できます。

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

Class::forNameスローClassNotFoundExceptionされ、チェックを。ストリーム自体もをスローしClassNotFoundException、一部のラッピングされていない未チェックの例外はスローしません。

public final class UtilException {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

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

@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .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) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

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

}

それを使用する方法に関する他の多くの例(静的にインポートした後UtilException):

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }

ただし、次の利点、欠点、および制限を理解する前に使用しないでください

•呼び出しコードでチェック済み例外を処理する場合は、ストリームを含むメソッドのthrows句にそれを追加する必要があります。コンパイラーはもはやそれを追加することを強制しないので、それを忘れる方が簡単です。

•呼び出しコードがチェック済み例外をすでに処理している場合、コンパイラーは、ストリームを含むメソッド宣言にthrows句を追加するように通知します(そうしないと、対応するtryステートメントの本文で例外がスローされることはありません) )。

•いずれの場合も、ストリーム自体を囲んで、ストリームを含むメソッド内でチェックされた例外をキャッチすることはできません(試みた場合、コンパイラーは次のようにします:対応するtryステートメントの本文で例外がスローされることはありません)。

•宣言した例外を文字通り決してスローできないメソッドを呼び出す場合は、throws句を含めないでください。例:new String(byteArr、 "UTF-8")はUnsupportedEncodingExceptionをスローしますが、UTF-8はJava仕様によって常に存在することが保証されています。ここで、throws宣言は煩わしいものであり、最小限のボイラープレートで沈黙させるためのソリューションは歓迎されます。

•チェックされた例外が嫌いで、そもそもJava言語に追加すべきではないと感じた場合(多くの人がこのように考えており、私もその一人ではありません)、チェックされた例外をストリームを含むメソッドの句をスローします。チェックされた例外は、チェックされていない例外と同じように動作します。

•throws宣言を追加するオプションがない厳密なインターフェイスを実装していて、例外をスローすることが完全に適切である場合、例外をラップして、それをスローする特権を得るだけで、疑似例外のあるスタックトレースが発生します。実際に何がうまくいかなかったかについての情報を提供しません。良い例は、チェックされた例外をスローしないRunnable.run()です。この場合、ストリームを含むメソッドのthrows句に、checked例外を追加しないことを決定できます。

•いずれの場合でも、チェックされた例外をストリームを含むメソッドのthrows句に追加しない(または追加するのを忘れる)場合は、CHECKED例外をスローすることによる次の2つの結果に注意してください。

1)呼び出しコードは名前でそれをキャッチすることができません(試みた場合、コンパイラーは次のように言います:対応するtryステートメントの本文で例外がスローされることはありません)。それはバブルし、おそらく何らかの「キャッチ例外」または「キャッチスロー可能」によってメインプログラムループでキャッチされます。

2)これは、最小の驚きの原則に違反します。実行可能なすべての例外を確実にキャッチできるように、RuntimeExceptionをキャッチするだけでは十分ではありません。このため、これはフレームワークコードではなく、完全に制御できるビジネスコードでのみ行う必要があると思います。

結論:ここでの制限は深刻ではなく、UtilExceptionクラスは恐れることなく使用できると思います。しかし、それはあなた次第です!


8

Streamラムダをラップして未チェックの例外をスローし、後でターミナル操作でその未チェックの例外をラップ解除することで、独自のバリアントをロールすることができます。

@FunctionalInterface
public interface ThrowingPredicate<T, X extends Throwable> {
    public boolean test(T t) throws X;
}

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

@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
    public R get() throws X;
}

public interface ThrowingStream<T, X extends Throwable> {
    public ThrowingStream<T, X> filter(
            ThrowingPredicate<? super T, ? extends X> predicate);

    public <R> ThrowingStream<T, R> map(
            ThrowingFunction<? super T, ? extends R, ? extends X> mapper);

    public <A, R> R collect(Collector<? super T, A, R> collector) throws X;

    // etc
}

class StreamAdapter<T, X extends Throwable> implements ThrowingStream<T, X> {
    private static class AdapterException extends RuntimeException {
        public AdapterException(Throwable cause) {
            super(cause);
        }
    }

    private final Stream<T> delegate;
    private final Class<X> x;

    StreamAdapter(Stream<T> delegate, Class<X> x) {
        this.delegate = delegate;
        this.x = x;
    }

    private <R> R maskException(ThrowingSupplier<R, X> method) {
        try {
            return method.get();
        } catch (Throwable t) {
            if (x.isInstance(t)) {
                throw new AdapterException(t);
            } else {
                throw t;
            }
        }
    }

    @Override
    public ThrowingStream<T, X> filter(ThrowingPredicate<T, X> predicate) {
        return new StreamAdapter<>(
                delegate.filter(t -> maskException(() -> predicate.test(t))), x);
    }

    @Override
    public <R> ThrowingStream<R, X> map(ThrowingFunction<T, R, X> mapper) {
        return new StreamAdapter<>(
                delegate.map(t -> maskException(() -> mapper.apply(t))), x);
    }

    private <R> R unmaskException(Supplier<R> method) throws X {
        try {
            return method.get();
        } catch (AdapterException e) {
            throw x.cast(e.getCause());
        }
    }

    @Override
    public <A, R> R collect(Collector<T, A, R> collector) throws X {
        return unmaskException(() -> delegate.collect(collector));
    }
}

次に、これをと同じ方法で使用できますStream

Stream<Account> s = accounts.values().stream();
ThrowingStream<Account, IOException> ts = new StreamAdapter<>(s, IOException.class);
return ts.filter(Account::isActive).map(Account::getNumber).collect(toSet());

このソリューションにはかなりのボイラープレートが必要になるので、クラス全体(およびその他!)についてここで説明したことを正確に実行する、すでに作成したライブラリを確認することをお勧めしますStream


こんにちは...小さなバグ? new StreamBridge<>(ts, IOException.class);->new StreamBridge<>(s, IOException.class);
kevinarpe 2015

1
@kevinarpeうん。それも言うべきだったStreamAdapter
ジェフリー

5

#propagate()メソッドを使用します。Sam BeranによるJava 8ブログの非Guava実装のサンプル:

public class Throwables {
    public interface ExceptionWrapper<E> {
        E wrap(Exception e);
    }

    public static <T> T propagate(Callable<T> callable) throws RuntimeException {
        return propagate(callable, RuntimeException::new);
    }

    public static <T, E extends Throwable> T propagate(Callable<T> callable, ExceptionWrapper<E> wrapper) throws E {
        try {
            return callable.call();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw wrapper.wrap(e);
        }
    }
}

Java 8ブログのリンクは機能していません。
Spycho 2015年

4

これは質問に直接回答するわけではありません(他にも多くの回答があります)が、そもそも問題を回避しようとします。

私の経験では、Stream(または他のラムダ式)で例外を処理する必要性は、例外がスローされるべきではないメソッドからスローされるように宣言されているという事実から生じることがよくあります。これは、多くの場合、ビジネスロジックを入出力と混合することから生じます。あなたのAccountインターフェースは完璧な例です:

interface Account {
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
}

IOException各ゲッターでをスローする代わりに、次の設計を検討してください。

interface AccountReader {
    Account readAccount(…) throws IOException;
}

interface Account {
    boolean isActive();
    String getNumber();
}

このメソッドAccountReader.readAccount(…)は、データベースやファイルなどからアカウントを読み取り、成功しなかった場合に例外をスローする可能性があります。Accountすでにすべての値を含み、すぐに使用できるオブジェクトを作成します。値は既にによって読み込まれているreadAccount(…)ため、ゲッターは例外をスローしません。したがって、例外をラップ、マスキング、または非表示にする必要なく、ラムダで自由に使用できます。

もちろん、私が説明した方法で常に実行できるとは限りませんが、多くの場合それが可能であり、それによりコードがよりクリーンになります(IMHO):

  • 懸念の分離単一責任の原則の改善
  • ボイラープレートの削減:throws IOExceptionコンパイラーを満足させるためだけに、使用せずにコードを散らかす必要はありません
  • エラー処理:フィールド値を取得したいという理由だけで、ビジネスロジックの途中ではなく、ファイルまたはデータベースから読み取るときに、発生したエラーを処理します。
  • あなたが作ることができるかもしれません Account 不変にして、その利点(スレッドセーフなど)から利益
  • あなたは使用することを「ダーティトリック」や回避策を必要としないAccount(例えば中AラムダでStream

4

AbacusUtilStream and Try使用した以下の簡単なコードで解決できます。

Stream.of(accounts).filter(a -> Try.call(a::isActive)).map(a -> Try.call(a::getNumber)).toSet();

開示:私はの開発者ですAbacusUtil


3

@marcgソリューションを拡張すると、通常、Streamsでチェック済み例外をスローおよびキャッチできます。つまり、コンパイラーは、ストリームの外にいるのと同じように、キャッチ/再スローするように要求します

@FunctionalInterface
public interface Predicate_WithExceptions<T, E extends Exception> {
    boolean test(T t) throws E;
}

/**
 * .filter(rethrowPredicate(t -> t.isActive()))
 */
public static <T, E extends Exception> Predicate<T> rethrowPredicate(Predicate_WithExceptions<T, E> predicate) throws E {
    return t -> {
        try {
            return predicate.test(t);
        } catch (Exception exception) {
            return throwActualException(exception);
        }
    };
}

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

次に、例は次のように記述されます(より明確に示すためにテストを追加します)。

@Test
public void testPredicate() throws MyTestException {
    List<String> nonEmptyStrings = Stream.of("ciao", "")
            .filter(rethrowPredicate(s -> notEmpty(s)))
            .collect(toList());
    assertEquals(1, nonEmptyStrings.size());
    assertEquals("ciao", nonEmptyStrings.get(0));
}

private class MyTestException extends Exception { }

private boolean notEmpty(String value) throws MyTestException {
    if(value==null) {
        throw new MyTestException();
    }
    return !value.isEmpty();
}

@Test
public void testPredicateRaisingException() throws MyTestException {
    try {
        Stream.of("ciao", null)
                .filter(rethrowPredicate(s -> notEmpty(s)))
                .collect(toList());
        fail();
    } catch (MyTestException e) {
        //OK
    }
}

この例はコンパイルされません
Roman M

こんにちは@RomanMこれを指摘してくれてありがとう:「throwActualException」メソッドで欠落していた戻り値の型を修正しました。これを本番環境で使用しているので、あなたの側でも機能することを願っています。
PaoloC 2016

3

IOExceptionを(RuntimeExceptionに)処理するコードを適切に追加するには、メソッドは次のようになります。

Stream<Account> s =  accounts.values().stream();

s = s.filter(a -> { try { return a.isActive(); } 
  catch (IOException e) { throw new RuntimeException(e); }});

Stream<String> ss = s.map(a -> { try { return a.getNumber() }
  catch (IOException e) { throw new RuntimeException(e); }});

return ss.collect(Collectors.toSet());

今の問題は、IOExceptionがとしてキャプチャされ、RuntimeException再びに変換される必要があることです。IOExceptionです。これにより、上記のメソッドにさらにコードが追加されます。

なぜStreamこれがこのようにできるときに使用するのですか-そしてメソッドがスローするIOExceptionので、追加のコードも必要ありません:

Set<String> set = new HashSet<>();
for(Account a: accounts.values()){
  if(a.isActive()){
     set.add(a.getNumber());
  } 
}
return set;


1

あなたの例は次のように書くことができます:

import utils.stream.Unthrow;

class Bank{
   ....
   public Set<String> getActiveAccountNumbers() {
       return accounts.values().stream()
           .filter(a -> Unthrow.wrap(() -> a.isActive()))
           .map(a -> Unthrow.wrap(() -> a.getNumber()))
           .collect(Collectors.toSet());
   }
   ....
}

Unthrowクラスは、ここで撮影することができますhttps://github.com/SeregaLBN/StreamUnthrower



0

Javaの機能インターフェースは、チェック済みまたは未チェックの例外を宣言しません。メソッドのシグネチャを次のように変更する必要があります。

boolean isActive() throws IOException; 
String getNumber() throwsIOException;

に:

boolean isActive();
String getNumber();

または、try-catchブロックで処理します。

public Set<String> getActiveAccountNumbers() {
  Stream<Account> s =  accounts.values().stream();
  s = s.filter(a -> 
    try{
      a.isActive();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  Stream<String> ss = s.map(a -> 
    try{
      a.getNumber();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  return ss.collect(Collectors.toSet());
}

別のオプションは、カスタムラッパーを作成するか、ThrowingFunctionのようなライブラリを使用することです。ライブラリを使用すると、pom.xmlに依存関係を追加するだけで済みます。

<dependency>
    <groupId>pl.touk</groupId>
    <artifactId>throwing-function</artifactId>
    <version>1.3</version>
</dependency>

そして、ThrowingFunction、ThrowingConsumer、ThrowingPredicate、ThrowingRunnable、ThrowingSupplierのような特定のクラスを使用します。

最後に、コードは次のようになります。

public Set<String> getActiveAccountNumbers() {
  return accounts.values().stream()
    .filter(ThrowingPredicate.unchecked(Account::isActive))
    .map(ThrowingFunction.unchecked(Account::getNumber))
    .collect(Collectors.toSet());
}

0

ストリームでチェックされた例外を処理する方法が見当たらない(Java -8)。私が適用した唯一の方法は、ストリームでチェックされた例外をキャッチし、チェックされていない例外として再スローすることです。

        Arrays.stream(VERSIONS)
        .map(version -> TemplateStore.class
                .getClassLoader().getResourceAsStream(String.format(TEMPLATE_FILE_MASK, version)))
        .map(inputStream -> {
            try {
                return ((EdiTemplates) JAXBContext.newInstance(EdiTemplates.class).createUnmarshaller()
                        .unmarshal(inputStream)).getMessageTemplate();
            } catch (JAXBException e) {
                throw new IllegalArgumentException(ERROR, e);
            }})
        .flatMap(Collection::stream)
        .collect(Collectors.toList());

あなたは実際に質問に答えようとしていますか?
Nilambar Sharma

@Nilambar-ここで私が言おうとしていることは、Javaストリームの使用中にチェック例外を処理する方法がないことです。 2つあります。1。私の理解が正しくないと思われる場合は、私を訂正してください。または2.考えている場合、私の投稿は無関係であり、同じものを削除させていただきます。よろしく、Atul
atul sachan

0

ストリーム内で例外を処理し、追加の例外の処理を続行したい場合は、Eitherの概念を使用したBrian Vermeer によるDZoneの優れた記事があります。この状況を処理する優れた方法を示しています。欠けているのはサンプルコードだけです。これは、その記事の概念を使用した私の調査のサンプルです。

@Test
public void whenValuePrinted_thenPrintValue() {

    List<Integer> intStream = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
    intStream.stream().map(Either.liftWithValue(item -> doSomething(item)))
             .map(item -> item.isLeft() ? item.getLeft() : item.getRight())
             .flatMap(o -> {
                 System.out.println(o);
                 return o.isPresent() ? Stream.of(o.get()) : Stream.empty();
             })
             .forEach(System.out::println);
}

private Object doSomething(Integer item) throws Exception {

    if (item == 0) {
        throw new Exception("Zero ain't a number!");
    } else if (item == 4) {
        return Optional.empty();
    }

    return item;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.