Search code examples
javaexceptionjava-8java-streamtry-catch

Why Java streams are not able to handle exception even after surrounding with a try-catch block?


I have the following piece of code with Java streams

Problematic code

You can see that I am having an error on the 4th line. Basically the error says "Unhandled Exception: AddressException". But you can see that I am catching it within a catch block. But still that is not working. Even though, if I use a try catch block within the map method it works as shown below:

public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails){
     List<InternetAddress> internetAddresses = new ArrayList<>();
          internetAddresses = toEmails.stream().map(a->{
              InternetAddress ia = null;
              try{
                 ia = new InternetAddress(a);
              } catch (AddressException e) {
                  
              }
              return ia;
          }).collect(Collectors.toList());
      return internetAddresses;
}

Does anyone know why this behaviour and if knows please give some insights to that. One more quetion, will the anonymous inner class also behave the same?


Solution

  • Error is shown because you provided method with different signature (additional thows clause). You have to provide implementation that is compatible with java.util.function.Function#apply signature

    R apply(T var1);
    

    There is several ways to deal with your problem:

    • anonymous function with try-catch
        public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
            return toEmails.stream().map(new Function<String, InternetAddress>() {
                @Override
                public InternetAddress apply(String email) {
                    try {
                        return new InternetAddress(email);
                    } catch (AddressException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            }).collect(Collectors.toList());
        }
    
    • try-catch in lambda
        public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
            return toEmails.stream().map(email -> {
                try {
                    return new InternetAddress(email);
                } catch (AddressException e) {
                    e.printStackTrace();
                }
                return null;
            }).collect(Collectors.toList());
        }
    
    • extracted handling method
        public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
            return toEmails.stream().map(this::createInternetAddress).collect(Collectors.toList());
        }
    
        private InternetAddress createInternetAddress(String email) {
            try {
                return  new InternetAddress(email);
            } catch (AddressException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    • generalized extracted handling method
    @FunctionalInterface
    public interface FunctionThrowing <T, R, E extends Exception> {
        R apply(T var1) throws E;
    
        static <T, R, E extends Exception> Function<T, R> handled(FunctionThrowing<T, R, E> ft) {
            return result -> {
                try {
                    return ft.apply(result);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            };
        }
    }
    
        public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
            List<InternetAddress> internetAddresses = new ArrayList<>();
            internetAddresses = toEmails.stream().map(FunctionThrowing.handled(InternetAddress::new)).collect(Collectors.toList());
            return internetAddresses;
        }