4

I want to replace lambda expression by method reference in the below example :

 public class Example {

        public static void main(String[] args) {
            List<String> words = Arrays.asList("toto.", "titi.", "other");
         //lambda expression in the filter (predicate)
            words.stream().filter(s -> s.endsWith(".")).forEach(System.out::println);
        }
   }

I want to write a something like this :

words.stream().filter(s::endsWith(".")).forEach(System.out::println);

is it possible to transform any lambda expression to method reference.

7
  • Possible duplicate of Method references for non-empty arguments? Commented Oct 24, 2016 at 10:01
  • 5
    You can't use :: if the argument is on the instance call. You can replace s -> "hi".equals(s) with "hi"::equals but not if it's s -> s.equals("hi") Commented Oct 24, 2016 at 10:07
  • 2
    under the hood MethodHandle can shuffle arguments, but this is not exposed in the java method reference syntax and I wonder if it would actually be any faster after inling. scala on the other hand can do that with partially applied functions Commented Oct 24, 2016 at 10:52
  • 2
    @the8472: MethodHandle can shuffle arguments, but the result is not a direct method handle anymore and LambdaMetaFactory does support direct method handles only. Partially applied functions, on the other hand, would work, as they don’t shuffle arguments, and LMF supports left-to-right parameter binding. So for .endsWith("."), where the right parameter ought to be bound, no chance… Commented Oct 24, 2016 at 11:21
  • 1
    The syntax for a method reference would be String::endsWith, plus some hypothetical way to bind the "." argument. What’s the advantage over s -> s.endsWith(".")? Commented Oct 24, 2016 at 11:24

2 Answers 2

4

There is no way “to transform any lambda expression to method reference”, but you can implement a factory for a particular target type, if this serves recurring needs:

public static <A,B> Predicate<A> bind2nd(BiPredicate<A,B> p, B b) {
    return a -> p.test(a, b);
}

with this, you can write

words.stream().filter(bind2nd(String::endsWith, ".")).forEach(System.out::println);

but actually, there’s no advantage. Technically, a lambda expression does exactly what you want, there’s the minimum necessary argument transformation code, expressed as the lambda expression’s body, compiled into a synthetic method and a method reference to that synthetic code. The syntax
s -> s.endsWith(".") also is already the smallest syntax possible to express that intent. I doubt that you can find a smaller construct that would still be compatible with the rest of the Java programming language.

Sign up to request clarification or add additional context in comments.

2 Comments

why when i use : Supplier<String> x=String::toUpperCase; i get "Cannot make a static reference to the non-static method toUpperCase() from the type String" but when i use BiPredicate<String,String> x=String::endsWith; this work fine
How is toUpperCase supposed to be a Supplier? It requires a String to convert to upper case, so you have to use a function type that consumes a String, e.g. Function<String,String> or UnaryOperator<String>. Or you bind an instance like Supplier<String> x="foo"::toUpperCase, but there is not much use in a supplier that always supplies "FOO"
3

You can use selectWith() from Eclipse Collections. selectWith() takes a Predicate2 which takes 2 parameters instead of a Predicate. The second parameter to selectWith() gets passed as the second parameter to the Predicate2 every time it's called, once per item in the iterable.

MutableList<String> words = Lists.mutable.with("toto.", "titi.", "other");
words.selectWith(String::endsWith, ".").each(System.out::println);

By default Eclipse Collections is eager, if you want to iterate lazily then you can use asLazy()

words.asLazy().selectWith(String::endsWith, ".").each(System.out::println);

If you can't change from List:

List<String> words = Arrays.asList("toto.", "titi.", "other");
ListAdapter.adapt(words).selectWith(String::endsWith, ".").each(System.out::println);

Eclipse Collections' RichIterable has several other *With methods which work well with method references, including rejectWith(), partitionWith(), detechWith(), anySatisfyWith(), allSatisfyWith(), noneSatisfyWith(), collectWith()

Note: I am a contributor to Eclipse Collections.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.