В 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 Автор, разумеется, знаком с различными библиотечными реализациями конкатенации коллекций строк в одну строку. Однако моей целью было показать реализации без использования сторонних библиотек.