The essential observation here is that your problem involves a non-isomorphic transformation: a single input element may map to zero, one, or two output elements. Whenever you notice this, you should immediately start looking for a solution which involves flatMap instead of map because that's the only way to achieve such a general transformation. In your particular case you can first apply filter for a one-to-zero element mapping, then flatMap for one-to-two mapping:
List<Integer> result =
IntStream.rangeClosed(1, 10)
.filter(i -> 10 % i == 0)
.flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
.boxed()
.collect(toList());
(assuming import static java.util.stream.Collectors.toList)
Videos
The essential observation here is that your problem involves a non-isomorphic transformation: a single input element may map to zero, one, or two output elements. Whenever you notice this, you should immediately start looking for a solution which involves flatMap instead of map because that's the only way to achieve such a general transformation. In your particular case you can first apply filter for a one-to-zero element mapping, then flatMap for one-to-two mapping:
List<Integer> result =
IntStream.rangeClosed(1, 10)
.filter(i -> 10 % i == 0)
.flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
.boxed()
.collect(toList());
(assuming import static java.util.stream.Collectors.toList)
You could declare a body for a lambda. For example:
Runnable run = () -> System.out.println("Hey");
Could be
Runnable run = () -> {
System.out.println("Hey");
};
Within that body, you can create nested statements:
Runnable run = () -> {
int num = 5;
if(num == 5) {
System.out.println("Hey");
}
};
Lambdas are purely a call-site construct: the recipient of the lambda does not need to know that a Lambda is involved, instead it accepts an Interface with the appropriate method.
In other words, you define or use a functional interface (i.e. an interface with a single method) that accepts and returns exactly what you want.
Since Java 8 there is a set of commonly-used interface types in java.util.function.
For this specific use case there's java.util.function.IntBinaryOperator with a single int applyAsInt(int left, int right) method, so you could write your method like this:
static int method(IntBinaryOperator op){
return op.applyAsInt(5, 10);
}
But you can just as well define your own interface and use it like this:
public interface TwoArgIntOperator {
public int op(int a, int b);
}
//elsewhere:
static int method(TwoArgIntOperator operator) {
return operator.op(5, 10);
}
Then call the method with a lambda as parameter:
public static void main(String[] args) {
TwoArgIntOperator addTwoInts = (a, b) -> a + b;
int result = method(addTwoInts);
System.out.println("Result: " + result);
}
Using your own interface has the advantage that you can have names that more clearly indicate the intent.
To use Lambda expression you need to either create your own functional interface or use Java functional interface for operation that require two integer and return as value. IntBinaryOperator
Using user defined functional interface
interface TwoArgInterface {
public int operation(int a, int b);
}
public class MyClass {
public static void main(String javalatte[]) {
// this is lambda expression
TwoArgInterface plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34));
}
}
Using Java functional interface
import java.util.function.IntBinaryOperator;
public class MyClass1 {
static void main(String javalatte[]) {
// this is lambda expression
IntBinaryOperator plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34));
}
}
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. :)
As it almost but not really matches Optional, maybe you might reconsider the logic:
Java 8 has a limited expressiveness:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));
Here the map might restrict the view on the element:
element.map(el -> el.mySpecialView()).ifPresent(System.out::println);
Java 9:
element.ifPresentOrElse(el -> System.out.println("Present " + el,
() -> System.out.println("Not present"));
In general the two branches are asymmetric.
It's called a 'fluent interface'. Simply change the return type and return this; to allow you to chain the methods:
public MyClass ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
return this;
}
public MyClass ifNotExist(Consumer<Element> consumer) {
if (!exist()) {
consumer.accept(this);
}
return this;
}
You could get a bit fancier and return an intermediate type:
interface Else<T>
{
public void otherwise(Consumer<T> consumer); // 'else' is a keyword
}
class DefaultElse<T> implements Else<T>
{
private final T item;
DefaultElse(final T item) { this.item = item; }
public void otherwise(Consumer<T> consumer)
{
consumer.accept(item);
}
}
class NoopElse<T> implements Else<T>
{
public void otherwise(Consumer<T> consumer) { }
}
public Else<MyClass> ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
return new NoopElse<>();
}
return new DefaultElse<>(this);
}
Sample usage:
element.ifExist(el -> {
//do something
})
.otherwise(el -> {
//do something else
});
Alternatively, in Java 8, the Iterator interface has a default method forEachRemaining(Consumer).
That one would solve your problem without having to resort to streams. You can simply do:
Iterator<Match> it = myScreen.findAll(myPattern);
it.forEachRemaining(Match::click);
Well there will be a way to iterate with streams like a for loop or an iterator - via Stream.iterate, but it will be present in jdk-9. But it is not that trivial to use - because it acts exactly like a for loop and thus not exactly what you might expect. For example:
Iterator<Integer> iter = List.of(1, 2, 3, 4).iterator();
Stream<Integer> stream = Stream.iterate(iter.next(),
i -> iter.hasNext(),
i -> iter.next());
stream.forEach(System.out::println); // prints [1,2,3]
Or this:
Iterator<Integer> iter = List.of(1).iterator();
Stream.iterate(iter.next(), i -> iter.hasNext(), i -> iter.next())
.forEach(System.out::println); // prints nothing
For the case that you need there's the forEachRemaining, but it's no "magic", internally it does exactly what you do:
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}