Как Lambba работает в Java при использовании Thread и Runnable? - PullRequest
0 голосов
/ 01 февраля 2020

Моя IDE (IntelliJ) предлагает заменить этот код:

private void countIterations() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            long startTimestamp = System.currentTimeMillis();
            long endTimestamp = startTimestamp + ITERATIONS_COUNTER_DURATION_SEC * 1000;

            int iterationsCount = 0;
            while (System.currentTimeMillis() <= endTimestamp) {
                iterationsCount++;
            }

            Log.d(
                    "Exercise1",
                    "iterations in " + ITERATIONS_COUNTER_DURATION_SEC + "seconds: " + iterationsCount
            );
        }
    }).start();

}

этим:

private void countIterations() {
    new Thread(() -> {
        long startTimestamp = System.currentTimeMillis();
        long endTimestamp = startTimestamp + ITERATIONS_COUNTER_DURATION_SEC * 1000;

        int iterationsCount = 0;
        while (System.currentTimeMillis() <= endTimestamp) {
            iterationsCount++;
        }

        Log.d(
                "Exercise1",
                "iterations in " + ITERATIONS_COUNTER_DURATION_SEC + "seconds: " + iterationsCount
        );
    }).start();

}

Мои вопросы: откуда он знает, что это Runnable? И Thread, и Runnable имеют метод run.

1 Ответ

1 голос
/ 01 февраля 2020

откуда он знает, что это Runnable?

Прежде всего, давайте удостоверимся, что мы знаем, что означает "Runnable". Опытные Java программисты говорят, что не задумываясь об этом слишком глубоко, но Runnable - это не класс. Это интерфейс : это спецификация одного или нескольких методов, которые, как ожидается, должен иметь какой-то фактический класс. Когда мы говорим «Runnable», мы на самом деле имеем в виду «экземпляр некоторого класса, который implements Runnable».

Так как же компилятор узнает, что лямбда-выражение должно создавать «Runnable?» Это легко. Компилятор видел объявление класса Thread, а объявление класса Thread явно говорит, что аргумент конструктора должен быть Runnable.

Оба Thread и Runnable есть метод run().

ОК. Thread implements Runnable, но не имеет смысла использовать там экземпляр Thread, потому что метод Thread class run() не выполняет то, что вы хотите, чтобы ваш поток выполнял. Компилятор должен определить совершенно новый класс с помощью метода run(), который выполняет все то, что вы помещаете в тело вашей лямбды. В системе нет другого класса, который бы все это делал.

ОК, так почему новый класс не extends Thread? (или extends любой другой существующий класс, который implements Runnable?)

Просто потому, что для этого нет причин. Конструктор Thread не говорит, что ему нужен аргумент Thread. Он говорит, что хочет аргумент Runnable. Он будет доволен любым классом, implements Runnable, и никогда не будет ничего делать с объектом, кроме как вызвать его метод run().

ОК, но как узнает компилятор превратить лямбда-тело в метод с именем run()?

, поскольку Runnable - это интерфейс @functional, который объявляет ровно один метод. Runnable объект должен иметь метод run(), и интерфейс не указывает никакой другой метод, поэтому другого выбора нет.

...