it-swarm.com.de

Java 8: Lambda-Streams, Filtern nach Methode mit Ausnahme

Ich habe ein Problem beim Ausprobieren der Lambda-Ausdrücke von Java 8. Normalerweise funktioniert es gut, aber jetzt habe ich Methoden, die IOException werfen. Am besten schauen Sie sich folgenden Code an:

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;
    ....
}

Das Problem ist, dass es nicht kompiliert werden kann, da ich die möglichen Ausnahmen der isActive- und der getNumber-Methods feststellen muss. Aber selbst wenn ich explizit einen try-catch-Block wie unten verwende, kompiliert er immer noch nicht, da ich die Exception nicht fange. Entweder gibt es einen Fehler in JDK, oder ich weiß nicht, wie ich diese Ausnahmen einfangen kann.

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){
        }
    }
    ....
}

Wie kann ich es zum Laufen bringen? Kann mir jemand die richtige Lösung vorschlagen?

149
Martin Weber

Sie müssen die Ausnahme fangen, bevor sie dem Lambda entgeht:

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

Bedenken Sie die Tatsache, dass das Lambda nicht an der Stelle ausgewertet wird, an der Sie es schreiben, sondern an einer völlig anderen Stelle innerhalb einer JDK-Klasse. Das wäre also der Punkt, an dem die geprüfte Ausnahme ausgelöst würde, und an dieser Stelle wird sie nicht deklariert.

Sie können damit umgehen, indem Sie einen Lambda-Wrapper verwenden, der geprüfte Ausnahmen in ungeprüfte Ausdrücke übersetzt:

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

Dein Beispiel würde als geschrieben

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

In meinen Projekten beschäftige ich mich ohne Umhüllung mit diesem Problem. Stattdessen verwende ich eine Methode, die die Überprüfung von Ausnahmen durch den Compiler effektiv entschärft. Es ist unnötig zu erwähnen, dass dies mit Vorsicht behandelt werden muss und jeder im Projekt muss sich bewusst sein, dass eine geprüfte Ausnahme erscheinen kann, wenn sie nicht deklariert ist. Dies ist der Installationscode:

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;
}

und Sie können damit rechnen, dass eine IOException in Ihr Gesicht geworfen wird, obwohl collect es nicht deklariert. In most, aber nicht allen Fällen aus dem wirklichen Leben möchten Sie die Ausnahme sowieso nur erneut auslösen und sie als generischen Fehler behandeln. In all diesen Fällen geht nichts an Klarheit oder Korrektheit verloren. Hüten Sie sich nur vor den anderen Fällen, in denen Sie vor Ort auf die Ausnahme reagieren möchten. Der Entwickler wird vom Compiler nicht darauf aufmerksam gemacht, dass es eine IOException gibt, die dort abgefangen werden kann, und der Compiler wird sich in der Tat beschweren, wenn Sie versuchen, ihn zu fangen, weil wir ihn getäuscht haben, zu glauben, dass keine solche Ausnahme ausgelöst werden kann.

191
Marko Topolnik

Sie können Ihren statischen Schmerz auch mit Lambdas verbreiten, so dass das Ganze lesbar erscheint:

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

propagate empfängt hier Java.util.concurrent.Callable als Parameter und konvertiert jede während des Aufrufs festgestellte Ausnahme in RuntimeException. Es gibt eine ähnliche Umwandlungsmethode Throwables # propagate (Throwable) in Guava.

Diese Methode scheint für die Verkettung von Lambda-Methoden unerlässlich zu sein, daher hoffe ich, dass sie eines Tages zu einer der populärsten Bibliotheken hinzugefügt wird.

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);
    }
}
26
Andrey Chaschev

Mit dieser UtilException-Helper-Klasse können Sie in Java-Streams alle geprüften Ausnahmen verwenden, z.

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

Hinweis Class::forName löst ClassNotFoundException aus. Dies ist checked. Der Stream selbst wirft auch ClassNotFoundException und NICHT einige ungeprüfte Wrapping-Exceptions ab.

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; }

}

Viele andere Beispiele zur Verwendung (nach statischem Import von 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");
    }

Verwenden Sie es jedoch nicht, bevor Sie die folgenden Vorteile, Nachteile und Einschränkungen verstehen:

• Wenn der aufrufende Code die geprüfte Ausnahmebedingung behandeln soll, MÜSSEN Sie ihn der throws-Klausel der Methode hinzufügen, die den Stream enthält . Der Compiler zwingt Sie nicht mehr, es hinzuzufügen, so dass Sie es leichter vergessen können.

• Wenn der aufrufende Code die geprüfte Ausnahmebedingung bereits behandelt, erinnert der Compiler Sie daran, die Throws-Klausel zur Methodendeklaration hinzuzufügen das enthält den Stream (wenn Sie dies nicht tun, heißt es: Exception wird niemals im Rumpf der entsprechenden try-Anweisung geworfen).

