编程kata是一种练习,可以帮助程序员通过练习和重复练习来磨练自己的技能。
本文是“ 通过Katas进行Java教程 ”系列的一部分。
本文假定读者已经具有Java的经验,熟悉单元测试的基础知识,并且知道如何从他最喜欢的IDE(我是IntelliJ IDEA )运行它们。
下面显示的练习背后的想法是,使用测试驱动的开发方法来学习Java 8 Streaming(编写第一个测试的实现,确认它通过并转到下一个测试)。
每个部分都将以测试形式的目标开始,以证明实现一旦编写便是正确的。 这些测试中的每一个都在Java 7(或更早版本)和Java 8中使用Streams进行了一种可能的实现。 这样,读者可以将Java 8的某些新功能与早期JDK中的等效功能进行比较。 请尝试解决测试,而不查看提供的解决方案。
有关TDD最佳实践的更多信息,请阅读“ 测试驱动开发(TDD):使用Java示例的最佳实践” 。
Java 8地图
将集合的元素转换为大写。
测验
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)实现
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个字符的元素。
测验
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)实现
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
展平多维集合。
测验
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)实现
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 Max和比较器
从集合中获取最老的人。
测验
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)实现
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之和
对集合的所有元素求和。
测验
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(calculate7)和Java8(calculate)实现
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岁以下)的名字。
测验
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)实现
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摘要统计
获取人员统计信息:平均年龄,人数,最大年龄,最小年龄和所有年龄的总和。
测验
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)实现
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分区
分区成人和孩子。
测验
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)实现
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分组
按国籍分组人。
测验
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)实现
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加入
返回用逗号分隔的人名。
测验
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)实现
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,除其他外,build.gradle可用于下载AssertJ依赖项并运行测试。
翻译自: https://www.javacodegeeks.com/2014/11/java-8-streams-micro-katas.html