Программирование ката — это упражнение, которое помогает программисту отточить свои навыки посредством практики и повторения.
Эта статья является частью серии 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 Виктора Фарчича в блоге « Технологии» |