Why is it possible initialize java.util.function.Consumer with lambda that returns value? [duplicate] - java-8

I am confused by the following code
class LambdaTest {
public static void main(String[] args) {
Consumer<String> lambda1 = s -> {};
Function<String, String> lambda2 = s -> s;
Consumer<String> lambda3 = LambdaTest::consume; // but s -> s doesn't work!
Function<String, String> lambda4 = LambdaTest::consume;
}
static String consume(String s) { return s;}
}
I would have expected the assignment of lambda3 to fail as my consume method does not match the accept method in the Consumer Interface - the return types are different, String vs. void.
Moreover, I always thought that there is a one-to-one relationship between Lambda expressions and method references but this is clearly not the case as my example shows.
Could somebody explain to me what is happening here?

As Brian Goetz pointed out in a comment, the basis for the design decision was to allow adapting a method to a functional interface the same way you can call the method, i.e. you can call every value returning method and ignore the returned value.
When it comes to lambda expressions, things get a bit more complicated. There are two forms of lambda expressions, (args) -> expression and (args) -> { statements* }.
Whether the second form is void compatible, depends on the question whether no code path attempts to return a value, e.g. () -> { return ""; } is not void compatible, but expression compatible, whereas () -> {} or () -> { return; } are void compatible. Note that () -> { for(;;); } and () -> { throw new RuntimeException(); } are both, void compatible and value compatible, as they don’t complete normally and there’s no return statement.
The form (arg) -> expression is value compatible if the expression evaluates to a value. But there are also expressions, which are statements at the same time. These expressions may have a side effect and therefore can be written as stand-alone statement for producing the side effect only, ignoring the produced result. Similarly, the form (arg) -> expression can be void compatible, if the expression is also a statement.
An expression of the form s -> s can’t be void compatible as s is not a statement, i.e. you can’t write s -> { s; } either. On the other hand s -> s.toString() can be void compatible, because method invocations are statements. Similarly, s -> i++ can be void compatible as increments can be used as a statement, so s -> { i++; } is valid too. Of course, i has to be a field for this to work, not a local variable.
The Java Language Specification §14.8. Expression Statements lists all expressions which may be used as statements. Besides the already mentioned method invocations and increment/ decrement operators, it names assignments and class instance creation expressions, so s -> foo=s and s -> new WhatEver(s) are void compatible too.
As a side note, the form (arg) -> methodReturningVoid(arg) is the only expression form that is not value compatible.

consume(String) method matches Consumer<String> interface, because it consumes a String - the fact that it returns a value is irrelevant, as - in this case - it is simply ignored. (Because the Consumer interface does not expect any return value at all).
It must have been a design choice and basically a utility: imagine how many methods would have to be refactored or duplicated to match needs of functional interfaces like Consumer or even the very common Runnable. (Note that you can pass any method that consumes no parameters as a Runnable to an Executor, for example.)
Even methods like java.util.List#add(Object) return a value: boolean. Being unable to pass such method references just because that they return something (that is mostly irrelevant in many cases) would be rather annoying.

Related

Method Reference - passing Function to method with Consumer argument

