What is the breakdown for Java's lambda syntax? - Stack Overflow
Lambda expressions in Java 8 - Stack Overflow
java - Lambda Expressions in Java8 - Stack Overflow
How do I debug lambda functions in Java
Videos
Syntax is:
arguments -> body
where arguments can be either
()a single variable if the type of that variable can be inferred from the context
a sequence of variables, with or without types (or since Java 11, with
var), in parentheses.
Examples:(x),(x, y),(int x, int y),(var x, var y)(Java 11+).
The following are invalid:(int x, y),(x, var y),(var x, int y)
and body can be either an expression or a {...} block with statements. The expression (other than a method or constructor call) is simply returned, i.e. () -> 2 is equivalent to () -> {return 2;}
In case of lambda expressions like () -> f() (the body is a method or constructor call expression):
if
f()returnsvoid, they are equivalent to() -> { f(); }otherwise, they are equivalent to either
() -> { f(); }or() -> { return f(); }). The compiler infers it from the calling context, but usually it will prefer the latter.
Therefore, if you have two methods: void handle(Supplier<T>) and void handle(Runnable), then:
handle(() -> { return f(); })andhandle(() -> x)will call the first one,handle(() -> { f(); }will call the second one, andhandle(() -> f()):if
f()returnsvoidor a type that is not convertible toT, then it will call the second oneif
f()returns a type that is convertible toT, then it will call the first one
The compiler tries to match the type of the lambda to the context. I don't know the exact rules, but the answer to:
What would happen if there were two SwingUtilities.invokeLater methods which differ only in parameter list?
is: it depends on what would be those parameter lists. If the other invokeLater had also exactly one parameter and that parameter would be of type that is also an interface with one method of type void*(), well, then it would complain that it cannot figure out which method you mean.
Why are they written as they are? Well, I think it's because syntax in C# and Scala is almost the same (they use => rather than ->).
The syntax is
(parameter_list_here) -> { stuff_to_do; }
The curly braces can be omitted if it's a single expression. The regular parentheses around the parameter list can be omitted if it's a single parameter.
The syntax only works for all functional interfaces. The @FunctionalInterface annotation tells the compiler that you intend to write such an interface and gives a compile error if you do not meet the requirement(s) - for example it must only have 1 overrideable method.
@FunctionalInterface
interface TestInterface {
void dostuff();
}
Runnable is also declared like that. Other interfaces are not, and they cannot be used with lambda functions.
Now that we've made a new functional interface with a method that takes no parameters, how about we test the question you had about "collision" in the signatures?
public class Main {
private void test(Runnable r) {
}
private void test(TestInterface ti) {
}
public static void main(String[] args) {
test(() -> { System.out.println("test");})
}
@FunctionalInterface
interface TestInterface {
void dostuff();
}
}
Result: compile error: ambigouous call to method test.
You see, the compiler/VM(if done runtime) finds the appropriate methods and their parameter list and sees if the parameter is a functional interface and if it is it creates an anonymous implementation of that interface. Technically (in byte code) it's different from an anonymous class, but otherwise identical (you won't see Main$1.class files).
Your example code (courtesy of Netbeans) can also be replaced with
SwingUtilities.invokeLater(MainAppJFrame::new);
Btw. :)
In general case what you're looking for is take-while. Unfortunately, it has no default implementation in Java 8 streams. See a question about take-while.
If all you're looking to do is convert the given sequence into the triangle (as you describe), this does it much simpler.
List<Integer> l = IntStream.rangeClosed(1, 100)
.mapToObj(n -> (n*n + n) / 2)
.collect(Collectors.toList());
the primitive stream wrappers need an extra step to up-convert to objects, hence the mapToObj method.
If you're looking to stop filtering when you hit 100, easiest way I can think of is
IntFunction<Integer> calc =n -> (n*n+n) / 2;
List<Integer> l = IntStream.rangeClosed(1, 100)
.filter(n -> calc.apply(n) < 100)
.mapToObj(calc)
.collect(Collectors.toList());
Based on the changes to your question, I think this is also pretty important to point out. If you want to mirror what you used to do, that would look like this:
List<Integer> results = new ArrayList<>(100);
IntStream.rangeClosed(1, 100).forEach(i -> {
int tri =calc.apply(i);
if(tri < 100) {
results.add(tri);
}
});
It's worth pointing out that streams are not necessarily ordered (though the default implementation follows the iterator). If this were converted to a parallel stream you would see the difference (and power of streams). You can't break from the execution because then you're assuming a certain amount about the processing order. By filtering early (in my second form) you'll ensure that you only end up with a result stream of 13 entries in it before the final calculation. Take this parallel option as a note as well.
List<Integer> l = IntStream.rangeClosed(1, 100).parallel()
.filter(n -> calc.apply(n) < 100)
.mapToObj(calc)
.collect(Collectors.toList());
You'll see they're still ordered, but the computation of them was done on multiple threads.
In the following line
String s = (String) invoke(() -> true);
It is actually invoke(Callable) that is getting called. The reason is:
() -> trueis a lambda expression that has zero formal parameter and return a result.- Such a signature (zero parameter, single result) is compatible with the functional method
call()of theCallableinterface. Note that the interface does not need to have the@FunctionalInterfaceannotation, it just needs to have a single abstract method.
If you want to invoke invoke(Runnable) instead, you will need to create a lambda that is compatible with a functional method that takes zero parameter and returns no result (i.e. conforms with the signature of run()). Something like this:
invoke(() -> System.out.println("foo"));
Which just prints foo when ran.
A lambda expression supplies an implementation for a functional interface. This is what your code snippet does.
Your call to invoke passes a lambda expression with no arguments that returns a value (a boolean in your case). Therefore it matches Object invoke(Callable c), and not void invoke(Runnable r) (since a Callable's call method has a return value while a Runnable's run method doesn't return anything).
invoke(() -> {System.out.println("something");});
will call void invoke(Runnable r), since in this case the lambda expression has no return type.