What does this below lambda function do?
public class FunctionInterface {
public static void main(String[] args) {
Function<String, Consumer<Integer>> secondFunction = s -> x -> System.out.println(x);
System.out.println(secondFunction.apply("Text"));
}
}
The above code is printing some random value, how to make it print text?
Your variable secondFunction is a Function that takes a String and returns a Consumer<Integer>. In this line:
System.out.println(secondFunction.apply("Text"));
you are calling apply on the Function, which will return a Consumer<Integer>, and then you print the object, which will cause toString to be called on the Consumer<Integer> object (and then the string will be printed).
It will not run the lambda expression, which is what you seem to expect. Try this instead:
// Call accept(123) on the consumer, which will execute the lambda
secondFunction.apply("Text").accept(123);
You say you wanted to print "Text" maybe this is easier?
You don't need to return the consumer with a Function. I'm confused what is the purpose?
Consumer<String> consumer = System.out::println;
consumer.accept("Text");
Related
This question already has answers here:
Lambda 'special void-compatibility rule' - statement expression
(3 answers)
Why do Consumers accept lambdas with statement bodies but not expression bodies?
(3 answers)
Why does a Java method reference with return type match the Consumer interface?
(2 answers)
Consumer lambda in Java 8 [duplicate]
(2 answers)
Closed 4 years ago.
Given this method:
private static Integer return0() {
return 0;
}
I discovered a weird property of the following lambda expression:
() -> return0();
Does it actually return the value from the function it calls (which would make it a Supplier-Interface) or does it not return the value but only calls the function and returns void (which would make it a Runnable-Interface). Intuitively, I would expect the first case to be correct but could live with the second.
When trying to assign the statement:
Supplier<Integer> supplier2 = () -> return0();
Runnable runnable2 = () -> return0();
It turns out both lines do compile! Why would they allow that? It is completely ambiguous and really confusing!
EDIT:
Here is more code to demonstrate what I mean by confusing/ambigous:
public static void main(String[] args) {
callMe(() -> return0());
}
private static Integer return0() {
return 0;
}
private static void callMe(Supplier<Integer> supplier) {
System.out.println("supplier!");
}
private static void callMe(Runnable runnable) {
System.out.println("runnable!");
}
This all compiles well and upon execution prints "supplier!". I do not find it particularly intuitive that the first method is chosen but rather arbitrary.
The relevant part of the spec is Sec 15.27.3 (emphasis mine):
A lambda expression is congruent with a function type if all of the following are true:
The function type has no type parameters.
The number of lambda parameters is the same as the number of parameter types of the function type.
If the lambda expression is explicitly typed, its formal parameter types are the same as the parameter types of the function type.
If the lambda parameters are assumed to have the same types as the function type's parameter types, then:
If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.
If the function type's result is a (non-void) type R, then either i) the lambda body is an expression that is compatible with R in an assignment context, or ii) the lambda body is a value-compatible block, and each result expression (§15.27.2) is compatible with R in an assignment context.
Your lambda body is a statement expression, and the function type's result is void.
In other words, it would be fine for you to write:
return0();
and ignore the return value in "regular" code, so it's fine to ignore the result value in a lambda too.
In terms of the question over ambiguity of overloads, there is no ambiguity in this case (it's easy to construct a case where there is ambiguity, e.g. another overload with a parameter that looks like Supplier but is a different interface, i.e. takes no parameters, returns a value).
You would have to read the spec in detail for the precise reasoning, but I think the most relevant section is Sec 15.12, which describes method invocation expressions, and the most useful quote from that is in Sec 15.12.2.5, which deals with selecting the most-specific overload:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
You can use a Supplier<Integer> in place of a Runnable (with a bit of a hand-wavy fudge) because you can simply ignore the return value; you can't use a Runnable in place of a Supplier<Integer> because it doesn't have a return value.
So a method taking the Supplier<Integer> is more specific than the method taking the Runnable, hence that is the one which is invoked.
If you get confused with lambda expressions, replace them with anonymous classes for a better understanding (IntelliJ IDEA can easily help you with that). The following code snippets are completely valid:
Supplier<Integer> supplier2 = () -> return0() is equivalent to:
Supplier<Integer> supplier2 = new Supplier<Integer>() {
#Override
public Integer get() {
return return0();
}
};
Runnable runnable2 = () -> return0() is equivalent to:
Runnable runnable2 = new Runnable() {
#Override
public void run() {
return0();
}
};
public static void main(String[] args) throws Exception
{
Supplier<Integer> consumer2 = Trial::return0;
Runnable runnable2 = Trial::return0;
run(Trial::return0);
}
private static Integer return0() {
return 0;
}
private static int run(Supplier<Integer> a)
{
System.out.println("supplier");
return a.get();
}
private static void run(Runnable r)
{
System.out.println("runnable");
r.run();
}
As far as method overloading is concerned, this code in class Trial prints "supplier".
I am not understanding the reason, for having the compilation error for the below program. Where am I going wrong? I want to print the value of the string as output using method reference.
public class ConsumerDemo{
public static void main(String[] args) {
test("hello", (str)-> str::toUpperCase);
}
public static void test(String str, Consumer<String> consumer) {
consumer.accept(str);
}
}
test("hello", String::toUpperCase)
should be the correct syntax.
In order to print the upper case of the input, you can use:
String str = "hello"; // any input value
test(str.toUpperCase(), System.out::println);
you cannot combine lambda syntax and method reference syntax as such.
You're either looking for:
test("hello", String::toUpperCase);
or:
test("hello", s -> s.toUpperCase());
but this then means the result of String::toUpperCase/s -> s.toUpperCase() is ignored hence, you'll need to perform something more useful. for example:
test("hello", s -> System.out.println(s.toUpperCase()));
This is a regular Consumer with usage:
public static void main(String[] args){
Consumer<String> consumer = (str) -> {
//stuff
};
consumer.accept(args[0]);
}
Here is what I am attempting to do (make it so consumer returns as boolean)
public static void main(String[] args){
Consumer<String> consumer = (str) -> {
return str.equals("yes"); //type mis-match error because consumer is void not boolean
};
boolean a = consumer.accept(args[0]); //type mis-match error because consumer is void not boolean
}
How can I manipulate consumer to return as a boolean?
Without obviously creating a whole new interface.... (below)
public interface ConsumerB {
boolean accept(String s);
}
For the case in which one wants to pass a String and get a boolean, one can use Predicate<String>. There are similiar functions if one wants to return one of the following primitives:
for int: ToIntFunction<String>,
for long: ToLongFunction<String>, and
for double: ToDoubleFunction<String>.
In line with the rest of the java.util.function- and the java.util.stream package, there are no further To<Primitive>Function interfaces for the primitives byte, short, char and float.
For the case in which one wants to pass a String and get a String, one can use UnaryOperator<String>.
For the general case in which one wants to pass some T and get some R, one can use Function<T, R>.
Whether this, however, improves the readability of the code is another question...
A consumer that returns something is not a consumer anymore. It becomes a Predicate<String>:
Predicate<String> consumer = (str) -> {
return str.equals("yes");
};
You also mentioned in the title that you want the functional interface to return a String. In that case, use Function<String, String>.
What does ()->{} represent in java?. Any help would be highly appreciated.
It's a lambda expression, basically a concise way of writing a function. ()->{} is a function that takes no arguments and does nothing. A longer way of writing the same thing:
new Runnable() {
#Override
public void run() {
// nothing
}
};
Let's consider old way of writing functions(i.e methods) in java.
//lets assume this is inside calculate class
public int sum(int a, int b){
return a+b;
}
in java 8 we have something called lambda's in which we have concept called passing behaviours(methods) to another behaviour(methods).
in those case we use syntax like (a,b) -> return a+b;
BiFunction<Integer,Integer,Integer> sum= (a,b)->{
return a+b;
};
System.out.println(sum.apply(1, 2));
Even we can store Function in a variable and pass to another function. you
can see here
now lets see about syntax (a,b) ->{ return a + b};
(a,b) are arguments to function;
and the line of code inside {} represent the behaviour. -> is to separate
both left and right expressions.
you can explore more about java8 and lambda over here
OK, the first question in this "series" was this one.
Now, here is another case:
Arrays.asList("hello", "world").stream().forEach(System.out::println);
This compiles, and works...
OK, in the last question, static methods from a class were used.
But now this is different: System.out is a static field of System, yes; it is also a PrintStream, and a PrintStream has a println() method which happens to match the signature of a Consumer in this case, and a Consumer is what forEach() expects.
So I tried this...
public final class Main
{
public static void main(final String... args)
{
Arrays.asList(23, 2389, 19).stream().forEach(new Main()::meh);
}
// Matches the signature of a Consumer<? super Integer>...
public void meh(final Integer ignored)
{
System.out.println("meh");
}
}
And it works!
This is quite a different scope here, since I initiate a new instance and can use a method reference right after this instance is constructed!
So, is a method reference really any method which obeys the signature? What are the limits? Are there any cases where one can build a "#FunctionalInterface compatible" method which cannot be used in a #FunctionalInterface?
The syntax of method references is defined in JLS #15.13. In particular it can be of the form:
Primary :: [TypeArguments] Identifier
Where Primary can be, among other things, a:
ClassInstanceCreationExpression
so yes, your syntax is correct. A few other interesting examples:
this::someInstanceMethod // (...) -> this.someInstanceMethod(...)
"123"::equals // (s) -> "123".equals(s)
(b ? "123" : "456")::equals // where b is a boolean
array[1]::length // (String[] array) -> array[1].length()
String[]::new // i -> new String[i]
a.b()::c // (...) -> a.b().c(...)
By the way, since you mention static methods, it is interesting to note that you can't create a static method reference from an instance:
class Static { static void m() {} }
Static s = new Static();
s.m(); //compiles
someStream.forEach(s::m); //does not compile
someStream.forEach(Static::m); //that's ok
From the State of Lambda
Kinds of method references
There are several different kinds of method references, each with
slightly different syntax:
A static method (ClassName::methName)
An instance method of a particular object (instanceRef::methName)
A super method of a particular object (super::methName)
An instance method of an arbitrary object of a particular type (ClassName::methName)
A class constructor reference (ClassName::new)
An array constructor reference (TypeName[]::new)
Saying this:
something(new Main()::meh);
Is approximately equivalent to saying this:
Main x = new Main();
something(() -> x.meh());
Or this:
final Main x = new Main();
something(new Whatever() {
public void meh(Integer ignored) {
x.meh();
}
}
The new instance is "captured" and used in the new lambda instance which was implicitly created from the method handle.