I'm learning about Method References from Java 8 and I have difficulties understanding why does this work?
class Holder {
private String holded;
public Holder(String holded) {
this.holded = holded;
}
public String getHolded() {
return holded;
}
}
private void run() {
Function<Holder, String> getHolded = Holder::getHolded;
consume(Holder::getHolded); //This is correct...
consume(getHolded); //...but this is not
}
private void consume(Consumer<Holder> consumer) {
consumer.accept(null);
}
As you can see in run method - Holder::getHolded returns unbound method reference which you can invoke by passing object of type Holder as an argument. Like this: getHolded.apply(holder)
But why it casts this unbound method reference to Consumer when it is invoked directly as an method argument, and it does not doing it when I'm passing Function explicitly?
Two things here, lambda expressions are poly expressions - they are inferred by the compiler using their context (like generics for example).
When you declare consume(Holder::getHolded);, compiler (under the so-called special void compatibility rule) will infer it to Consumer<Holder>.
And this might not look obvious, but think of a simplified example. It is generally more than ok do call a method and discard it's return type, right? For example:
List<Integer> list = new ArrayList<>();
list.add(1);
Even if list.add(1) returns a boolean, we don't care about it.
Thus your example that works can be simplified to:
consume(x -> {
x.getHolded(); // ignore the result here
return;
});
So these are both possible and valid declarations:
Consumer<Holder> consumer = Holder::getHolded;
Function<Holder, String> function = Holder::getHolded;
But in this case we are explicitly telling what type is Holder::getHolded,, it's not the compiler inferring, thus consume(getHolded); fails, a Consumer != Function after all.
Java 8 introduced 4 important "function shapes" in the package java.util.function.
Consumer -> accepts a method reference (or a lambda expression) that takes one argument but doesn't return anything
Supplier -> accepts a method reference (or a lambda expression) that takes no argument and returns an object.
Function -> accepts a method reference (or a lambda expression) that takes one argument and returns an object.
Predicate -> accepts a method reference (or a lambda expression) that takes one argument and returns a boolean.
Read the Java docs for more detail.
To answer your question on why the first one works but the second one errors out, read following:
The second statement
consume(getHolded);
doesn't work because the type of the argument getHolded is Function<Holder, String> whereas the consume method expects an argument of type Consumer<Holder>. Since there is no parent-child relationship between Function and Consumer, it requires an explicit cast without which the compiler rightly errors out.
The first statement
consume(Holder::getHolded);
works because the method getHolded is declared as public String getHolded() meaning that it doesn't take any argument and returns a String. As per the new void compatibility rule, void types are inferred as the class containing the referenced method. Consider the following statement:
Consumer<Holder> consumer = Holder::getHolded;
This is a valid statement even though the method getHolded doesn't accept any arguments. This is allowed to facilitate inferring void types. Yet another example is the one you have mentioned yourself:
Function<Holder, String> getHolded = Holder::getHolded;
This is also a valid statement where you have said that the function object getHolded is a Function that returns String and accepts a type Holder even though the assigned method reference doesn't take any argument.
Sharing just a summary of the four types of Method References under the hood:
Reference to a static method:
Type::staticMethod ===>>> x -> Type.staticMethod(x)
Reference to an instance method of a particular object:
instance::instanceMethod ===>>> x -> instance.instanceMethod(x)
Reference to an Instance Method of an Arbitrary Object of a Particular Type:
Type::instanceMethod ===>>> x -> x.instanceMethod() OR (x, y) -> x.instanceMethod(y)
Reference to a constructor:
Type::new ===> x -> new Type(x)

How to get that the limit exceeded when I use limit() on a range of items from stream using Java 8 lambda?

How should I know without using another condition to compare the map.size() with limitValue, that the limit was exceeding when my stream iterated?
Here,
for limitValue = 3, it should return false.
for limitValue = 4, it should return true.
I can not use an outside int field as it must be final to be used inside lambda.
import java.util.*;
import java.util.stream.*;
public class Test {
public static void main(String[] args) throws Exception {
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(2, "bar");
map.put(3, "baz");
int limitValue = 3;
String result = map.entrySet()
.stream()
.limit(limitValue)
.map(entry -> entry.getKey() + " - " + entry.getValue())
.collect(Collectors.joining(", "));
System.out.println(result);
}
}
I can not use an outside int field as it must be final to be used
inside lambda.
Yes, this is because, within a lambda expression, you can only reference local variables whose value doesn’t change (in java).
This is a good thing in a way as mutating a variable(s) inside a lambda is not thread safe when executing in parallel.
So, the system is helping you prevent such scenarios at compile time by allowing only final or effectively final variables to be used in lambdas.
Note, this restriction only holds for local variables.
Anyhow, my advice is not to mutate variables that are not solely contained within a given function itself as it introduces a side-effect and side-effects in behavioral parameters to stream operations are, in general, discouraged.
Keep things simple and proceed with the below approach.
boolean exceeded = limitValue > map.size();

Java 8 - Static Method Reference Rule

