package com.annimon.stream; import com.annimon.stream.function.BinaryOperator; import com.annimon.stream.function.Function; import com.annimon.stream.function.IntSupplier; import com.annimon.stream.function.Supplier; import com.annimon.stream.function.ToDoubleFunction; import com.annimon.stream.function.ToIntFunction; import com.annimon.stream.function.ToLongFunction; import com.annimon.stream.function.UnaryOperator; import static com.annimon.stream.test.hamcrest.CommonMatcher.hasOnlyPrivateConstructors; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Test; /** * Tests {@code Collectors}. * * @see com.annimon.stream.Collectors */ public class CollectorsTest { @Test public void testToCollection() { Collection<Integer> result = Stream.range(0, 5) .collect(Collectors.toCollection(new Supplier<Collection<Integer>>() { @Override public Collection<Integer> get() { return new LinkedList<Integer>(); } })); assertThat(result, contains(0, 1, 2, 3, 4)); assertThat(result, instanceOf(LinkedList.class)); } @Test public void testToList() { List<Integer> expected = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); List<Integer> list = Stream.range(0, 10) .collect(Collectors.<Integer>toList()); assertThat(list, is(expected)); } @Test public void testToSet() { Set<Integer> set = Stream.of(1, 2, 2, 3, 3, 3) .collect(Collectors.<Integer>toSet()); assertThat(set, containsInAnyOrder(1, 2, 3)); } @Test public void testToMapWithDefaultValueMapper() { final Function<String, Character> keyMapper = Functions.firstCharacterExtractor(); Map<Character, String> chars = Stream.of("a", "b", "c", "d") .collect(Collectors.toMap(keyMapper)); assertThat(chars.size(), is(4)); assertThat(chars, allOf( hasEntry('a', "a"), hasEntry('b', "b"), hasEntry('c', "c"), hasEntry('d', "d") )); } @Test public void testToMapWithIdentityValueMapper() { final Function<String, Character> keyMapper = Functions.firstCharacterExtractor(); Map<Character, String> chars = Stream.of("a", "b", "c", "d") .collect(Collectors.toMap(keyMapper, UnaryOperator.Util.<String>identity())); assertThat(chars.size(), is(4)); assertThat(chars, allOf( hasEntry('a', "a"), hasEntry('b', "b"), hasEntry('c', "c"), hasEntry('d', "d") )); } @Test public void testToMapWithCustomValueMapper() { final Function<String, Character> keyMapper = Functions.firstCharacterExtractor(); Map<Character, String> chars = Stream.of("a0", "b0", "c0", "d0") .collect(Collectors.toMap(keyMapper, new UnaryOperator<String>() { @Override public String apply(String value) { if ("c0".equals(value)) return null; return String.valueOf(Character.toUpperCase(value.charAt(0))); } })); assertThat(chars.size(), is(3)); assertThat(chars, allOf( hasEntry('a', "A"), hasEntry('b', "B"), hasEntry('d', "D") )); } @Test public void testJoining() { String text = Stream.of("a", "b", "c", "def", "", "g") .collect(Collectors.joining()); assertEquals("abcdefg", text); } @Test public void testJoiningWithDelimiter() { String text = Stream.of("a", "b", "c", "def", "", "g") .collect(Collectors.joining(", ")); assertEquals("a, b, c, def, , g", text); } @Test public void testJoiningWithDelimiterPrefixAndSuffixEmpty() { String text = Stream.<String>empty() .collect(Collectors.joining(", ", "prefix|", "|suffix", "empty")); assertEquals("empty", text); } @Test public void testJoiningWithDelimiterPrefixAndSuffixEmptyStream() { String text = Stream.<String>empty() .collect(Collectors.joining(", ", "prefix|", "|suffix")); assertEquals("prefix||suffix", text); } @Test public void testJoiningWithDelimiterPrefixAndSuffix() { String text = Stream.of("a", "b", "c", "def", "", "g") .collect(Collectors.joining(", ", "prefix|", "|suffix")); assertEquals("prefix|a, b, c, def, , g|suffix", text); } @Test @SuppressWarnings("deprecation") public void testAveraging() { double avg; avg = Stream.<Integer>empty() .collect(Collectors.averaging(new Function<Integer, Double>() { @Override public Double apply(Integer t) { return t.doubleValue(); } })); assertThat(avg, closeTo(0, 0.001)); avg = Stream.of(10, 20, 30, 40) .collect(Collectors.averaging(new Function<Integer, Double>() { @Override public Double apply(Integer value) { return value / 10d; } })); assertThat(avg, closeTo(2.5, 0.001)); } @Test public void testAveragingInt() { final ToIntFunction<Integer> identity = new ToIntFunction<Integer>() { @Override public int applyAsInt(Integer t) { return t; } }; double avg; avg = Stream.<Integer>empty() .collect(Collectors.averagingInt(identity)); assertThat(avg, closeTo(0, 0.001)); avg = Stream.of(1, 2, 3, 4) .collect(Collectors.averagingInt(identity)); assertThat(avg, closeTo(2.5, 0.001)); avg = Stream.of(Integer.MAX_VALUE, Integer.MAX_VALUE) .collect(Collectors.averagingInt(identity)); assertThat(avg, closeTo(Integer.MAX_VALUE, 0.001)); } @Test public void testAveragingLong() { final ToLongFunction<Integer> identity = new ToLongFunction<Integer>() { @Override public long applyAsLong(Integer t) { return t; } }; double avg; avg = Stream.<Integer>empty() .collect(Collectors.averagingLong(identity)); assertThat(avg, closeTo(0, 0.001)); avg = Stream.of(1, 2, 3, 4) .collect(Collectors.averagingLong(identity)); assertThat(avg, closeTo(2.5, 0.001)); avg = Stream.of(Integer.MAX_VALUE, Integer.MAX_VALUE) .collect(Collectors.averagingLong(identity)); assertThat(avg, closeTo(Integer.MAX_VALUE, 0.001)); } @Test public void testAveragingDouble() { final ToDoubleFunction<Integer> intToDoubleFunction = new ToDoubleFunction<Integer>() { @Override public double applyAsDouble(Integer t) { return t.doubleValue(); } }; double avg; avg = Stream.<Integer>empty() .collect(Collectors.averagingDouble(intToDoubleFunction)); assertThat(avg, closeTo(0, 0.001)); avg = Stream.of(1, 2, 3, 4) .collect(Collectors.averagingDouble(intToDoubleFunction)); assertThat(avg, closeTo(2.5, 0.001)); } @Test public void testSummingInt() { final ToIntFunction<Integer> identity = new ToIntFunction<Integer>() { @Override public int applyAsInt(Integer t) { return t; } }; int sum; sum = Stream.<Integer>empty() .collect(Collectors.summingInt(identity)); assertThat(sum, is(0)); sum = Stream.of(1, 2, 3, 4) .collect(Collectors.summingInt(identity)); assertThat(sum, is(10)); } @Test public void testSummingLong() { final ToLongFunction<Long> identity = new ToLongFunction<Long>() { @Override public long applyAsLong(Long t) { return t; } }; long sum; sum = Stream.<Long>empty() .collect(Collectors.summingLong(identity)); assertThat(sum, is(0L)); sum = Stream.of(1L, 2L, 3L, 4L) .collect(Collectors.summingLong(identity)); assertThat(sum, is(10L)); sum = Stream.of(1L, Long.MAX_VALUE - 1) .collect(Collectors.summingLong(identity)); assertThat(sum, is(Long.MAX_VALUE)); } @Test public void testSummingDouble() { final ToDoubleFunction<Double> identity = new ToDoubleFunction<Double>() { @Override public double applyAsDouble(Double t) { return t; } }; double sum; sum = Stream.<Double>empty() .collect(Collectors.summingDouble(identity)); assertThat(sum, closeTo(0, 0.001)); sum = Stream.of(1d, 2d, 3d, 4d) .collect(Collectors.summingDouble(identity)); assertThat(sum, closeTo(10, 0.001)); } @Test public void testCounting() { long count = Stream.range(0, 20) .collect(Collectors.counting()); assertEquals(20, count); } @Test public void testReducingMultiply() { long production = Stream.of(1, 2, 3, 4, 5).collect( Collectors.reducing(1, new BinaryOperator<Integer>() { @Override public Integer apply(Integer value1, Integer value2) { return value1 * value2; } }) ); assertEquals(120, production); } @Test public void testReducingSumDivision() { double sumDiv = Stream.of(1, 2, 3, 4, 5).collect( Collectors.reducing(0d, new Function<Integer, Double>() { @Override public Double apply(Integer value) { return 1d / value; } }, new BinaryOperator<Double>() { @Override public Double apply(Double value1, Double value2) { return value1 + value2; } }) ); assertThat(sumDiv, closeTo(2.28, 0.01)); } @Test public void testGroupingBy() { final Integer partitionItem = 1; List<Integer> items = Arrays.asList(1, 2, 3, 1, 2, 3, 1, 2, 3); Map<Boolean, List<Integer>> groupedBy = Stream.of(items) .collect(Collectors.groupingBy(Functions.equalityPartitionItem(partitionItem))); assertThat(groupedBy, allOf( hasEntry(true, Arrays.asList(1, 1, 1)), hasEntry(false, Arrays.asList(2, 3, 2, 3, 2, 3)) )); } @Test public void testGroupingByCounting() { Map<Integer, Long> byCounting = Stream.of(1, 2, 2, 3, 3, 3, 4, 4, 4, 4) .collect(Collectors.groupingBy( UnaryOperator.Util.<Integer>identity(), Collectors.counting())); assertThat(byCounting, allOf( hasEntry(1, 1L), hasEntry(2, 2L), hasEntry(3, 3L), hasEntry(4, 4L) )); } @Test public void testGroupingByStudentSpeciality() { Map<String, List<Student>> bySpeciality = Stream.of(Students.ALL) .collect(Collectors.groupingBy(Students.speciality)); assertThat(bySpeciality.get("CS"), is(Arrays.asList( Students.STEVE_CS_4, Students.VICTORIA_CS_3, Students.JOHN_CS_2, Students.MARIA_CS_1 ))); assertThat(bySpeciality.get("Economics"), is(Arrays.asList( Students.MARIA_ECONOMICS_1, Students.SERGEY_ECONOMICS_2, Students.SOPHIA_ECONOMICS_2 ))); assertThat(bySpeciality.get("Law"), is(Arrays.asList( Students.GEORGE_LAW_3, Students.SERGEY_LAW_1 ))); } @Test public void testGroupingByStudentCourse() { Map<Integer, List<Student>> byCourse = Stream.of(Students.ALL) .collect(Collectors.groupingBy(Students.course)); assertThat(byCourse.get(1), is(Arrays.asList( Students.MARIA_ECONOMICS_1, Students.SERGEY_LAW_1, Students.MARIA_CS_1 ))); assertThat(byCourse.get(2), is(Arrays.asList( Students.JOHN_CS_2, Students.SERGEY_ECONOMICS_2, Students.SOPHIA_ECONOMICS_2 ))); assertThat(byCourse.get(3), is(Arrays.asList( Students.VICTORIA_CS_3, Students.GEORGE_LAW_3 ))); assertThat(byCourse.get(4), is(Arrays.asList( Students.STEVE_CS_4 ))); } @Test public void testGroupingByStudentSpecialityAndCourse() { Map<String, Map<Integer, List<Student>>> bySpecialityAndCourse = Stream.of(Students.ALL) .collect(Collectors.groupingBy(Students.speciality, Collectors.groupingBy(Students.course))); assertThat(bySpecialityAndCourse.get("Economics").get(2), is(Arrays.asList( Students.SERGEY_ECONOMICS_2, Students.SOPHIA_ECONOMICS_2 ))); } @Test public void testGroupingByStudentCourseCounting() { Map<Integer, Long> byCourseCounting = Stream.of(Students.ALL) .collect(Collectors.groupingBy(Students.course, Collectors.counting())); assertThat(byCourseCounting, allOf( hasEntry(1, 3L), hasEntry(2, 3L), hasEntry(3, 2L), hasEntry(4, 1L) )); } @Test public void testFiltering() { List<Integer> list; list = Stream.rangeClosed(1, 6) .collect( Collectors.filtering(Functions.remainder(2), Collectors.<Integer>toList()) ); assertThat(list, contains(2, 4, 6)); list = Stream.rangeClosed(1, 6) .collect( Collectors.filtering(Functions.remainder(20), Collectors.<Integer>toList()) ); assertThat(list, is(empty())); list = Stream.<Integer>empty() .collect( Collectors.filtering(Functions.remainder(20), Collectors.<Integer>toList()) ); assertThat(list, is(empty())); } @Test public void testMappingSquareIntToString() { Function<Integer, String> squareToString = new Function<Integer, String>() { @Override public String apply(Integer value) { return Integer.toString(value * value); } }; String result = Stream.of(1, 2, 3, 4) .collect( Collectors.mapping(squareToString, Collectors.joining(", ")) ); assertEquals("1, 4, 9, 16", result); } @Test public void testMappingStudentNamesBySpeciality() { Map<String, Set<String>> namesBySpeciality = Stream.of(Students.ALL) .collect(Collectors.groupingBy(Students.speciality, Collectors.mapping(Students.studentName, Collectors.<String>toSet()))); assertThat(namesBySpeciality.get("Economics"), containsInAnyOrder(new String[] { Students.MARIA_ECONOMICS_1.getName(), Students.SERGEY_ECONOMICS_2.getName(), Students.SOPHIA_ECONOMICS_2.getName() })); assertThat(namesBySpeciality.get("CS"), containsInAnyOrder(new String[] { Students.STEVE_CS_4.getName(), Students.VICTORIA_CS_3.getName(), Students.JOHN_CS_2.getName(), Students.MARIA_CS_1.getName() })); assertThat(namesBySpeciality.get("Law"), containsInAnyOrder(new String[] { Students.GEORGE_LAW_3.getName(), Students.SERGEY_LAW_1.getName() })); } @Test public void testFlatMapping() { Function<Integer, Stream<Integer>> repeaterFunction = new Function<Integer, Stream<Integer>>() { @Override public Stream<Integer> apply(final Integer value) { if (value < 0) return null; if (value == 0) return Stream.empty(); return IntStream.generate(new IntSupplier() { @Override public int getAsInt() { return value; } }).limit(value).boxed(); } }; List<Integer> list; list = Stream.of(1, 2, 3, 4) .collect( Collectors.flatMapping(repeaterFunction, Collectors.<Integer>toList()) ); assertThat(list, contains(1, 2, 2, 3, 3, 3, 4, 4, 4, 4)); list = Stream.of(-1, -1) .collect( Collectors.flatMapping(repeaterFunction, Collectors.<Integer>toList()) ); assertThat(list, is(empty())); list = Stream.of(0, 0) .collect( Collectors.flatMapping(repeaterFunction, Collectors.<Integer>toList()) ); assertThat(list, is(empty())); list = Stream.of(2, 0, 3, -4) .collect( Collectors.flatMapping(repeaterFunction, Collectors.<Integer>toList()) ); assertThat(list, contains(2, 2, 3, 3, 3)); } @Test public void testCollectingAndThen() { List<Integer> result = Stream.of(1, 2, 3, 4).collect( Collectors.collectingAndThen(Collectors.<Integer>toList(), new UnaryOperator<List<Integer>>() { @Override public List<Integer> apply(List<Integer> list) { return new LinkedList<Integer>(list); } }) ); assertThat(result, instanceOf(LinkedList.class)); } @Test public void testPrivateConstructor() throws Exception { assertThat(Collectors.class, hasOnlyPrivateConstructors()); } }