• In jedem Fall können Sie den Stream nicht selbst umgeben, um die aktivierte Ausnahme INSIDE der Methode abzufangen, die den Stream enthält (Wenn Sie es versuchen, sagt der Compiler: Eine Ausnahme wird niemals im Rumpf der entsprechenden try-Anweisung ausgelöst).

• Wenn Sie eine Methode aufrufen, die buchstäblich niemals die von ihr deklarierte Ausnahme auslösen kann, sollten Sie die throws-Klausel ..__ nicht einschließen. Beispiel: new String (byteArr, "UTF-8") löst UnsupportedEncodingException aus, UTF-8 wird jedoch durch die Java-Spezifikation garantiert immer vorhanden .. ... Hier ist die Wurf-Deklaration ein Ärgernis und jede Lösung, um sie mit minimaler Heizplatte zum Schweigen zu bringen, ist willkommen.

• Wenn Sie harte geprüfte Ausnahmen hassen und der Meinung sind, dass sie niemals der Java-Sprache hinzugefügt werden sollten (eine wachsende Anzahl von Menschen denkt so,. Und ich bin NICHT einer von ihnen), dann fügen Sie das Häkchen nicht hinzu Ausnahme von der Throws-Klausel der Methode, die den Stream enthält. Das geprüfte Eine Ausnahme verhält sich also wie eine ungeprüfte Ausnahme.

• Wenn Sie eine strikte Schnittstelle implementieren, bei der Sie keine Option zum Hinzufügen einer Throws-Deklaration haben und dennoch eine Ausnahme ausgelöst wird, ist Es ist durchaus angebracht, eine Ausnahme zu verpacken, um das Privileg zu erhalten, sie zu werfen, und führt zu einem Stacktrace mit falschen Ausnahmen, die Keine Informationen darüber, was tatsächlich schiefgegangen ist. Ein gutes Beispiel ist Runnable.run (), das keine geprüften Ausnahmen auslöst . In diesem Fall können Sie entscheiden, die geprüfte Ausnahme nicht der Throws-Klausel der Methode hinzuzufügen, die den Stream enthält.

• In jedem Fall, wenn Sie sich dafür entscheiden, die geprüfte Ausnahme NICHT zu der Throws-Klausel der Methode hinzuzufügen, die den Stream enthält (oder das Hinzufügen vergessen), Beachten Sie diese beiden Konsequenzen des Auswerfens von CHECKED-Ausnahmen:

1) Der aufrufende Code kann den Namen nicht abfangen (wenn Sie es versuchen, sagt der Compiler: Eine Ausnahme wird niemals im Rumpf der entsprechenden try -Anweisung ausgelöst). Es blubbert und wird wahrscheinlich in der Hauptprogrammschleife von "catch Exception" oder "catch Throwable" aufgefangen. will sowieso.

2) Es verstößt gegen das Prinzip der geringsten Überraschung: Es reicht nicht mehr aus, um RuntimeException abzufangen, um das Einfangen aller .__ zu garantieren. mögliche Ausnahmen. Aus diesem Grund glaube ich, dass dies nicht im Rahmencode erfolgen sollte, sondern nur im Geschäftscode, den Sie vollständig kontrollieren.

Zusammenfassend: Ich glaube, dass die Einschränkungen hier nicht ernst sind und die UtilException-Klasse ohne Angst verwendet werden kann. Es liegt jedoch an Ihnen!

17
MarcG

Sie können möglicherweise Ihre eigene Stream-Variante rollen, indem Sie Ihr Lambda so umwickeln, dass eine ungeprüfte Ausnahme ausgelöst wird, und diese ungeprüfte Ausnahme später bei Terminalvorgängen aufheben:

@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));
    }
}

Dann können Sie dies genauso wie eine Stream verwenden:

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());

Diese Lösung würde einiges an Boilerplate erfordern, also schlage ich vor, dass Sie sich die bereits erstellte -Bibliothek ansehen die genau das tut, was ich hier für die gesamte Stream-Klasse (und mehr!) Beschrieben habe.

8
Jeffrey

Verwenden Sie die Methode #propagate (). Beispiel einer Nicht-Guava-Implementierung aus dem Java 8-Blog von Sam Beran :

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);
        }
    }
}
5
n0mer

Um IOException (zu RuntimeException), der Code verarbeitet, richtig hinzuzufügen, sieht Ihre Methode folgendermaßen aus:

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());

Das Problem ist nun, dass die IOException als RuntimeException erfasst und wieder in eine IOException konvertiert werden muss. Dadurch wird der obigen Methode noch mehr Code hinzugefügt.

Warum Stream verwenden, wenn dies genauso möglich ist - und die Methode IOException wirft, so dass auch hierfür kein zusätzlicher Code benötigt wird:

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

Es kann durch einfachen Code mit Stream und Try in AbacusUtil gelöst werden:

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

