Lambda

Ни для кого не секрет, что во второй половине 2013 года планируется выпуск Java 8 (UPD: на JavaOne 2013 в Москве сообщили, что выход восьмерки перенесут на 2014). Мне наконец-то надоело быть пассивным читателем всех этих многочисленных восторженных отзывов о нововведениях языка и я решил скачать предварительную версию JDK (благо она уже давно выложена) и начать свои экзерсисы.

Как правило я стараюсь ждать релиза, но сейчас в новостях столько разговоров о лямбда-выражениях в новой Java, что мне, старому Scala-фанатику и функционального программирования, уж очень сильно захотелось поиграться с новыми возможностями языка. Если смотреть на все новшества восьмой Java со стороны Scala программиста, то в целом лично я отношусь к ним положительно, поскольку такой расклад возможно приведет к уменьшению разрыва между мощью синтаксиса Scala и текущей (седьмой) версией Java как языка программирования. Хотя конечно, даже со всеми новшествами восьмерки Java будет сильно отставать от Scala.

JDK с "Lambda Project" можно скачать c официальной страницы.
Также в текущей сборке JDK 8 (на момент написания статьи) лямбды уже тоже есть, но API с коллекциями еще не полностью завершены.

Целью данной статьи не написание учебного пособия по новым функциям Java, думаю этой работой должны заниматься ребята из Oracle. Здесь я хотел сделать небольшие заметки для себя на будущее вместе с небольшими примерами кода, к которым хотелось бы вернуться после официального выпуска JDK 8.

В бытовом, чисто утилитарном смысле, под этой пресловутой лямбдой (или лямбда-выражениями) многие программисты как правило подразумевают обычные анонимные функции (хотя конечно это не строгое определение). Причем под функцией имеется в виду первоклассный объект. Его можно передавать как объект в аргументы метода, присваивать какой-то переменной и т.д. С точки зрения конечного пользователя (в нашем случае программиста) мы получаем удобный способ сокращать количество строк кода, без сильной потери в его читаемости.

Мои опыты

Один из самых часто встречаемых примеров в интернете, демонстрирующих пользу от использования лямбды — замена старых добрых анонимных классов.
Сравните. Это новый вариант:

   // Вот она, анонимная функция!
   Runnable r = () -> System.out.println("hello");
   Thread th = new Thread(r);
   th.start();

Вот так по-старинке:

   Runnable r = new Runnable() {
        public void run() {
            System.out.println("hello");
        }
   };
   Thread th = new Thread(r);
   th.start();

Естественно и логично применить такой подход для слушателей.
Вот небольшой сниппет с формочкой и кнопкой.

public class Main {
    public static void foo(ActionEvent e) {
        System.out.println("hello:" + e);        
    }
 
    public static void main(String arg[]) throws Exception {
        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton("Hello");
        // магия происходит здесь
        button.addActionListener((ActionEvent e)-> { foo(e); });
 
        frame.getContentPane().add(button, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

Если у вас аллергия на вложенные скобки, то можно упростить следующим образом:

    // Можно присвоить listener-у
    ActionListener listener = (ActionEvent e)->{ foo(e); };
    // а вот так не скомпилируется ;)
    //Object o = (ActionEvent e) -> { foo(e); };
    button.addActionListener(listener);

Или даже можно сделать так:

   button.addActionListener(Main::foo);

Главное никаких отражений, используется invokedynamic.

Естественно возникает желание посмотреть на API коллекций.

Можно использовать в качестве Comparator-а функцию сортировщик:

   String arr[] = {"a","b","c"};
   Arrays.sort(arr, (x, y) -> x.compareToIgnoreCase(y));

Также в Java 8 будет реализация многопоточной сортировки:

  String arr[] = {"a","b","c"};
  Arrays.parallelSort(arr, (x, y) -> x.compareToIgnoreCase(y));

Функциональщики как раз любят такие многопоточные методы. К сожалению, на моих тестах в используемой версии JDK 8 от использования parallelSort польза была только на примитивных данных (например при сортировки массивов int-ов). На массивах с объектами никакой пользы не было, но ведь и релиз только через несколько месяцев, так что сейчас никаких серьезных тестов скорости проводить некорректно.

Итог

Думаю многие согласятся, что восьмерка не скоро будет тотально доминировать на серверах и использоваться в промышленной эксплуатации, поскольку существует довольно большая прослойки особо консервативных Java-программистов. Тем не менее функциональщина сейчас в мировом программистком тренде, поэтому Java 8 это безусловно интересно и имеет смысл потратить в дальнейшем дополнительное время на её изучение.