Is it possible to pass BiFunction references to methods that expect a functional interface?

I always used only Java 6 and now I'm trying to find out what's new in Java 8. I read this article here: http://www.drdobbs.com/jvm/lambda-expressions-in-java-8/240166764? PGNO = 2

And it says:

The Java API defines several generic functional interfaces in the java.util.function package. One of the interfaces, BiFunction, describes functions with parameter types T and U and return type R. You can save the string comparison lambda in a variable of this type:

BiFunction<String, String, Integer> comp = (first, second) -> Integer.compare(first.length(), second.length()); 

However, this does not help you in sorting. There is no Arrays.sort method that BiFunction wants. If you used a functional programming language before, this may seem interesting to you. But for Java programmers, this is quite natural. An interface, such as Comparator, has a specific purpose, not just a method with a given parameter and return types. Java 8 retains this flavor. When you want to do something with lambda expressions, you still need to remember the purpose of the expression and have a specific functional interface for this.

However, when I see this thread: How do you assign a lambda variable in Java 8?

The answers to this question suggest doing exactly what the paragraph above says that you cannot do.

So, is the information in the article incorrect, or am I reading something wrong here?

Thanks!

+7
source share
3 answers

I don't see anything in the SO related answer, which contradicts the article.

Common type system rules apply to a functional interface .

If you declare a variable as BiFunction<String,String,Integer> bifunc , you are not allowed to pass it to a method that requires a Comparator<String> since BiFunction<String,String,Integer> not a subtype of Comparator<String>

The fact that functional types follow all the usual rules has allowed us to add this new functionality with minimal perturbations.

And if you want to make a Comparator from BiFunction all you have to do is add ::apply like this:

 BiFunction<String,String,Integer> bifunc = (a,b) -> Integer.compare(a.length(), b.length()); Arrays.sort(array, bifunc::apply); 
+20
source

The article is true in the sense that you cannot sort based on an object of type BiFunction , but you can always use Comparator . But hey, they both can have the same body. For instance:

 private static void sort(Comparator<String> ls){ Arrays.sort(someArray, ls); } Comparator<String> comp = (String f1, String f2) -> Integer.compare(f1.length(), f2.length()); sort(comp); BiFunction<String, String, Integer> func = (String f1, String f2) -> Integer.compare(f1.length(), f2.length()); sort((String f1, String f2) -> Integer.compare(f1.length(), f2.length())); //line-4 sort(func) // compiler error 

On line 4, you can pass in a lambda that is exactly the same as func . But you still cannot go through func to sort . Lambdas in java8 is an implementation of some FunctionalInterface . Functional interfaces get their type based on its reference type. The way the same lambda during initialization can be either BiFunction or Comparator .

But once the lambda is built and it gets its type, then you cannot change it. Therefore, you cannot pass a func type BiFunction to the sort that Comparator expects

+3
source

The article is correct. You cannot appoint, for example. a BiFunction to a Comparator .

With that said, a great article written by Brian Goetz perfectly explains the problem.

When the compiler encounters a lambda expression, it first drops (desugars) the lambda body into a method whose argument list and return type match the lambda expression

So lambda can be removed - but what does that mean? Well, basically this means that a new method will be created (possibly) that somehow corresponds to lamdba.

 class A { public void foo() { List<String> list = ... list.forEach( s -> { System.out.println(s); } ); } } 

The code above will be hidden something like this:

 class A { public void foo() { List<String> list = ... list.forEach( [lambda for lambda$1 as Consumer] ); } static void lambda$1(String s) { System.out.println(s); } } 

So, in the case of BiFunction and Comparator . The provided lambda can be assigned to both:

 // Assign the lambda to a BiFunction BiFunction<String, String, Integer> b1 = (first, second) -> Integer.compare(first.length(), second.length()); // Assign the lambda to a Comparator Comparator<String> c1 = (first, second) -> Integer.compare(first.length(), second.length()); // But, once the lambda has been assigned to a type you can not reassign it BiFunction<String, String, Integer> b2 = c1; // <-- Error 

Note that once a lambda is assigned to a type ( BiFunction or Comparator ), it cannot be reassigned even if the lambda expression matches.

+2
source

Source: https://habr.com/ru/post/982014/


All Articles