В java8 появились таки приятные и взамосвязанные между собой вещи, как functional interfaces, lambda functions и streams. Java, конечно, не стала от этого функциональным языком, но некоторые вещи стало писать гораздо проще.
Streams позволяют обрабатывать наборы данных функциональным образом, собирая из функций обрабатывающий конвейер. Streams упрощают работу с коллекциями, в частности такие классические проблемы, как построить коллекцию из значений какого-либо свойства объектов другой коллекции или отобрать из коллекции объекты по какому-либо признаку и т.д. И, что самое приятное, Streams работают не только с коллекциями.
Впрочем, пора показать на практике. Пускай у нас есть список слов:
1 2 3 4 5 6 7 8 9 10 11 | private static final List<String> LONG_WELCOME = Arrays.asList( "Hello", "and", "welcome", "to", "the", "wonderful", "world", "of", "java", "8"); |
И мы хотим из этого списка отобрать все слова, длиной в 5 знаков и объединить результат в строку, разделяя слова запятой.
Раньше это привело бы к двум циклам: в одном фильтруется входящий список слов, в другом результирующий список склеивается в одну строку:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public final String oldSchoolGreet() { List<String> result = new ArrayList<>(); for (String s: LONG_WELCOME) { if (s.length() == WORD_LENGTH) { result.add(s); } } Iterator<String> it = result.iterator(); StringBuilder buf = new StringBuilder(); buf.append(it.next()); while (it.hasNext()) { buf.append(", "); buf.append(it.next()); } return buf.toString(); } |
В прекрасном новом функциональном мире два не очень понятных цикла схопываются в короткое выражение, практически декларативно описывающее что делать с входящим списком:
1 2 3 4 5 6 | public final String greet() { return LONG_WELCOME .stream() .filter(s -> s.length() == WORD_LENGTH) .collect(Collectors.joining(", ")); } |
Проверим, что результат выполнения функций идентичен:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class HelloStreamsTest { private static final String EXPECTED = "Hello, world"; private HelloStreams testedObject = new HelloStreams(); @Test public void testGreet() throws Exception { assertThat(testedObject.greet(), is(EXPECTED)); } @Test public void testOldSchooldGreet() throws Exception { assertThat(testedObject.oldSchoolGreet(), is(EXPECTED)); } } |
Код примера доступен на github.
PS Автор, разумеется, знаком с различными библиотечными реализациями конкатенации коллекций строк в одну строку. Однако моей целью было показать реализации без использования сторонних библиотек.