I have the following piece of code:
public class Chap20 {
public static void main(String[] args) {
String[] names = { "John", "Jane" };
Stream<String> namesStream = Stream.of(names);
Path path = Paths.get(".");
Stream<Path> files;
try {
files = Files.list(path);
files.forEach(System.out::println);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now here´s the file.forEach method signature:
void java.util.stream.Stream.forEach(Consumer<? super Path> action)
I´m reading it as a method that accepts a consumer of a type which is at least a Path type or a superclass of Path, but I´m probably missreading it, since System.out is not a superclass of Path.
Can someone please explain how to correct read it?
? super Path says: 'It has to be a super class of Path.
System.out.println accepts an Object. Object is a super class of Path hence this is correct.
You are reading that entirely correct IMO, you are just mislead by the :: notation probably. And it's not about System.out being a Path or not - it's about the implied parameter x (for example) that you can't see because of the method reference (read further).
There are a couple of things here, first one is called PECS; that is why the declaration is ? super P_OUT or ? super Path. Basically that means you can read any super type of Path. The only safe one would be Object (or any sub type of that, but you just don't know which exactly).
To make it simpler, you can write it like this for example:
Stream.of("John", "Jane")
.forEach((Object x) -> System.out.println(x)); // Object
Or since the compiler can see (infer) the type to be String :
Stream.of("John", "Jane")
.forEach((String x) -> System.out.println(x)); // String
Or you can omit that declaration at all and let the compiler do it's job:
Stream.of("John", "Jane")
.forEach(/* this is infered as String here */ x -> System.out.println(x));
Now the second part is called a Method Reference.
Instead of writing:
Stream.of("John", "Jane")
.forEach(x -> System.out.println(x));
You could write it simpler:
Stream.of("John", "Jane")
.forEach(System.out::println);
The x parameter (which is of type ? super T) is implied here.
The method signature indicates the forEach method of Stream takes a Consumer, which consumes each element from the Stream upon which it is iterating, in your case a collection of Paths.
Consumer refers to a functional interface that accepts an input and returns no result. It is one of many implemented in Java 8 to work with Lambdas and method references. A functional interface contains exactly one abstract method, also called its functional method.
The forEach method is used for iterating over a collection and applying an operation on each element. The operation, or "behavior" (any class implementing the Consumer interface), that's passed is the action, or lambda, performed on each element of the collection.
The forEach is an API (also added with Java 8) in the Iterable interface, which "performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception". It differs from the Java for loop in that it is an internal iterator, rather than an external one.

Convert for loop into Java 8 Stream

I need to convert these code into Java 8 Stream I tried it using the given below code written by me but still I haven't got what I wanted.
//contractList is list of Contract class
//contract.getProgramId() returns String
//contract.getEnrollmentID() returns String
//'usage = CommonUtils.getUsageType()' is other service to call wich returns String
//enroll and usage are String type
//enrollNoWithUsageTypeJson is json object '{"enroll": value, "usage": value}'
//usages is List<JSONObject> where enrollNoWithUsageTypeJson need to add
for (Contract contract : contractList) {
if (!StringUtils.isEmpty(contract.getProgramId())) {
enroll = contract.getEnrollmentID();
usage = CommonUtils.getUsageType(envProperty, contract.getProgramId());
if (!(StringUtils.isEmpty(enroll) || StringUtils.isEmpty(usage))) {
enrollNoWithUsageTypeJson.put("enroll", enroll);
enrollNoWithUsageTypeJson.put("usage", usage);
usages.add(enrollNoWithUsageTypeJson);
}
}
}
This is till now what I have got:
contractList.stream()
.filter(contract -> !StringUtils.isEmpty(contract) &&
!StringUtils.isEmpty(contract.getProgramId()))
.collect(Collectors.to);
Thakyou in advance :)
Here is how a stream based version of your code might look like (add static imports as needed):
List<JSONObject> usages = contractList.stream()
.filter(c -> isNotEmpty(c.getProgramId()))
.map(c -> new SimpleEntry<>(c.getEnrollmentID(), getUsageType(envProperty, c.getProgramId())))
.filter(e -> isNotEmpty(e.getKey()) && isNotEmpty(e.getValue())))
.map(e -> {
enrollNoWithUsageTypeJson.put("enroll", e.getKey());
enrollNoWithUsageTypeJson.put("usage", e.getValue());
return enrollNoWithUsageTypeJson; })
.collect(toList());
I took the liberty of using isNotEmpty from Apache Commons as given this option !isEmpty looks terrible. I am (ab)using AbstractMap.SimpleEntry to hold a pair of values. If you feel getKey, getValue make the code less readable, you can introduce a class to hold these 2 variables. E.g.:
class EnrollUsage {
String enroll, usage;
}
You may also prefer to define a method:
JSONObject withEnrollAndUsage(JSONObject json, String enroll, String usage) {
json.put("enroll", enroll);
json.put("usage", usage);
return json;
}
and in the above use instead:
.map(e -> withEnrollAndUsage(enrollNoWithUsageTypeJson, e.getKey(), e.getValue()))
Keep in mind that you never really "need" to convert code to use streams. There are cases where using streams, albeit intellectually satisfying, actually complicates your code. Exercise your best judgement in this case.

Type of method reference and lambda in Java 8

I'm wondering why methods references and lambdas are not recognized as a Function. Why I need to write
Function<Integer, Integer> fun1 = i -> i+2;
Function<Integer, Integer> fun2 = i -> i*i;
fun1.compose(fun2).apply(4);
instead of
((Integer i) -> i*2).compose((Integer i) -> i+2).apply(4)
Lambda expressions have no intrinsic type; the following is an error:
Object lambda = x -> x;
Lambda expressions are poly expressions, which are expressions whose type is dependent on their context. In particular, a lambda expression derives its type from its target type, which must be a functional interface -- an interface with a single (non-Object) abstract method. The same lambda expression could have multiple types, depending on its target type:
Predicate<String> isEmpty = s -> s.isEmpty();
Function<String, Boolean> isEmpty = s -> s.isEmpty();
The interface Function is not part of the language, nor does it have any magic properties; it is merely an ordinary functional interface, just like Runnable or Predicate or Comparable. There's no reason the compiler could guess that you meant the lambda to target Function rather than some other type.
Further, you don't need to be a lambda to implement Function; you could be a named class or an anonymous class. Lambdas (and method refs) are a syntactically compact means of specifying instances of functional interfaces.

Resources