ссылка на метод против лямбда-выражения

Я хочу заменить лямбда-выражение ссылкой на метод в приведенном ниже примере:

 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);
        }
   }

Я хочу написать что-то вроде этого:

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

возможно ли преобразовать любое лямбда-выражение в ссылку на метод.


person midy62    schedule 24.10.2016    source источник
comment
Возможный дубликат ссылок на методы для непустых аргументов?   -  person fafl    schedule 24.10.2016
comment
Благодарю за ваш ответ. не могли бы вы показать мне, пожалуйста, преобразование в моем случае, потому что с (s :: endWith (.)) я получаю ошибку компиляции.   -  person midy62    schedule 24.10.2016
comment
Вы не можете использовать ::, если аргумент находится в вызове экземпляра. Вы можете заменить s -> "hi".equals(s) на "hi"::equals, но не s -> s.equals("hi")   -  person Peter Lawrey    schedule 24.10.2016
comment
спасибо, Питер. Теперь все очень ясно. так что в моем случае это невозможно   -  person midy62    schedule 24.10.2016
comment
под капотом MethodHandle может перемешивать аргументы, но это не отображается в синтаксисе ссылки на метод Java, и мне интересно, действительно ли это будет быстрее после вставки. scala, с другой стороны, может делать это с частично примененными функциями   -  person the8472    schedule 24.10.2016
comment
@ the8472: MethodHandle может перемешивать аргументы, но результат больше не является дескриптором прямого метода, а LambdaMetaFactory поддерживает только дескрипторы прямого метода. Частично применяемые функции, с другой стороны, будут работать, поскольку они не перемешивают аргументы, а LMF поддерживает привязку параметров слева направо. Так что для .endsWith("."), где должен быть привязан правильный параметр, нет шансов ...   -  person Holger    schedule 24.10.2016
comment
Синтаксис ссылки на метод будет String::endsWith плюс некоторый гипотетический способ привязки аргумента ".". В чем преимущество перед s -> s.endsWith(".")?   -  person Holger    schedule 24.10.2016


Ответы (2)


Невозможно «преобразовать любое лямбда-выражение в ссылку на метод», но вы можете реализовать фабрику для определенного целевого типа, если это удовлетворяет повторяющиеся потребности:

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

с этим вы можете написать

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

но на самом деле преимущества нет. Технически лямбда-выражение делает именно то, что вы хотите, есть минимально необходимый код преобразования аргументов, выраженный в виде тела лямбда-выражения, скомпилированного в синтетический метод, и ссылка на метод этого синтетического кода. Синтаксис
s -> s.endsWith(".") также является наименьшим возможным синтаксисом для выражения этого намерения. Я сомневаюсь, что вы сможете найти меньшую конструкцию, которая все еще была бы совместима с остальной частью языка программирования Java.

person Holger    schedule 24.10.2016
comment
почему, когда я использую: Supplier ‹String› x = String :: toUpperCase; я получаю Невозможно создать статическую ссылку на нестатический метод toUpperCase () из типа String, но когда я использую BiPredicate ‹String, String› x = String ::ndsWith; это отлично работает - person midy62; 24.10.2016
comment
Как toUpperCase должен быть Supplier? Для преобразования в верхний регистр требуется String, поэтому вы должны использовать тип функции, который потребляет String, например Function<String,String> или UnaryOperator<String>. Или вы привязываете экземпляр типа Supplier<String> x="foo"::toUpperCase, но от поставщика, который всегда поставляет "FOO"…, нет особого смысла. - person Holger; 24.10.2016

Вы можете использовать selectWith() из Коллекций Eclipse. selectWith() принимает Predicate2, который принимает 2 параметра вместо Predicate. Второй параметр selectWith() передается как второй параметр Predicate2 каждый раз, когда он вызывается, один раз для каждого элемента в итерируемом объекте.

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

По умолчанию Eclipse Collections активен, если вы хотите лениво итерировать, вы можете использовать asLazy()

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

Если вы не можете перейти с List:

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

RichIterable имеет несколько других * с методами, которые хорошо работают со ссылками на методы, включая rejectWith(), partitionWith(), detechWith(), anySatisfyWith(), allSatisfyWith(), noneSatisfyWith(), collectWith()

Примечание: я участник коллекций Eclipse.

person Nikhil Nanivadekar    schedule 27.10.2016