Method Reference - passing Function to method with Consumer argument - java-8

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)

Related

method reference getting error : Ambiguous, both 'multiply(BigDecimal)' and 'multiply(BigDecimal, MathContext)' match [duplicate]

Questions:
What are raw types in Java, and why do I often hear that they shouldn't be used in new code?
What is the alternative if we can't use raw types, and how is it better?
What is a raw type?
The Java Language Specification defines a raw type as follows:
JLS 4.8 Raw Types
A raw type is defined to be one of:
The reference type that is formed by taking the name of a generic type declaration without an accompanying type argument list.
An array type whose element type is a raw type.
A non-static member type of a raw type R that is not inherited from a superclass or superinterface of R.
Here's an example to illustrate:
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] args) {
MyType mt; // warning: MyType is a raw type
MyType.Inner inn; // warning: MyType.Inner is a raw type
MyType.Nested nest; // no warning: not parameterized type
MyType<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
Here, MyType<E> is a parameterized type (JLS 4.5). It is common to colloquially refer to this type as simply MyType for short, but technically the name is MyType<E>.
mt has a raw type (and generates a compilation warning) by the first bullet point in the above definition; inn also has a raw type by the third bullet point.
MyType.Nested is not a parameterized type, even though it's a member type of a parameterized type MyType<E>, because it's static.
mt1, and mt2 are both declared with actual type parameters, so they're not raw types.
What's so special about raw types?
Essentially, raw types behaves just like they were before generics were introduced. That is, the following is entirely legal at compile-time.
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
The above code runs just fine, but suppose you also have the following:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
Now we run into trouble at run-time, because names contains something that isn't an instanceof String.
Presumably, if you want names to contain only String, you could perhaps still use a raw type and manually check every add yourself, and then manually cast to String every item from names. Even better, though is NOT to use a raw type and let the compiler do all the work for you, harnessing the power of Java generics.
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Of course, if you DO want names to allow a Boolean, then you can declare it as List<Object> names, and the above code would compile.
See also
Java Tutorials/Generics
How's a raw type different from using <Object> as type parameters?
The following is a quote from Effective Java 2nd Edition, Item 23: Don't use raw types in new code:
Just what is the difference between the raw type List and the parameterized type List<Object>? Loosely speaking, the former has opted out generic type checking, while the latter explicitly told the compiler that it is capable of holding objects of any type. While you can pass a List<String> to a parameter of type List, you can't pass it to a parameter of type List<Object>. There are subtyping rules for generics, and List<String> is a subtype of the raw type List, but not of the parameterized type List<Object>. As a consequence, you lose type safety if you use raw type like List, but not if you use a parameterized type like List<Object>.
To illustrate the point, consider the following method which takes a List<Object> and appends a new Object().
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Generics in Java are invariant. A List<String> is not a List<Object>, so the following would generate a compiler warning:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
If you had declared appendNewObject to take a raw type List as parameter, then this would compile, and you'd therefore lose the type safety that you get from generics.
See also
What is the difference between <E extends Number> and <Number>?
java generics (not) covariance
How's a raw type different from using <?> as a type parameter?
List<Object>, List<String>, etc are all List<?>, so it may be tempting to just say that they're just List instead. However, there is a major difference: since a List<E> defines only add(E), you can't add just any arbitrary object to a List<?>. On the other hand, since the raw type List does not have type safety, you can add just about anything to a List.
Consider the following variation of the previous snippet:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
The compiler did a wonderful job of protecting you from potentially violating the type invariance of the List<?>! If you had declared the parameter as the raw type List list, then the code would compile, and you'd violate the type invariant of List<String> names.
A raw type is the erasure of that type
Back to JLS 4.8:
It is possible to use as a type the erasure of a parameterized type or the erasure of an array type whose element type is a parameterized type. Such a type is called a raw type.
[...]
The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of the parameterizations of the generic type.
The type of a constructor, instance method, or non-static field of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.
In simpler terms, when a raw type is used, the constructors, instance methods and non-static fields are also erased.
Take the following example:
class MyType<E> {
List<String> getNames() {
return Arrays.asList("John", "Mary");
}
public static void main(String[] args) {
MyType rawType = new MyType();
// unchecked warning!
// required: List<String> found: List
List<String> names = rawType.getNames();
// compilation error!
// incompatible types: Object cannot be converted to String
for (String str : rawType.getNames())
System.out.print(str);
}
}
When we use the raw MyType, getNames becomes erased as well, so that it returns a raw List!
JLS 4.6 continues to explain the following:
Type erasure also maps the signature of a constructor or method to a signature that has no parameterized types or type variables. The erasure of a constructor or method signature s is a signature consisting of the same name as s and the erasures of all the formal parameter types given in s.
The return type of a method and the type parameters of a generic method or constructor also undergo erasure if the method or constructor's signature is erased.
The erasure of the signature of a generic method has no type parameters.
The following bug report contains some thoughts from Maurizio Cimadamore, a compiler dev, and Alex Buckley, one of the authors of the JLS, on why this sort of behavior ought to occur: https://bugs.openjdk.java.net/browse/JDK-6400189. (In short, it makes the specification simpler.)
If it's unsafe, why is it allowed to use a raw type?
Here's another quote from JLS 4.8:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.
Effective Java 2nd Edition also has this to add:
Given that you shouldn't use raw types, why did the language designers allow them? To provide compatibility.
The Java platform was about to enter its second decade when generics were introduced, and there was an enormous amount of Java code in existence that did not use generics. It was deemed critical that all this code remains legal and interoperable with new code that does use generics. It had to be legal to pass instances of parameterized types to methods that were designed for use with ordinary types, and vice versa. This requirement, known as migration compatibility, drove the decision to support raw types.
In summary, raw types should NEVER be used in new code. You should always use parameterized types.
Are there no exceptions?
Unfortunately, because Java generics are non-reified, there are two exceptions where raw types must be used in new code:
Class literals, e.g. List.class, not List<String>.class
instanceof operand, e.g. o instanceof Set, not o instanceof Set<String>
See also
Why is Collection<String>.class Illegal?
What are raw types in Java, and why do I often hear that they shouldn't be used in new code?
Raw-types are ancient history of the Java language. In the beginning there were Collections and they held Objects nothing more and nothing less. Every operation on Collections required casts from Object to the desired type.
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
While this worked most of the time, errors did happen
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
The old typeless collections could not enforce type-safety so the programmer had to remember what he stored within a collection.
Generics where invented to get around this limitation, the developer would declare the stored type once and the compiler would do it instead.
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
For Comparison:
// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings
More complex the Compareable interface:
//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
int id;
public int compareTo(Object other)
{return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
int id;
public int compareTo(MyCompareAble other)
{return this.id - other.id;}
}
Note that it is impossible to implement the CompareAble interface with compareTo(MyCompareAble) with raw types.
Why you should not use them:
Any Object stored in a Collection has to be cast before it can be used
Using generics enables compile time checks
Using raw types is the same as storing each value as Object
What the compiler does:
Generics are backward compatible, they use the same java classes as the raw types do. The magic happens mostly at compile time.
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
Will be compiled as:
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
This is the same code you would write if you used the raw types directly. Thought I'm not sure what happens with the CompareAble interface, I guess that it creates two compareTo functions, one taking a MyCompareAble and the other taking an Object and passing it to the first after casting it.
What are the alternatives to raw types: Use generics
A raw type is the name of a generic class or interface without any type arguments. For example, given the generic Box class:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
To create a parameterized type of Box<T>, you supply an actual type argument for the formal type parameter T:
Box<Integer> intBox = new Box<>();
If the actual type argument is omitted, you create a raw type of Box<T>:
Box rawBox = new Box();
Therefore, Box is the raw type of the generic type Box<T>. However, a non-generic class or interface type is not a raw type.
Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. When using raw types, you essentially get pre-generics behavior — a Box gives you Objects. For backward compatibility, assigning a parameterized type to its raw type is allowed:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
But if you assign a raw type to a parameterized type, you get a warning:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
You also get a warning if you use a raw type to invoke generic methods defined in the corresponding generic type:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
The warning shows that raw types bypass generic type checks, deferring the catch of unsafe code to runtime. Therefore, you should avoid using raw types.
The Type Erasure section has more information on how the Java compiler uses raw types.
Unchecked Error Messages
As mentioned previously, when mixing legacy code with generic code, you may encounter warning messages similar to the following:
Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
This can happen when using an older API that operates on raw types, as shown in the following example:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
The term "unchecked" means that the compiler does not have enough type information to perform all type checks necessary to ensure type safety. The "unchecked" warning is disabled, by default, though the compiler gives a hint. To see all "unchecked" warnings, recompile with -Xlint:unchecked.
Recompiling the previous example with -Xlint:unchecked reveals the following additional information:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
To completely disable unchecked warnings, use the -Xlint:-unchecked flag. The #SuppressWarnings("unchecked") annotation suppresses unchecked warnings. If you are unfamiliar with the #SuppressWarnings syntax, see Annotations.
Original source: Java Tutorials
A "raw" type in Java is a class which is non-generic and deals with "raw" Objects, rather than type-safe generic type parameters.
For example, before Java generics was available, you would use a collection class like this:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
When you add your object to the list, it doesn't care what type of object it is, and when you get it from the list, you have to explicitly cast it to the type you are expecting.
Using generics, you remove the "unknown" factor, because you must explicitly specify which type of objects can go in the list:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
Notice that with generics you don't have to cast the object coming from the get call, the collection is pre-defined to only work with MyObject. This very fact is the main driving factor for generics. It changes a source of runtime errors into something that can be checked at compile time.
private static List<String> list = new ArrayList<String>();
You should specify the type-parameter.
The warning advises that types that are defined to support generics should be parameterized, rather than using their raw form.
List is defined to support generics: public class List<E>. This allows many type-safe operations, that are checked compile-time.
What is a raw type and why do I often hear that they shouldn't be used in new code?
A "raw type" is the use of a generic class without specifying a type argument(s) for its parameterized type(s), e.g. using List instead of List<String>. When generics were introduced into Java, several classes were updated to use generics. Using these class as a "raw type" (without specifying a type argument) allowed legacy code to still compile.
"Raw types" are used for backwards compatibility. Their use in new code is not recommended because using the generic class with a type argument allows for stronger typing, which in turn may improve code understandability and lead to catching potential problems earlier.
What is the alternative if we can't use raw types, and how is it better?
The preferred alternative is to use generic classes as intended - with a suitable type argument (e.g. List<String>). This allows the programmer to specify types more specifically, conveys more meaning to future maintainers about the intended use of a variable or data structure, and it allows compiler to enforce better type-safety. These advantages together may improve code quality and help prevent the introduction of some coding errors.
For example, for a method where the programmer wants to ensure a List variable called 'names' contains only Strings:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
Here I am Considering multiple cases through which you can clearify the concept
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
Case 1
ArrayList<String> arr it is a ArrayList reference variable with type String which reference to a ArralyList Object of Type String. It means it can hold only String type Object.
It is a Strict to String not a Raw Type so, It will never raise an warning .
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23); //prone to compile time error.
//error: no suitable method found for add(int)
Case 2
In this case ArrayList<String> arr is a strict type but your Object new ArrayList(); is a raw type.
arr.add("hello"); //alone this compile but raise the warning.
arr.add(23); //again prone to compile time error.
//error: no suitable method found for add(int)
here arr is a Strict type. So, It will raise compile time error when adding a integer.
Warning :- A Raw Type Object is referenced to a Strict type Referenced Variable of ArrayList.
Case 3
In this case ArrayList arr is a raw type but your Object new ArrayList<String>(); is a Strict type.
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
It will add any type of Object into it because arr is a Raw Type.
Warning :- A Strict Type Object is referenced to a raw type referenced Variable.
The compiler wants you to write this:
private static List<String> list = new ArrayList<String>();
because otherwise, you could add any type you like into list, making the instantiation as new ArrayList<String>() pointless. Java generics are a compile-time feature only, so an object created with new ArrayList<String>() will happily accept Integer or JFrame elements if assigned to a reference of the "raw type" List - the object itself knows nothing about what types it's supposed to contain, only the compiler does.
Here's another case where raw types will bite you:
public class StrangeClass<T> {
#SuppressWarnings("unchecked")
public <X> X getSomethingElse() {
return (X)"Testing something else!";
}
public static void main(String[] args) {
final StrangeClass<String> withGeneric = new StrangeClass<>();
final StrangeClass withoutGeneric = new StrangeClass();
final String value1,
value2;
// Compiles
value1 = withGeneric.getSomethingElse();
// Produces compile error:
// incompatible types: java.lang.Object cannot be converted to java.lang.String
value2 = withoutGeneric.getSomethingElse();
}
}
This is counter-intuitive because you'd expect the raw type to only affect methods bound to the class type parameter, but it actually also affects generic methods with their own type parameters.
As was mentioned in the accepted answer, you lose all support for generics within the code of the raw type. Every type parameter is converted to its erasure (which in the above example is just Object).
A raw-type is the a lack of a type parameter when using a generic type.
Raw-type should not be used because it could cause runtime errors, like inserting a double into what was supposed to be a Set of ints.
Set set = new HashSet();
set.add(3.45); //ok
When retrieving the stuff from the Set, you don't know what is coming out. Let's assume that you expect it to be all ints, you are casting it to Integer; exception at runtime when the double 3.45 comes along.
With a type parameter added to your Set, you will get a compile error at once. This preemptive error lets you fix the problem before something blows up during runtime (thus saving on time and effort).
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
Avoid raw types.
Raw types refer to using a generic type without specifying a type parameter.
For example:
A list is a raw type, while List<String> is a parameterized type.
When generics were introduced in JDK 1.5, raw types were retained only to maintain backwards compatibility with older versions of Java.
Although using raw types is still possible, they should be avoided:
They usually require casts.
They aren't type safe, and some important kinds of errors will only appear at runtime.
They are less expressive, and don't self-document in the same way as parameterized types..
Example:
import java.util.*;
public final class AvoidRawTypes {
void withRawType() {
//Raw List doesn't self-document,
//doesn't state explicitly what it can contain
List stars = Arrays.asList("Arcturus", "Vega", "Altair");
Iterator iter = stars.iterator();
while (iter.hasNext()) {
String star = (String) iter.next(); //cast needed
log(star);
}
}
void withParameterizedType() {
List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
for (String star: stars) {
log(star);
}
}
private void log(Object message) {
System.out.println(Objects.toString(message));
}
}
For reference: https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
What is saying is that your list is a List of unespecified objects. That is that Java does not know what kind of objects are inside the list. Then when you want to iterate the list you have to cast every element, to be able to access the properties of that element (in this case, String).
In general is a better idea to parametrize the collections, so you don't have conversion problems, you will only be able to add elements of the parametrized type and your editor will offer you the appropiate methods to select.
private static List<String> list = new ArrayList<String>();
tutorial page.
A raw type is the name of a generic class or interface without any type arguments. For example, given the generic Box class:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
To create a parameterized type of Box, you supply an actual type argument for the formal type parameter T:
Box<Integer> intBox = new Box<>();
If the actual type argument is omitted, you create a raw type of Box:
Box rawBox = new Box();
I found this page after doing some sample exercises and having the exact same puzzlement.
============== I went from this code as provide by the sample ===============
public static void main(String[] args) throws IOException {
Map wordMap = new HashMap();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
====================== To This code ========================
public static void main(String[] args) throws IOException {
// replace with TreeMap to get them sorted by name
Map<String, Integer> wordMap = new HashMap<String, Integer>();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
Entry<String, Integer> entry = i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
}
===============================================================================
It may be safer but took 4 hours to demuddle the philosophy...
Just to synthesize a little bit: A raw type is a generic type without its type parameter (Example : List is the raw type of List<E>) Raw types shouldn't be used. They exist for compatibility with older versions of Java. We want to discover mistakes as soon as possible (compile time) and using raw types will probably result in error during runtime. We still need to use raw types in two cases :
Usage of class literals (List.class)
Usage of instanceof
Examples :
//Use of raw type : don't !
private final Collection stamps = ...
stamps.add(new Coin(...)); //Erroneous insertion. Does not throw any error
Stamp s = (Stamp) stamps.get(i); // Throws ClassCastException when getting the Coin
//Common usage of instance of
if (o instanceof Set){
Set<?> = (Set<?>) o;
}
Raw types are fine when they express what you want to express.
For example, a deserialisation function might return a List, but it doesn't know the list's element type. So List is the appropriate return type here.

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

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.

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.

How do I use [TypeArguments] with a constructor reference in Java 8?

Section 15.13 of the Java Language Specification for Java 8 describes this form of the method reference syntax for creating a constructor reference:
ClassType :: [TypeArguments] new
For example:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
That all works fine, but it seems that absolutely anything (excluding primitives) can be also supplied for the [TypeArguments] and everything still works:
Here's a silly example to prove the point:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
A few questions arising:
[1] Since the String class doesn't even use generics, is it valid that the compiler allows the creation of that test2 constructor reference with those meaningless [TypeArguments]?
[2] What would be a meaningful example of using [TypeArguments] when creating a constructor reference?
[3] Under what conditions is it essential to specify [TypeArguments] when creating a constructor reference?
1 15.13.1. Compile-Time Declaration of a Method Reference
If the method reference expression has the form ClassType :: [TypeArguments] new, the potentially applicable methods are a set of notional methods corresponding to the constructors of ClassType.
...
Otherwise, the candidate notional member methods are the constructors of ClassType, treated as if they were methods with return type ClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from [TypeArguments]) are selected, as specified in §15.12.2.1.
JLS 15.12.2.1. Identify Potentially Applicable Methods
This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.
2 Whenever a constructor is parameterized. I've never stumbled upon one.
public class Foo {
public <T> Foo(T parameter) {
...
Function<String, Foo> test = Foo::<String>new
3 When the compiler can't infer the type.

how to build Expression<Func<x,y>> with no input parameters?

I use Expression.Call to build MethodCallExpression dynamically. The call is for "First" method.
Then, I need to wrap it to Expression<Func<x,y>> (x and y are types, and it irrelevant to the question). I'm trying to do it with Expression.Lambda<Func<x,y>>, but get Incorrect number of parameters supplied for lambda declaration exception when passing
new ParameterExpression[]{} (i.e. empty array) in the ParameterExpression[] input parameter.
what should be provided to Expression.Lambda when the Lambda takes ZERO parameters?
Action is the delegate that corresponds to a void that accepts no parameters. Func<x, y> says that the method accepts an x and returns a y. All the Func delegates return values, and all the Action delegates are void.

Resources