Offenlegung : Ich bin der Entwickler von AbacusUtil.

3
user_3380739

Dies beantwortet die Frage nicht direkt (es gibt viele andere Antworten, die dies tun), sondern versucht, das Problem zunächst zu vermeiden:

Nach meiner Erfahrung besteht die Notwendigkeit, mit Ausnahmen in einer Stream (oder einem anderen Lambda-Ausdruck) umzugehen, häufig darin, dass die Ausnahmen als von Methoden geworfen erklärt werden, wo sie nicht geworfen werden sollen. Dies ist häufig auf das Mischen von Geschäftslogik mit Ein- und Ausgabe zurückzuführen. Ihre Account-Schnittstelle ist ein perfektes Beispiel:

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

Anstatt eine IOException auf jeden Getter zu werfen, betrachten Sie diesen Entwurf:

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

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

Die Methode AccountReader.readAccount(…) könnte ein Konto aus einer Datenbank oder einer Datei oder Ähnlichem lesen und eine Ausnahme auslösen, falls dies nicht erfolgreich ist. Es erstellt ein Account-Objekt, das bereits alle Werte enthält und zur Verwendung bereit ist. Da die Werte bereits von readAccount(…) geladen wurden, würden die Getter keine Ausnahme auslösen. Sie können sie also frei in Lambdas verwenden, ohne die Ausnahmen einwickeln, maskieren oder ausblenden zu müssen.

Natürlich ist es nicht immer möglich, es so zu machen, wie ich es beschrieben habe, aber oft ist das der Fall und führt zu reinem Code (IMHO):

  • Bessere Trennung von Anliegen und Befolgung Grundsatz der Einzelverantwortung
  • Weniger Boilerplate: Sie müssen Ihren Code nicht mit throws IOException überladen, um den Compiler zu befriedigen
  • Fehlerbehandlung: Sie behandeln die Fehler dort, wo sie auftreten - beim Lesen aus einer Datei oder Datenbank - anstatt irgendwo in der Mitte Ihrer Geschäftslogik, nur weil Sie einen Feldwert abrufen möchten
  • Sie können möglicherweise Accountunveränderlich machen und von den Vorteilen davon profitieren (z. B. Thread-Sicherheit).
  • Sie brauchen keine "schmutzigen Tricks" oder Workarounds, um Account in Lambdas zu verwenden (z. B. in einer Stream).
3
siegi

Durch die Erweiterung der @ marcg-Lösung können Sie normalerweise eine geprüfte Ausnahme in Streams werfen und abfangen. das heißt, der Compiler wird Sie auffordern, zu fangen/erneut zu werfen wie Sie sich außerhalb von Streams befanden

@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;
}

Dann würde Ihr Beispiel wie folgt geschrieben (Hinzufügen von Tests, um es deutlicher zu machen):

@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
    }
}
2
PaoloC

Ihr Beispiel kann geschrieben werden als:

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());
   }
   ....
}

Die Klasse Unthrow kann hier abgelegt werden https://github.com/SeregaLBN/StreamUnthrower

1
SeregaLBN

Im Hinblick auf dieses Problem habe ich eine kleine Bibliothek für den Umgang mit geprüften Ausnahmen und Lambdas entwickelt. Benutzerdefinierte Adapter ermöglichen die Integration mit vorhandenen Funktionstypen:

stream().map(unchecked(URI::new)) //with a static import

https://github.com/TouK/ThrowingFunction/

1

Ich sehe keine Möglichkeit, geprüfte Ausnahmen in Stream (Java -8) zu behandeln. Die einzige Möglichkeit, die ich angewendet habe, ist, geprüfte Ausnahmen in Stream abzufangen und sie erneut als ungeprüfte Ausnahmen zu werfen.

        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());
0
atul sachan

Die funktionalen Schnittstellen in Java deklarieren keine geprüften oder ungeprüften Ausnahmen. Sie müssen die Signatur der Methoden folgendermaßen ändern:

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

Zu:

boolean isActive();
String getNumber();

Oder handhaben Sie es mit dem try-catch-Block:

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());
}

Eine andere Möglichkeit ist, einen benutzerdefinierten Wrapper zu schreiben oder eine Bibliothek wie ThrowingFunction ..__ zu verwenden. Mit der Bibliothek müssen wir nur die Abhängigkeit zu unserer pom.xml hinzufügen:

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

Und verwenden Sie die spezifischen Klassen wie ThrowingFunction, ThrowingConsumer, ThrowingPredicate, ThrowingRunnable, ThrowingSupplier.

Am Ende sieht der Code so aus:

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

Wenn es Ihnen nichts ausmacht, Drittanbieter-Bibliotheken zu verwenden, haben AOLs cyclops-react lib, Disclosure :: Ich bin ein Mitarbeiter, der eine ExceptionSoftener -Klasse hat, die hier helfen kann.

 s.filter(softenPredicate(a->a.isActive()));
0
John McClean