Okan Menevşeoğlu
Okan Menevşeoğlu

Reputation: 31

Java 11 Local-Variable Type Inference Improvement Usage

I am trying to make a use case for the Java 11 extension on var keyword for lambda expressions. The examples I could find online are always related to @NonNull annotation. However when I want to do something like this:

long count = Stream.of(-3, -2, -1, 0, 1, 2, 3, 4)
            .filter((@NegativeOrZero var a) ->  a > -3)
            .count();

System.out.println(count);

I get:

7

I expect to count only -2, -1 and 0 and not count others, or throw an error or something. Same goes for the following:

long count = Stream.of(1, 2, 3, 4, 5, null, 7, 8, 9)
            .filter((@NotNull(message="It is a null!!") var a) ->  a > 5)
            .count();

 System.out.println(count);

I get an NPE without any custom message unless I change a > 5 to a != null && a > 5 which is not related to annotation.

Can someone explain what am I missing here?

Edit: Maybe I forgot to mention but can you provide an example with var keyword and validations combined to understand its benefits?

Edit 2: I found a more simple example that is supposed to throw an error. However, for me, it returns true. I am using JDK 13 btw.

Predicate<String> predicate = (@NotNull var a) -> true;
System.out.println(predicate.test(null));

Upvotes: 3

Views: 1008

Answers (2)

Mikhail Kholodkov
Mikhail Kholodkov

Reputation: 25176

One of the possible use cases to pre-filter null values with Local-Variable Syntax for Lambda Parameters can be done by using JetBrains annotations.

https://mvnrepository.com/artifact/org.jetbrains/annotations/18.0.0

import org.jetbrains.annotations.NotNull;

...

public static void main(String[] args) {
    long cnt = Stream.of(2, 4, 6, 8, 10, null, 1)
            .filter((@NotNull var i) -> i > 5)
            .count();

    System.out.println(cnt);
}

Will yield IllgalArgumentException instead of NullPointerException at runtime:

Exception in thread "main" java.lang.IllegalArgumentException: Argument for @NotNull parameter 'i' of com/app/App.lambda$main$0 must not be null
    at com.app.App.$$$reportNull$$$0(App.java)
    at com.app.App.lambda$main$0(App.java)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)

As said at this time javax.constraint.* annotations won't be automagically performed as a validation against the lambda parameter. With time, I'm sure, more and more libraries, such as static code analyzers or compile time checker tools, will leverage http://openjdk.java.net/jeps/323 feature and will support that.

Upvotes: 1

Karol Dowbecki
Karol Dowbecki

Reputation: 44970

java.util.stream classes are not in any way related to javax.validation so the stream won't understand or process @NotNull or @NegativeOrZero. When you annotate type you only provide the metadata. Something has to process this metadata to create the desired behavior, and stream does not.

Your examples are evaluated as:

Stream.of(-3, -2, -1, 0, 1, 2, 3, 4)
      .filter((var a) -> a > -3)
      .count(); // 7 as only -3 is filtered out
Stream.of(1, 2, 3, 4, 5, null, 7, 8, 9)
      .filter((var a) -> a > 5) // NPE on boxing null
      .count(); 

Upvotes: 2

Related Questions