Home » Java » What's the right way to check null or check exceptions in a chained statement in Java 8?

What's the right way to check null or check exceptions in a chained statement in Java 8?

Posted by: admin December 28, 2021 Leave a comment

Questions:

For example for this code:

List<Class> classes = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
              .map(className -> Class.forName(className))
              .collect(Collectors.toList());

This code runs fine now. but, assume we have a empty list in stream and we have tons of operations to the stream. It could get NullPointer exceptions and etc.
I find it’s also hard to try-catch for this kind of statement.
What’s the right way to handle exception for this?

Answers:

You do not need to check for nulls. If you have an empty stream all operations will be skipped:

Stream.of("hello")
      .filter(e => "world".equals(e)) // empties the stream
      .foreach(System.out::println); // no NullPointer, no output

Exception handling is possible in mapper:

    List<Class<?>> classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
            .map(className -> {
                try {
                    return Class.forName(className);
                } catch (Exception e) {
                    throw new YourRuntimeException();
                }
            })
            .collect(Collectors.toList());

If you want exceptions to be ignored, then I suggest to map to Optionals.

    List<Class<?>> classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
            .map(className -> {
                try {
                    return Optional.of(Class.forName(className));
                } catch (Exception e) {
                    return Optional.<Class<?>>empty();
                }
            })
            .filter(Optional::isPresent) // ignore empty values
            .map (Optional::get) // unwrap Optional contents
            .collect(Collectors.toList());

Please also have a look at How can I throw CHECKED exceptions from inside Java 8 streams? for a more detailed discussion about Class.forName in combination with java 8 streams.

###

Your question is a bit strange. You are claiming “This code runs fine now” whereas it should generate compile-time errors as you are not handling the checked exception declared by Class.forName. Further you are talking about empty lists, but in your code, no lists are involved. The same applies to your reference to NullPointerException as your code does not produce null at any place.

Most probably, you are talking about a code which catches the ClassNotFoundException and handles it by returning null. You should never do this. If you want to filter out failures, you may do it this way:

List<Class<?>> classes = 
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
        .flatMap(className -> {
                try {
                    return Stream.of(Class.forName(className));
                } catch (ClassNotFoundException ex) {
                    // recommended: insert logging statement here
                    return Stream.empty();
                }
            })
        .collect(Collectors.toList());

This way, no element will be generated in the case of an exception and you don’t have to do additional error handling downstream.