Метка: lambda

  • Java и лямбда-выражения.

    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 это безусловно интересно и имеет смысл потратить в дальнейшем дополнительное время на её изучение.