Java 8: Comment travailler avec les méthodes de lancement d'exceptions dans les flux?


Supposons que j'ai une classe et une méthode

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

Maintenant, je voudrais appeler foo pour chaque instance de A livré par un flux comme:

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

Question: Comment gérer correctement l'exception? Le code ne compile pas sur ma machine car je ne gère pas les exceptions qui peuvent être levées par foo(). Le throws Exception de bar semble être inutile. Pourquoi est-ce?

Author: Luiggi Mendoza, 2014-05-08

7 answers

Vous devez envelopper votre appel de méthode dans un autre, où vous ne lancez pas exceptions vérifiées. Vous pouvez toujours lancer tout ce qui est une sous-classe de RuntimeException.

Un idiome d'emballage normal est quelque chose comme:

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

(Exception Supertype Exception est seulement utilisé comme exemple, n'essayez jamais de l'attraper vous-même)

Alors vous pouvez l'appeler avec: as.forEach(this::safeFoo).

 159
Author: skiwi, 2014-05-08 17:35:43

Si tout ce que vous voulez est d'invoquer foo, et que vous préférez propager l'exception telle quelle (sans encapsuler), vous pouvez également simplement utiliser la boucle for de Java à la place (après avoir transformé le flux en Itérable avec une astuce ):

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

C'est du moins ce que je fais dans mes tests JUnit, où je ne veux pas avoir la peine d'emballer mes exceptions vérifiées (et préfère en fait mes tests pour jeter les originaux non emballés)

 40
Author: avandeursen, 2017-05-23 12:18:10

Cette question est peut-être un peu ancienne, mais parce que je pense que la "bonne" réponse ici n'est qu'une façon qui peut conduire à des problèmes cachés plus tard dans votre code. Même s'il y a un peu de Controverse, les exceptions vérifiées existent pour une raison.

La manière la plus élégante à mon avis que vous puissiez trouver a été donnée par Misha ici Exceptions d'exécution agrégées dans les flux Java 8 en effectuant simplement les actions dans "futures". Vous pouvez donc exécuter toutes les pièces de travail et ne pas collecter exceptions de travail comme une seule. Sinon, vous pouvez les collecter tous dans une liste et les traiter plus tard.

Une approche similaire vient de Benji Weber. Il suggère de créer un propre type pour collecter des pièces de travail et non de travail.

Selon ce que vous voulez vraiment réaliser un mappage simple entre les valeurs d'entrée et les valeurs de sortie, les exceptions survenues peuvent également fonctionner pour vous.

Si vous n'aimez aucune de ces façons, envisagez d'utiliser (en fonction de l'original Exception) au moins une exception.

 17
Author: Mariano, 2017-05-23 12:26:14

Je suggère d'utiliser la classe Google Guava Throwables

propager(Throwable throwable)

Propage throwable tel quel si c'est un instance de RuntimeException ou Error, ou bien en dernier recours, wraps il dans une RuntimeException puis se propage.**

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

MISE À JOUR:

Maintenant qu'il est obsolète, utilisez:

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    });
}
 11
Author: yanefedor, 2020-06-20 09:12:55

Vous pouvez envelopper et déballer les exceptions de cette façon.

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);
    }
}
 10
Author: aalku, 2014-05-13 15:48:25

Vous pouvez effectuer l'une des opérations suivantes:

  • propager l'exception vérifiée,
  • enveloppez - le et propagez l'exception non cochée, ou
  • attrape l'exception et arrête la propagation.

Plusieurs bibliothèques permet de le faire facilement. L'exemple ci-dessous est écrit en utilisant ma bibliothèque NoException.

// 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)));
 10
Author: Robert Važan, 2017-06-16 03:56:36

Manière plus lisible:

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

Il suffit de le cacher dans un RuntimeException pour le dépasser forEach()

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

Bien qu'à ce stade, je ne m'opposerai pas à quelqu'un s'il dit ignorer les flux et aller avec une boucle for, à moins que:

  • vous ne créez pas votre flux en utilisant Collection.stream(), c'est-à-dire pas de traduction directe en une boucle for.
  • vous essayez d'utiliser parallelstream()
 3
Author: Kashyap, 2018-03-25 01:39:52