简体   繁体   中英

How do I return a value from a lambda within the method I want to return on?

How do I return a value from a lambda within the method I want to return on?

Originally, I had this:

myCollection.forEach(item -> {
  try {
    doSomething(item);
  } catch (Exception e) {
    return "There was a problem doing something: " + e.getMessage();
  }
});

But my intent was to return on the method containing all this code, not return on just the lambda. So, I ended up having to do this:

String error = "";
myCollection.stream().filter(item -> {
  try {
    doSomething(item);
    return true;
  } catch (Exception e) {
    error = "There was a problem doing something: " + e.getMessage();
  }
  return false;
});
if (!error.isEmpty()) {
  return error;
}

But this can't be the best way. What's the Java 8 functional, elegant way to do this?

Anything thrown from inside of the stream can be caught with a try clause surrounding the stream.

try {
    myCollection.forEach(SurroundingClass::doSomething);
} catch (Exception e) {
    return "..."
}

However, I do not recommend using exceptions as a way of flow control. Throwing and catching exceptions are slow. You should always check whether your data will produce an exception or not before passing it to doSomething if you can.

If you are talking about checked exceptions, there is no easy way to handle them. Check out this post if you want to know about some (pretty lengthy) workarounds.

Maybe something like this, I haven't tested.

   myCollection.stream().map(item -> {
      try {
        doSomething(item);
        return null;
      } catch (Exception e) {
        return "There was a problem doing something: " + e.getMessage();
      }
    }).filter(exp -> exp!=null).findFirst();

Do you really need to use a Lambda here? The best Java way would be just use 1.5 for-each on the collection:

try {
  for (final E item : myCollection) {
     doSomething(item)
  }
} catch (final Exception ex) {
  return "blah";
}

Notice that one pays a performance penalty when entering and exiting the try-catch block so is better to have it outside the loop.

Handling of checked exceptions in lambdas can be achieved in following way

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

    private static <T> Consumer<T> wrap(ThrowingConsumer<T, Exception> throwingConsumer) {
        return item -> {
            try {
                throwingConsumer.accept(item);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    private String processCollection(List</* whatever type */> myCollection) {
        try {
            myCollection.forEach(wrap(this::doSomething));
        } catch (Exception e) {
            return e.getMessage(); // error
        }
        return null; // no error
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM