Лямбда-выражения в Java8

import java.util.concurrent.Callable;

public class AdvancedLambda {

    static void invoke(Runnable r){
        r.run();
    }

    static Object invoke(Callable c) throws Exception {
        return c.call();
    }

    public static void main(String[] args) throws Exception {

        String s = (String) invoke(() -> true);
        System.out.println(s);
    }
}

может ли кто-нибудь помочь мне понять это? У меня сложилось впечатление, что мы можем использовать выражения lamba в Java 8 только тогда, когда реализуем интерфейс и переопределяем его методы (заменяя анонимные классы лямбда-выражениями).

и в какой ситуации будет метод invoke(Runnable r) назвать?

5 ответов


в следующей строке

String s = (String) invoke(() -> true);

это на самом деле invoke(Callable) что называется. Причина:

  • () -> true - лямбда-выражение, которое имеет нулевой формальный параметр и возвращает результат.
  • такая подпись (нулевой параметр, одиночный результат) совместима с функциональным методом call() на Callable интерфейс. Обратите внимание, что интерфейс не нужен @FunctionalInterface аннотации, он просто должен иметь один абстрактный метод.

если вы хотите вызвать invoke(Runnable) вместо этого вам нужно будет создать лямбду, совместимую с функциональным методом, который принимает нулевой параметр и не возвращает результата (т. е. соответствует сигнатуре run()). Что-то вроде этого:--11-->

invoke(() -> System.out.println("foo"));

которая просто выводит foo когда побежал.


лямбда-выражение обеспечивает реализацию функционального интерфейса. Это то, что делает фрагмент кода.

вызов invoke передает лямбда-выражение без аргументов, которое возвращает значение (a boolean в вашем случае). Поэтому он соответствует Object invoke(Callable c), а не void invoke(Runnable r) (поскольку Callable ' s call метод имеет возвращаемое значение, а Runnable ' s run метод ничего не возвращает).

invoke(() -> {System.out.println("something");});

будем называть void invoke(Runnable r), так как в этом случае лямбда-выражение не имеет возвращаемого типа.


только когда мы реализуем интерфейс и переопределить его методы

это, более или менее, то, что вы здесь делаете. Не методs, но только один способ: call(). Это () -> true - Это ваша реализация Callable#call().

другими словами, эта строка:

String s = (String) invoke(() -> true);

было бы полностью эквивалентно этому:

String s = (String) invoke(new Callable() {
        @Override
        public Object call() throws Exception {
            return true;
        }
    });    

взгляните на пример ниже.

import javafx.beans.DefaultProperty;
import jdk.nashorn.internal.codegen.CompilerConstants;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by KUMAJYE on 13/09/2016.
 */
public class ThreadMonitor {

private static int noOfThreads = 0;


public static void main(String[] args) {
    ThreadModel threadModel;
    noOfThreads = Integer.parseInt(args[0]);
    if (noOfThreads > 0) {
        threadModel = getThreadingModelForCallsInCallingThread();
    } else {
        threadModel = getAsynchThreadingModel();
    }

}

public static ThreadModel getThreadingModelForCallsInCallingThread() {
    ExecutorService executor = Executors.newFixedThreadPool(noOfThreads);
    return (r) -> executor.submit(r);
}


public static ThreadModel getAsynchThreadingModel() {
    // do execution on same Thread or separate Thread.
    // or
    // r.run();
    return (r) -> new Thread(r).start();
}

interface ThreadModel {

    void invoke(Runnable r);
}

}


  • лямда -: может использоваться только для выполнения фоновых задач (здесь компилятор затем выясняет)
  • выражения: возвращают какое-то значение

лямбда-выражение-это еще один способ написания экземпляра анонимного класса, чтобы упростить запись экземпляра анонимного класса. В JVM он не будет занимать много памяти по сравнению с обычным созданием объектов java с new(выполнении статических переменных, статические блоки, загрузка классов из всей иерархии ).

enter image description here

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

(params) -> expression to implement a @FunctionalInterface

в вашем тесте: String s = (String) invoke(() -> true); выражение имеет тип возвращаемого true не аргумент. Так что Runnable FunctionalInterface не соответствует лямбда-выражению, потому что оно имеет . Он совпадает с Callable FuncationalInterface используя
V call().

как работают лямбда-выражения под капотом?
Может показаться, что лямбда-выражения-это просто синтаксический сахар для анонимных внутренних классов, но есть гораздо более элегантный подход. Самое простое объяснение: лямбда-выражение представлено новым методом и вызывается во время выполнения с помощью invokedynamic.

Исходный Код:

class LambdaExample {

    public void abc() {
        Runnable r = () -> { 
            System.out.println("hello");
        }
        r.run();
    }

}

байт-кода эквивалентны:

class LambdaExample {

    public void abc() {
        Runnable r = <lambda as Runnable instance>;
        r.run(); 
    }

    static void lambda() {
        System.out.println("hello");
    }

}

внутри JVM есть лямбда-фабрика это создает экземпляр функционального интерфейса (например, Runnable) из сгенерированного метода lambda (например, lambda$1).

лямбда-выражения великолепны, и в Java 8...