It's possible to chain/concatenate what is done with elements in a lambda expression like this:
list.forEach(s -> {
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
});
Is there a way to do this also with method references? Something like this:
list.forEach({
System.out::println(String::toLowerCase);
System.out::println(String::toCase);
});
I know I could do this in four separate calls (which do also more, that is mutate the values):
list.replaceAll(String::toLowerCase);
list.forEach(System.out::println);
list.replaceAll(String::toUpperCase);
list.forEach(System.out::println);
I can't even do something easy like this:
list.forEach({
System.out::println;
System.out::println;
});
chaining is possible through default methods of the functional interfaces. But the "problem" is that there that the inference engine does not have enough information to determine that the left hand side is the same functional interface when you're returning the right hand side of the compositing expression.
To provide that information you either have to cast the statement:
List<String> l = Collections.emptyList();
l.forEach(((Consumer<String>)System.out::println).andThen(System.out::println));
Or assign it to a variable first:
Consumer<String> cons = System.out::println;
Collections.<String>emptyList().forEach(cons.andThen(System.out::println));
Alternatively you could also write static helper methods that do what you want
Collections.<String>emptyList().forEach(combine(System.out::println, System.out::println));
static <T> Consumer<T> combine(Consumer<T>... consumers) {
// exercise left to the reader
}
No you can't use method references as you have suggested. Method references are really just a syntactic replacement for a lambda expression. So that instead of:
text -> console.print(text)
You can avoid introducing an unnecessary variable and instead use
console::print
So when you mention that you can't do something such as:
list.forEach({
System.out::println;
System.out::println;
});
This is just a syntactic shortcut for
list.forEach({
c -> System.out.println(c);
c -> System.out.println(c);
});
This really makes no sense. There's no variable representing the item in the list (which would have to be outside the block) and the two 'statements' are lambda expressions with nothing to be applied to.
Method references are a pretty neat shortcut to avoid having an unnecessary variable but they are just a substitute for a more verbose lambda expression and can't be used as an independent statement in a block.
There is no point in converting
list.forEach(s -> {
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
});
to
list.forEach({
System.out::println(String::toLowerCase);
System.out::println(String::toUpperCase);
});
as there is no win in clarity, the latter even consists of more characters than the former, if we use the same indention and insert the Upper
you have left off the second variant. So why should we have such an alternative form?
Method reference have been invented as a feature allowing a dense syntax for a single method delegation, were declaring and referencing the parameters could really make a difference. Even replacing a sole s->System.out.println(s)
with System.out::println
is no that big win, but at least, there is some. Further, encoding the method reference at bytecode level can be more compact because the target method can be directly referenced just like the synthetic method holding a lambda expression’s code. For compound method references, there is no such compact form.
Since your desired operation consist of operations of different kinds, you may use the Stream
API, which is intended to combine such operations:
list.stream().flatMap(s->Stream.of(s.toLowerCase(), s.toUpperCase()))
.forEach(System.out::println);
and if you want to include method references for everything, at all costs, you may do it the following way:
list.stream()
.flatMap(s->Stream.<UnaryOperator<String>>of(String::toLowerCase, String::toUpperCase)
.map(f->f.apply(s)))
.forEach(System.out::println);
来源:https://stackoverflow.com/questions/31625299/multiple-lambda-method-references