it-swarm.com.de

Java 8: Wie arbeite ich mit Methoden zum Auslösen von Ausnahmen in Streams?

Angenommen, ich habe eine Klasse und eine Methode

class A {
  void foo() throws Exception() {
    ...
  }
}

Jetzt möchte ich foo für jede Instanz von A aufrufen, die von einem Stream wie dem folgenden geliefert wird:

void bar() throws Exception {
  Stream<A> as = ...
  as.forEach(a -> a.foo());
}

Frage: Wie gehe ich mit der Ausnahme richtig um? Der Code wird auf meinem Computer nicht kompiliert, weil ich die möglichen Ausnahmen, die foo () auslösen kann, nicht verstehe. Das throws Exception von bar scheint hier nutzlos zu sein. Warum ist das so?

147
Bastian

Sie müssen Ihren Methodenaufruf in einen anderen umschließen, in dem Sie nicht überprüfte Ausnahmen auslösen. Sie können immer noch alles werfen, was eine Unterklasse von RuntimeException ist.

Eine normale Umhüllungssprache ist so etwas wie:

private void safeFoo(final A a) {
    try {
        a.foo();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

(Supertype-Ausnahme Exception ist nur wird als Beispiel verwendet, versuche niemals, es selbst zu fangen.)

Dann können Sie es aufrufen mit: as.forEach(this::safeFoo).

130
skiwi

Wenn Sie nur foo aufrufen möchten und die Ausnahme lieber unverändert (ohne Zeilenumbruch) weitergeben möchten, können Sie stattdessen auch einfach die for -Schleife von Java verwenden (nachdem Sie den Stream in eine Iterable umgewandelt haben) mit einigem Trick ):

for (A a : (Iterable<A>) as::iterator) {
   a.foo();
}

Dies ist zumindest das, was ich in meinen JUnit-Tests mache, in denen ich nicht die Mühe machen möchte, meine geprüften Ausnahmen zu verpacken (und in der Tat meine Tests vorziehen, um die nicht verpackten Originalausnahmen zu werfen).

26
avandeursen

Diese Frage ist vielleicht ein bisschen alt, aber weil ich denke, dass die "richtige" Antwort hier nur eine Möglichkeit ist, die zu versteckten Problemen führen kann, die später in Ihrem Code auftreten. Auch wenn es ein bisschen Kontroverse gibt, gibt es geprüfte Ausnahmen aus einem Grund.

Der meiner Meinung nach eleganteste Weg, den Sie finden können, wurde von Mischa hier angegeben Aggregierte Laufzeitausnahmen in Java 8 Streams indem Sie einfach die Aktionen in "Futures" ausführen kann alle funktionierenden Teile ausführen und nicht funktionierende Ausnahmen als eine einzige sammeln, andernfalls können Sie sie alle in einer Liste sammeln und später verarbeiten.

Ein ähnlicher Ansatz kommt von Benji Weber . Er schlägt vor, einen eigenen Typ zu erstellen, um arbeitende und nicht arbeitende Teile zu sammeln.

Je nachdem, was Sie wirklich wollen, um eine einfache Zuordnung zwischen den Eingabewerten und den aufgetretenen Ausgabewerten zu erreichen, funktionieren möglicherweise auch Ausnahmen für Sie.

Wenn Ihnen eine dieser Möglichkeiten nicht gefällt, sollten Sie (abhängig von der ursprünglichen Ausnahme) mindestens eine eigene Ausnahme verwenden.

13
Mariano

Ich empfehle die Verwendung der Google Guava Throwables-Klasse

verbreiten (werfen werfen)

Propagiert die Ausgabe unverändert, wenn es sich um eine Instanz von RuntimeException oder Error handelt, oder als letzte Möglichkeit, um eine RuntimeException zu verpacken und dann zu propagieren. **

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            throw Throwables.propagate(e);
        }
    });
}

AKTUALISIEREN:

Jetzt, da es veraltet ist, verwenden Sie:

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    });
}
10
fbokovikov

Auf diese Weise können Sie Ausnahmen ein- und auspacken.

class A {
    void foo() throws Exception {
        throw new Exception();
    }
};

interface Task {
    void run() throws Exception;
}

static class TaskException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public TaskException(Exception e) {
        super(e);
    }
}

void bar() throws Exception {
      Stream<A> as = Stream.generate(()->new A());
      try {
        as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo()
    } catch (TaskException e) {
        throw (Exception)e.getCause();
    }
}

static void wrapException(Task task) {
    try {
        task.run();
    } catch (Exception e) {
        throw new TaskException(e);
    }
}
7
aalku

Möglicherweise möchten Sie eine der folgenden Aktionen ausführen:

  • geprüfte Ausnahme weitergeben,
  • binde es ein und verbreite ungeprüfte Ausnahmen, oder
  • fange die Ausnahme ab und stoppe die Weitergabe.

Mehrere Bibliotheken Damit geht das ganz einfach. Das folgende Beispiel wurde mit meiner NoException Bibliothek geschrieben.

// Propagate checked exception
as.forEach(Exceptions.sneak().consumer(A::foo));

// Wrap and propagate unchecked exception
as.forEach(Exceptions.wrap().consumer(A::foo));
as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo));

// Catch the exception and stop propagation (using logging handler for example)
as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));
7
Robert Važan

Mehr lesbare Art und Weise:

class A {
  void foo() throws MyException() {
    ...
  }
}

Verstecke es einfach in einem RuntimeException, um es hinter forEach() zu bringen

  void bar() throws MyException {
      Stream<A> as = ...
      try {
          as.forEach(a -> {
              try {
                  a.foo();
              } catch(MyException e) {
                  throw new RuntimeException(e);
              }
          });
      } catch(RuntimeException e) {
          throw (MyException) e.getCause();
      }
  }

Obwohl ich an dieser Stelle nicht gegen jemanden vorgehen werde, der sagt, er überspringe die Streams und gehe mit einer for-Schleife, es sei denn:

  • sie erstellen Ihren Stream nicht mit Collection.stream(), d. h. nicht direkt in eine for-Schleife.
  • sie versuchen, parallelstream() zu verwenden
1
Kashyap