Friday 4 July 2014

Java 8 и лямбда

Пока в производстве она наверно есть далеко не везде, да и в некоторых местах вообще так и не появится. По крайне мере, лучшие и много-обещающие надежды на нее не возлагают.
Так, ну есть и есть... "Писать не писать - ну можно расписать че та, а вообще ну сами понимаете..."

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

For loop

1
2
3
4
5
6
7
8
9
                // Обычный цикл
  for (Person p : people) {
   System.out.println(p);
  }
  
  // Тоже удобно
  people.forEach(System.out::println);
  people.forEach(p->System.out.println(p.getBirthPlace()));
  

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

::

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


people.removeIf(p->p.getBirthPlace().contains("г.Москва"));

То есть это заменит

1
2
3
4
5
6
                for (Iterator<Person> it = people.iterator(); it.hasNext();) {
   Person p = it.next();
   if (p.getBirthPlace().contains("г.Москва")) {
    it.remove();
   }
  }

Сама ламбда


->

По левую сторону указываются параметры, по правую - реализация метода какого либо.


Predicate
Это что-то новенькое но довольно удобное. Взгляните на следующий код.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 // Поиск в коллекции.
 public static Person findPerson(List<Person> people, Predicate<Person> p) {
  Person found = null;
  
  for (Person person : people) {
   if (p.test(person)) {
    found = person;
    break;
   }
  }
  
  return found;
 }

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


1
2
3
4
5
  // Вариант с Predicate
  Person guyFromLeningrad = findPerson(people, 
    p -> p.getSex().equalsIgnoreCase("MALE") && p.getBirthPlace().contains("г.Ленинград"));
  
  System.out.println(guyFromLeningrad);

По правую сторону от -> тут мы реализуем метод test интерфейса Predicate, в котором как параметр принимается элемент из итерации.

Comparators
Вот пример с комператорами. Но тут дело в то что они как правило часто повторно используются, особенно при сортировки элементов для UI.

Стандартный вариант.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 public static final Comparator<Person> PASSPORT_COMPARATOR = new Comparator<Person>() {
  @Override
  public int compare(Person a, Person b) {
   int date = a.getBirthDate().compareTo(b.getBirthDate());
   if (date == 0) {
    return a.getLastName().compareTo(b.getLastName()) == 0 ? 
      0 : a.getFirstName().compareTo(b.getFirstName());
   }
   return date;
  }
 };

и

1
2
  // Стандартный вариант
  Collections.sort(people, PASSPORT_COMPARATOR);

или


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  // Ламбда-Комператор 
  Collections.sort(people, (a, b) -> {
   int date = a.getBirthDate().compareTo(b.getBirthDate());
   if (date == 0) {
    int last = a.getLastName().compareTo(b.getLastName());
    if (last == 0) {
     return a.getFirstName().compareTo(b.getFirstName());
    }
    return last;
   }
   return date;
  });

Тут все конечно зависит от среды. Если преобладают annonimous реализации, то можно попробовать, а так...? )

No comments:

Post a Comment