Программирование ката — это упражнение, которое помогает программисту отточить свои навыки посредством практики и повторения.
Эта статья является частью серии Java Tutorial Through Katas .
В статье предполагается, что читатель уже имеет опыт работы с Java, что он знаком с основами модульных тестов и знает, как запускать их из своей любимой среды IDE (моя — IntelliJ IDEA ).
Идея, стоящая за упражнениями, показанными ниже, заключается в изучении потоковой передачи Java 8 с использованием подхода разработки, основанного на тестировании (напишите реализацию для первого теста, подтвердите, что он прошел, и перейдите к следующему).
Каждый раздел будет начинаться с цели в виде тестов, которые доказывают, что реализация будет правильной после ее написания. Каждый из этих тестов сопровождается одной возможной реализацией в Java 7 (или более ранней версии) и Java 8 с использованием Streams. Таким образом, читатель может сравнить некоторые из новых функций Java 8 с их эквивалентами в более ранних версиях JDK. Пожалуйста, попробуйте выполнить тесты, не глядя на предоставленные решения.
Для получения дополнительной информации о передовых методах TDD, пожалуйста, прочитайте Test Driven Development (TDD): Лучшие практики с использованием примеров Java .
Карта Java 8
Преобразуйте элементы коллекции в верхний регистр.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.ToUpperCase.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Convert elements of a collection to upper case. */public class ToUpperCaseSpec { @Test public void transformShouldConvertCollectionElementsToUpperCase() { List<String> collection = asList("My"< "name"< "is"< "John"< "Doe"); List<String> expected = asList("MY"< "NAME"< "IS"< "JOHN"< "DOE"); assertThat(transform(collection)).hasSameElementsAs(expected); }} |
Реализации Java 7 (transform7) и Java8 (transform)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.technologyconversations.java8exercises.streams;import java.util.ArrayList;import java.util.List;import static java.util.stream.Collectors.toList;public class ToUpperCase { public static List<String> transform7(List<String> collection) { List<String> coll = new ArrayList<>(); for (String element : collection) { coll.add(element.toUpperCase()); } return coll; } public static List<String> transform(List<String> collection) { return collection.stream() // Convert collection to Stream .map(String::toUpperCase) // Convert each element to upper case .collect(toList()); // Collect results to a new list }} |
Фильтр Java 8
Отфильтруйте коллекцию так, чтобы возвращались только элементы длиной менее 4 символов.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.FilterCollection.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Filter collection so that only elements with less then 4 characters are returned. */public class FilterCollectionSpec { @Test public void transformShouldFilterCollection() { List<String> collection = asList("My", "name", "is", "John", "Doe"); List<String> expected = asList("My", "is", "Doe"); assertThat(transform(collection)).hasSameElementsAs(expected); }} |
Реализации Java 7 (transform7) и Java8 (transform)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.technologyconversations.java8exercises.streams;import java.util.ArrayList;import java.util.List;import static java.util.stream.Collectors.toList;public class FilterCollection { public static List<String> transform7(List<String> collection) { List<String> newCollection = new ArrayList<>(); for (String element : collection) { if (element.length() < 4) { newCollection.add(element); } } return newCollection; } public static List<String> transform(List<String> collection) { return collection.stream() // Convert collection to Stream .filter(value -> value.length() < 4) // Filter elements with length smaller than 4 characters .collect(toList()); // Collect results to a new list }} |
Java 8 flatMap
Свести многомерную коллекцию.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.FlatCollection.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Flatten multidimensional collection */public class FlatCollectionSpec { @Test public void transformShouldFlattenCollection() { List<List<String>> collection = asList(asList("Viktor", "Farcic"), asList("John", "Doe", "Third")); List<String> expected = asList("Viktor", "Farcic", "John", "Doe", "Third"); assertThat(transform(collection)).hasSameElementsAs(expected); }} |
Реализации Java 7 (transform7) и Java8 (transform)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.technologyconversations.java8exercises.streams;import java.util.ArrayList;import java.util.List;import static java.util.stream.Collectors.toList;public class FlatCollection { public static List<String> transform7(List<List<String>> collection) { List<String> newCollection = new ArrayList<>(); for (List<String> subCollection : collection) { for (String value : subCollection) { newCollection.add(value); } } return newCollection; } public static List<String> transform(List<List<String>> collection) { return collection.stream() // Convert collection to Stream .flatMap(value -> value.stream()) // Replace list with stream .collect(toList()); // Collect results to a new list }} |
Java 8 Макс и компаратор
Получить старейшего человека из коллекции.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.OldestPerson.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Get oldest person from the collection */public class OldestPersonSpec { @Test public void getOldestPersonShouldReturnOldestPerson() { Person sara = new Person("Sara", 4); Person viktor = new Person("Viktor", 40); Person eva = new Person("Eva", 42); List<Person> collection = asList(sara, eva, viktor); assertThat(getOldestPerson(collection)).isEqualToComparingFieldByField(eva); }} |
Реализации Java 7 (getOldestPerson7) и Java8 (getOldestPerson)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.technologyconversations.java8exercises.streams;import java.util.Comparator;import java.util.List;public class OldestPerson { public static Person getOldestPerson7(List<Person> people) { Person oldestPerson = new Person("", 0); for (Person person : people) { if (person.getAge() > oldestPerson.getAge()) { oldestPerson = person; } } return oldestPerson; } public static Person getOldestPerson(List<Person> people) { return people.stream() // Convert collection to Stream .max(Comparator.comparing(Person::getAge)) // Compares people ages .get(); // Gets stream result }} |
Java 8 сумма и уменьшение
Суммируйте все элементы коллекции.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.Sum.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Sum all elements of a collection */public class SumSpec { @Test public void transformShouldConvertCollectionElementsToUpperCase() { List<Integer> numbers = asList(1, 2, 3, 4, 5); assertThat(calculate(numbers)).isEqualTo(1 + 2 + 3 + 4 + 5); }} |
Реализации Java 7 (вычисления7) и Java8 (вычисления)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
package com.technologyconversations.java8exercises.streams;import java.util.List;public class Sum { public static int calculate7(List<Integer> numbers) { int total = 0; for (int number : numbers) { total += number; } return total; } public static int calculate(List<Integer> people) { return people.stream() // Convert collection to Stream .reduce(0, (total, number) -> total + number); // Sum elements with 0 as starting value }} |
Фильтр и карта Java 8
Получить имена всех детей (в возрасте до 18 лет).
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.Kids.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Get names of all kids (under age of 18) */public class KidsSpec { @Test public void getKidNameShouldReturnNamesOfAllKidsFromNorway() { Person sara = new Person("Sara", 4); Person viktor = new Person("Viktor", 40); Person eva = new Person("Eva", 42); Person anna = new Person("Anna", 5); List<Person> collection = asList(sara, eva, viktor, anna); assertThat(getKidNames(collection)) .contains("Sara", "Anna") .doesNotContain("Viktor", "Eva"); }} |
Java 7 (getKidNames7) и Java8 (getKidNames) реализации
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.technologyconversations.java8exercises.streams;import java.util.*;import static java.util.stream.Collectors.toSet;public class Kids { public static Set<String> getKidNames7(List<Person> people) { Set<String> kids = new HashSet<>(); for (Person person : people) { if (person.getAge() < 18) { kids.add(person.getName()); } } return kids; } public static Set<String> getKidNames(List<Person> people) { return people.stream() .filter(person -> person.getAge() < 18) // Filter kids (under age of 18) .map(Person::getName) // Map Person elements to names .collect(toSet()); // Collect values to a Set }} |
Java 8 summaryStatistics
Получить статистику людей: средний возраст, количество, максимальный возраст, минимальный возраст и сумма всех возрастов.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.PeopleStats.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Get people statistics: average age, count, maximum age, minimum age and sum og all ages. */public class PeopleStatsSpec { Person sara = new Person("Sara", 4); Person viktor = new Person("Viktor", 40); Person eva = new Person("Eva", 42); List<Person> collection = asList(sara, eva, viktor); @Test public void getStatsShouldReturnAverageAge() { assertThat(getStats(collection).getAverage()) .isEqualTo((double)(4 + 40 + 42) / 3); } @Test public void getStatsShouldReturnNumberOfPeople() { assertThat(getStats(collection).getCount()) .isEqualTo(3); } @Test public void getStatsShouldReturnMaximumAge() { assertThat(getStats(collection).getMax()) .isEqualTo(42); } @Test public void getStatsShouldReturnMinimumAge() { assertThat(getStats(collection).getMin()) .isEqualTo(4); } @Test public void getStatsShouldReturnSumOfAllAges() { assertThat(getStats(collection).getSum()) .isEqualTo(40 + 42 + 4); }} |
Реализации Java 7 (getStats7) и Java8 (getStats)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package com.technologyconversations.java8exercises.streams;import java.util.IntSummaryStatistics;import java.util.List;public class PeopleStats { public static Stats getStats7(List<Person> people) { long sum = 0; int min = people.get(0).getAge(); int max = 0; for (Person person : people) { int age = person.getAge(); sum += age; min = Math.min(min, age); max = Math.max(max, age); } return new Stats(people.size(), sum, min, max); } public static IntSummaryStatistics getStats(List<Person> people) { return people.stream() .mapToInt(Person::getAge) .summaryStatistics(); }} |
Java 8 partitioningBy
Разделение взрослых и детей.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import java.util.Map;import static com.technologyconversations.java8exercises.streams.Partitioning.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Partition adults and kids */public class PartitioningSpec { @Test public void partitionAdultsShouldSeparateKidsFromAdults() { Person sara = new Person("Sara", 4); Person viktor = new Person("Viktor", 40); Person eva = new Person("Eva", 42); List<Person> collection = asList(sara, eva, viktor); Map<Boolean, List<Person>> result = partitionAdults(collection); assertThat(result.get(true)).hasSameElementsAs(asList(viktor, eva)); assertThat(result.get(false)).hasSameElementsAs(asList(sara)); }} |
Java 7 (partitionAdults7) и Java8 (partitionAdults) реализации
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.technologyconversations.java8exercises.streams;import java.util.*;import static java.util.stream.Collectors.*;public class Partitioning { public static Map<Boolean, List<Person>> partitionAdults7(List<Person> people) { Map<Boolean, List<Person>> map = new HashMap<>(); map.put(true, new ArrayList<>()); map.put(false, new ArrayList<>()); for (Person person : people) { map.get(person.getAge() >= 18).add(person); } return map; } public static Map<Boolean, List<Person>> partitionAdults(List<Person> people) { return people.stream() // Convert collection to Stream .collect(partitioningBy(p -> p.getAge() >= 18)); // Partition stream of people into adults (age => 18) and kids }} |
Java 8 groupingBy
Группировка людей по национальности.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import java.util.Map;import static com.technologyconversations.java8exercises.streams.Grouping.*;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Group people by nationality */public class GroupingSpec { @Test public void partitionAdultsShouldSeparateKidsFromAdults() { Person sara = new Person("Sara", 4, "Norwegian"); Person viktor = new Person("Viktor", 40, "Serbian"); Person eva = new Person("Eva", 42, "Norwegian"); List<Person> collection = asList(sara, eva, viktor); Map<String, List<Person>> result = groupByNationality(collection); assertThat(result.get("Norwegian")).hasSameElementsAs(asList(sara, eva)); assertThat(result.get("Serbian")).hasSameElementsAs(asList(viktor)); }} |
Java 7 (groupByNationality7) и Java8 (groupByNationality) реализации
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.technologyconversations.java8exercises.streams;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import static java.util.stream.Collectors.*;public class Grouping { public static Map<String, List<Person>> groupByNationality7(List<Person> people) { Map<String, List<Person>> map = new HashMap<>(); for (Person person : people) { if (!map.containsKey(person.getNationality())) { map.put(person.getNationality(), new ArrayList<>()); } map.get(person.getNationality()).add(person); } return map; } public static Map<String, List<Person>> groupByNationality(List<Person> people) { return people.stream() // Convert collection to Stream .collect(groupingBy(Person::getNationality)); // Group people by nationality }} |
Java 8 присоединяется
Вернуть имена людей через запятую.
тесты
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.technologyconversations.java8exercises.streams;import org.junit.Test;import java.util.List;import static com.technologyconversations.java8exercises.streams.Joining.namesToString;import static java.util.Arrays.asList;import static org.assertj.core.api.Assertions.assertThat;/*Return people names separated by comma */public class JoiningSpec { @Test public void toStringShouldReturnPeopleNamesSeparatedByComma() { Person sara = new Person("Sara", 4); Person viktor = new Person("Viktor", 40); Person eva = new Person("Eva", 42); List<Person> collection = asList(sara, viktor, eva); assertThat(namesToString(collection)) .isEqualTo("Names: Sara, Viktor, Eva."); }} |
Реализации Java 7 (namesToString7) и Java8 (namesToString)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.technologyconversations.java8exercises.streams;import java.util.List;import static java.util.stream.Collectors.joining;public class Joining { public static String namesToString7(List<Person> people) { String label = "Names: "; StringBuilder sb = new StringBuilder(label); for (Person person : people) { if (sb.length() > label.length()) { sb.append(", "); } sb.append(person.getName()); } sb.append("."); return sb.toString(); } public static String namesToString(List<Person> people) { return people.stream() // Convert collection to Stream .map(Person::getName) // Map Person to name .collect(joining(", ", "Names: ", ".")); // Join names }} |
Источник
Полный исходный код находится в репозитории GitHub https://github.com/vfarcic/java-8-exercises . Помимо тестов и реализации, репозиторий включает build.gradle, который может использоваться, среди прочего, для загрузки зависимостей AssertJ и запуска тестов.
| Ссылка: | Java 8 Streams: Micro Katas от нашего партнера по JCG Виктора Фарчича в блоге « Технологии» |