Blog-Archiv

Mittwoch, 12. Januar 2022

Functional Java Streams Cheat Sheet

Java, since version 8, has become a hybrid language, being both object-oriented and functional. Thus you can implement even loops and conditions now in a style that looks very different from conventional source code.

In this article I want to study the most important Java Stream functions, because without knowing them, you may have problems to understand nowadays code. Mind that some stream functions return Optional objects (to avoid NullPointerExceptions in the caller), so we need to know that too.


Below you find a short example for each of the most important stream functions. They are organized in expandable boxes, please click on the left-side arrows to see explanations and content. You can copy the classes in your Java IDE (Eclipse, ...) and try them out, they are normal unit tests.

  • Vehicle.java is the test subject. Streams of vehicles get processed in different ways.
  • FunctionsTestBase.java contains three test vehicles and is the super-class of ...
    • StreamCreations.java shows how streams can be created.
    • IntermediateOperations.java shows functions that do not close the stream but return a follower stream.
    • TerminalOperations.java shows functions that close the stream, but may generate some kind of Collection or Map that can be streamed further.

Vehicle.java
Test objects are vehicles, having a name, seats, wheels, maybe a motor, and one can set a ranking on them.
Field name
public final String name;
Field seats
public final int seats;
Field wheels
public final int wheels;
Field motorized
public final boolean motorized;
Field ranking
private int ranking;
Constructor (name, seats, wheels, motorized)
public Vehicle(String name, int seats, int wheels, boolean motorized) {
    this.name = name;
    this.seats = seats;
    this.wheels = wheels;
    this.motorized = motorized;
}
Method getRanking()
public int getRanking() {
    return ranking;
}
Method setRanking(ranking)
public void setRanking(int ranking) {
    this.ranking = ranking;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Vehicle
{
    public final String name;
    public final int seats;
    public final int wheels;
    public final boolean motorized;
    
    private int ranking;
    
    public Vehicle(String name, int seats, int wheels, boolean motorized) {
        this.name = name;
        this.seats = seats;
        this.wheels = wheels;
        this.motorized = motorized;
    }
    
    public int getRanking() {
        return ranking;
    }
    public void setRanking(int ranking) {
        this.ranking = ranking;
    }
}

FunctionsTestBase.java
Base class for all tests, containing test data.
A bicycle has one seat and two wheels, it is not motorized.
protected final Vehicle bicycle    = new Vehicle("bicycle",    1, 2, false);
A motorcycle has two seats and two wheels, and is motorized.
protected final Vehicle motorcycle = new Vehicle("motorcycle", 2, 2, true);
A car has four seats and four wheels, and is motorized.
protected final Vehicle car        = new Vehicle("car",        4, 4, true);
1
2
3
4
5
6
7
8
9
public class FunctionsTestBase
{
    /** A bicycle has one seat and two wheels, it is not motorized. */
    protected final Vehicle bicycle    = new Vehicle("bicycle",    1, 2, false);    // name, seats, wheels, motorized
    /** A motorcycle has two seats and two wheels, and is motorized. */
    protected final Vehicle motorcycle = new Vehicle("motorcycle", 2, 2, true);
    /** A car has four seats and four wheels, and is motorized. */
    protected final Vehicle car        = new Vehicle("car",        4, 4, true);
}

StreamCreations.java
Creation functions create a new stream from a collection or an array.
Interface Collection directly provides a stream() method.
@Test
public void streamFromCollection()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream();
    assertEquals(3, stream.count());
}
Use either Map.entrySet(), Map.keySet() or Map.values() to call a stream() method.
@Test
public void streamFromMap()    {
    Map<String,Vehicle> manufacturers = Map.of(
            "Trek",   bicycle,
            "Yamaha", motorcycle,
            "Ford",   car);
    Stream<Map.Entry<String,Vehicle>> stream = manufacturers.entrySet().stream();
    assertEquals(3, stream.count());
}
For arrays, use either Arrays.stream() or Stream.of().
@Test
public void streamFromArray()    {
    Vehicle[] vehicles = {
            bicycle,
            motorcycle,
            car
        };
    Stream<Vehicle> stream = Arrays.stream(vehicles);
    assertEquals(3, stream.count());
    
    Stream<Vehicle> stream2 = Stream.of(vehicles);
    assertEquals(3, stream2.count());
}
There is a builder for streams.
@Test
public void streamFromBuilder()    {
    Stream<Vehicle> stream = Stream.<Vehicle>builder()
            .add(bicycle)
            .add(motorcycle)
            .add(car)
            .build();
    assertEquals(3, stream.count());
}
Optional provides a stream for one element.
@Test
public void streamFromOptional()    {
    Stream<Vehicle> stream = Optional.ofNullable((Vehicle) null).stream();
    assertEquals(0, stream.count());
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
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
52
53
54
55
56
57
public class StreamCreations extends FunctionsTestBase
{
    /** Interface Collection directly provides a stream() method. */
    @Test
    public void streamFromCollection()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream();
        assertEquals(3, stream.count());
    }

    /** Use either Map.entrySet(), Map.keySet() or Map.values() to call a stream() method. */
    @Test
    public void streamFromMap()    {
        Map<String,Vehicle> manufacturers = Map.of(
                "Trek",   bicycle,
                "Yamaha", motorcycle,
                "Ford",   car);
        Stream<Map.Entry<String,Vehicle>> stream = manufacturers.entrySet().stream();
        assertEquals(3, stream.count());
    }
    
    /** For arrays, use either Arrays.stream() or Stream.of(). */
    @Test
    public void streamFromArray()    {
        Vehicle[] vehicles = {
                bicycle,
                motorcycle,
                car
            };
        Stream<Vehicle> stream = Arrays.stream(vehicles);
        assertEquals(3, stream.count());
        
        Stream<Vehicle> stream2 = Stream.of(vehicles);
        assertEquals(3, stream2.count());
    }
    
    /** There is a builder for streams. */
    @Test
    public void streamFromBuilder()    {
        Stream<Vehicle> stream = Stream.<Vehicle>builder()
                .add(bicycle)
                .add(motorcycle)
                .add(car)
                .build();
        assertEquals(3, stream.count());
    }
    
    /** Optional provides a stream for one element. */
    @Test
    public void streamFromOptional()    {
        Stream<Vehicle> stream = Optional.ofNullable((Vehicle) null).stream();
        assertEquals(0, stream.count());
    }
}

IntermediateOperations.java
Intermediate functions are called on a stream and always return a new stream.
filter() is to remove elements from stream.
@Test
public void filterRemovesElementsByCondition()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().filter(vehicle -> vehicle.wheels == 4);
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(1, results.length);
    assertEquals(car.name, results[0].name);
}
map() is to convert every element in stream to another type.
@Test
public void mapConvertsAllElements()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Boolean> stream = vehicles.stream().map(vehicle -> vehicle.motorized);
    
    Boolean[] motorized = stream.toArray(Boolean[]::new);
    assertArrayEquals(new Boolean[] { false, true, true }, motorized);
}
peek() is to execute a function on every element in stream.
@Test
public void peekExecutesOnAllElements()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().peek(vehicle -> vehicle.setRanking(-1));
    
    for (Vehicle result : stream.toArray(Vehicle[]::new))
        assertEquals(-1, result.getRanking());
}
sorted() is to sort the elements in stream.
@Test
public void sortedSortsElements()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().sorted((v1, v2) -> v2.seats - v1.seats);    // highest first
    
    Vehicle[] sorted = stream.toArray(Vehicle[]::new);
    assertEquals(car, sorted[0]);
    assertEquals(motorcycle, sorted[1]);
    assertEquals(bicycle, sorted[2]);
}
distinct() is to remove duplicate elements in stream.
@Test
public void distinctRemovesDuplicateElements()    {
    Collection<Vehicle> vehicles = List.of(    // need list to allow duplicates
            motorcycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().distinct();
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(2, results.length);
    assertEquals(motorcycle, results[0]);
    assertEquals(car, results[1]);
}
flatMap() is for replacing every stream element by 1-n elements from a sub-stream.
@Test
public void flatMapReplacesElementsBySeveralOthers()    {
    Collection<Vehicle> vehicles = Set.of(
            car);
    Vehicle ford = new Vehicle("Ford", 4, 4, true);
    Vehicle mercedes = new Vehicle("Mercedes", 4, 4, true);
    Stream<Vehicle> stream = vehicles.stream().flatMap(vehicle -> Stream.of(ford, mercedes));
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(2, results.length);
    assertEquals(ford, results[0]);
    assertEquals(mercedes, results[1]);
}
takeWhile() is to remove stream elements after a condition became false.
@Test
public void takeWhileRemovesElementsAfterCondition()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().takeWhile(vehicle -> vehicle.seats < 2);
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(1, results.length);
    assertEquals(bicycle, results[0]);
}
dropWhile() is to remove stream elements until a condition becomes true.
@Test
public void dropWhileRemovesElementsUntilCondition()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().dropWhile(vehicle -> vehicle.seats < 2);
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(2, results.length);
    assertEquals(motorcycle, results[0]);
    assertEquals(car, results[1]);
}
skip() is to remove a certain number of stream elements.
@Test
public void skipJumpsOverElements()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().skip(2);
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(1, results.length);
    assertEquals(car, results[0]);
}
limit() is to remove stream elements after a certain index.
@Test
public void limitBreaksAfterElements()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Stream<Vehicle> stream = vehicles.stream().limit(1);
    
    Vehicle[] results = stream.toArray(Vehicle[]::new);
    assertEquals(1, results.length);
    assertEquals(bicycle, results[0]);
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
public class IntermediateOperations extends FunctionsTestBase
{
    /** filter() is to remove elements from stream. */
    @Test
    public void filterRemovesElementsByCondition()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().filter(vehicle -> vehicle.wheels == 4);
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(1, results.length);
        assertEquals(car.name, results[0].name);
    }

    /** map() is to convert every element in stream to another type. */
    @Test
    public void mapConvertsAllElements()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Boolean> stream = vehicles.stream().map(vehicle -> vehicle.motorized);
        
        Boolean[] motorized = stream.toArray(Boolean[]::new);
        assertArrayEquals(new Boolean[] { false, true, true }, motorized);
    }

    /** peek() is to execute a function on every element in stream. */
    @Test
    public void peekExecutesOnAllElements()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().peek(vehicle -> vehicle.setRanking(-1));
        
        for (Vehicle result : stream.toArray(Vehicle[]::new))
            assertEquals(-1, result.getRanking());
    }

    /** sorted() is to sort the elements in stream. */
    @Test
    public void sortedSortsElements()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().sorted((v1, v2) -> v2.seats - v1.seats);    // highest first
        
        Vehicle[] sorted = stream.toArray(Vehicle[]::new);
        assertEquals(car, sorted[0]);
        assertEquals(motorcycle, sorted[1]);
        assertEquals(bicycle, sorted[2]);
    }

    /** distinct() is to remove duplicate elements in stream. */
    @Test
    public void distinctRemovesDuplicateElements()    {
        Collection<Vehicle> vehicles = List.of(    // need list to allow duplicates
                motorcycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().distinct();
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(2, results.length);
        assertEquals(motorcycle, results[0]);
        assertEquals(car, results[1]);
    }

    /** flatMap() is for replacing every stream element by 1-n elements from a sub-stream. */
    @Test
    public void flatMapReplacesElementsBySeveralOthers()    {
        Collection<Vehicle> vehicles = Set.of(
                car);
        Vehicle ford = new Vehicle("Ford", 4, 4, true);
        Vehicle mercedes = new Vehicle("Mercedes", 4, 4, true);
        Stream<Vehicle> stream = vehicles.stream().flatMap(vehicle -> Stream.of(ford, mercedes));
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(2, results.length);
        assertEquals(ford, results[0]);
        assertEquals(mercedes, results[1]);
    }

    /** takeWhile() is to remove stream elements after a condition became true. */
    @Test
    public void takeWhileRemovesElementsAfterCondition()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().takeWhile(vehicle -> vehicle.seats < 2);
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(1, results.length);
        assertEquals(bicycle, results[0]);
    }

    /** dropWhile() is to remove stream elements until a condition becomes true. */
    @Test
    public void dropWhileRemovesElementsUntilCondition()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().dropWhile(vehicle -> vehicle.seats < 2);
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(2, results.length);
        assertEquals(motorcycle, results[0]);
        assertEquals(car, results[1]);
    }

    /** skip() is to remove a certain number of stream elements. */
    @Test
    public void skipJumpsOverElements()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().skip(2);
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(1, results.length);
        assertEquals(car, results[0]);
    }

    /** limit() is to remove stream elements after a certain index. */
    @Test
    public void limitBreaksAfterElements()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Stream<Vehicle> stream = vehicles.stream().limit(1);
        
        Vehicle[] results = stream.toArray(Vehicle[]::new);
        assertEquals(1, results.length);
        assertEquals(bicycle, results[0]);
    }
}

TerminalOperations.java
Terminal functions return something that is not a stream. In case they return Collection, Map, or Optional, it can be streamed further.
anyMatch() returns true when at least one element in stream matches given condition.
@Test
public void anyMatchIsTrueWhenAtLeastOneElementMatches()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    boolean result = vehicles.stream().anyMatch(vehicle -> vehicle.seats == 1);
    
    assertTrue(result);    // bicycle has just one seat
}
allMatch() returns true when every element in stream matches given condition.
@Test
public void allMatchIsTrueWhenEveryElementMatches()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    boolean result = vehicles.stream().allMatch(vehicle -> vehicle.seats == 1);
    
    assertFalse(result);    // cars and motorcycles have more seats
}
noneMatch() returns true when no element in stream matches given condition.
@Test
public void noneMatchIsTrueWhenNoElementMatches()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    boolean result = vehicles.stream().noneMatch(vehicle -> vehicle.seats == 1);
    
    assertFalse(result);
}
collect() turns a stream into a Collection.
@Test
public void collectTurnsStreamIntoCollection()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertions
            bicycle,
            motorcycle,
            car);
    List<Vehicle> resultList = vehicles.stream()
        .collect(
            Collectors.toList()
        );
    
    assertArrayEquals(vehicles.toArray(), resultList.toArray());
}
collect() can also turn a stream into an index Map.
@Test
public void collectTurnsStreamIntoMap()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertions
            bicycle,
            motorcycle,
            car);
    Map<Integer,List<Vehicle>> resultMap = vehicles.stream()
        .collect(
            Collectors.groupingBy(
                vehicle -> vehicle.wheels,    // key
                Collectors.toList()    // aggregated vehicles for key
            )
        );
    
    assertEquals(2, resultMap.size());
    assertArrayEquals(
            new Vehicle[] { bicycle, motorcycle }, 
            resultMap.get(2).toArray());    // vehicles with 2 wheels
    assertArrayEquals(
            new Vehicle[] { car }, 
            resultMap.get(4).toArray());    // vehicles with 4 wheels
}
reduce() turns a stream into just one result element.
@Test
public void reduceTurnsStreamIntoOneResultElement()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Vehicle result = vehicles.stream().reduce(bicycle, (v1, v2) -> (v1.seats > v2.seats) ? v1 : v2);
    
    assertEquals(car, result);    // car has most seats
}
findFirst() returns an optional first element.
@Test
public void findFirstReturnsFirstElement()    {
    Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
            bicycle,
            motorcycle,
            car);
    Optional<Vehicle> result = vehicles.stream().findFirst();
    
    assertTrue(result.isPresent());
    assertEquals(bicycle, result.get());    // is first in list
    
    assertFalse(Stream.empty().findFirst().isPresent());
}
findAny() returns an optional randomly chosen element.
@Test
public void findAnyReturnsRandomlyChosenElement()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Optional<Vehicle> result = vehicles.stream().findAny();
    
    assertTrue(result.isPresent());    // can not assert more
    
    assertFalse(Stream.empty().findAny().isPresent());
}
count() returns the number of elements in stream.
@Test
public void countReturnsNumberOfElements()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    long result = vehicles.stream().count();
    
    assertEquals(3, result);
}
max() returns an optional maximal element in stream.
@Test
public void maxReturnsTheMaximalElement()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Optional<Vehicle> result = vehicles.stream()
            .max(Comparator.comparing(v -> v.seats));
    
    assertTrue(result.isPresent());
    assertEquals(car, result.get());    // car has most seats
}
min() returns an optional minimal element in stream.
@Test
public void minReturnsTheMinimalElement()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    Optional<Vehicle> result = vehicles.stream()
            .min((v1, v2) -> v1.seats - v2.seats);
    
    assertTrue(result.isPresent());
    assertEquals(bicycle, result.get());    // bicycle has least seats
}
forEach() loops all elements with a given function. Other than peek() it returns nothing.
@Test
public void forEachLoopsAllElementsWithGivenFunction()    {
    Collection<Vehicle> vehicles = Set.of(
            bicycle,
            motorcycle,
            car);
    vehicles.stream().forEach(vehicle -> vehicle.setRanking(-1));
    
    for (Vehicle vehicle : vehicles)
        assertEquals(-1, vehicle.getRanking());
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
public class TerminalOperations extends FunctionsTestBase
{
    /** anyMatch() returns true when at least one element in stream matches given condition. */
    @Test
    public void anyMatchIsTrueWhenAtLeastOneElementMatches()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        boolean result = vehicles.stream().anyMatch(vehicle -> vehicle.seats == 1);
        
        assertTrue(result);    // bicycle has just one seat
    }
    
    /** allMatch() returns true when every element in stream matches given condition. */
    @Test
    public void allMatchIsTrueWhenEveryElementMatches()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        boolean result = vehicles.stream().allMatch(vehicle -> vehicle.seats == 1);
        
        assertFalse(result);    // cars and motorcycles have more seats
    }
    
    /** noneMatch() returns true when no element in stream matches given condition. */
    @Test
    public void noneMatchIsTrueWhenNoElementMatches()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        boolean result = vehicles.stream().noneMatch(vehicle -> vehicle.seats == 1);
        
        assertFalse(result);
    }
    
    /** collect() turns a stream into a Collection. */
    @Test
    public void collectTurnsStreamIntoCollection()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertions
                bicycle,
                motorcycle,
                car);
        List<Vehicle> resultList = vehicles.stream()
            .collect(
                Collectors.toList()
            );
        
        assertArrayEquals(vehicles.toArray(), resultList.toArray());
    }
    
    /** collect() can also turn a stream into an index Map. */
    @Test
    public void collectTurnsStreamIntoMap()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertions
                bicycle,
                motorcycle,
                car);
        Map<Integer,List<Vehicle>> resultMap = vehicles.stream()
            .collect(
                Collectors.groupingBy(
                    vehicle -> vehicle.wheels,    // key
                    Collectors.toList()    // aggregated vehicles for key
                )
            );
        
        assertEquals(2, resultMap.size());
        assertArrayEquals(
                new Vehicle[] { bicycle, motorcycle }, 
                resultMap.get(2).toArray());    // vehicles with 2 wheels
        assertArrayEquals(
                new Vehicle[] { car }, 
                resultMap.get(4).toArray());    // vehicles with 4 wheels
    }
    
    /** reduce() turns a stream into just one result element. */
    @Test
    public void reduceTurnsStreamIntoOneResultElement()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Vehicle result = vehicles.stream().reduce(bicycle, (v1, v2) -> (v1.seats > v2.seats) ? v1 : v2);
        
        assertEquals(car, result);    // car has most seats
    }
    
    /** findFirst() returns an optional first element. */
    @Test
    public void findFirstReturnsFirstElement()    {
        Collection<Vehicle> vehicles = List.of(    // need ordered list for assertion
                bicycle,
                motorcycle,
                car);
        Optional<Vehicle> result = vehicles.stream().findFirst();
        
        assertTrue(result.isPresent());
        assertEquals(bicycle, result.get());    // is first in list
        
        assertFalse(Stream.empty().findFirst().isPresent());
    }
    
    /** findAny() returns an optional randomly chosen element. */
    @Test
    public void findAnyReturnsRandomlyChosenElement()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Optional<Vehicle> result = vehicles.stream().findAny();
        
        assertTrue(result.isPresent());    // can not assert more
        
        assertFalse(Stream.empty().findAny().isPresent());
    }
    
    /** count() returns the number of elements in stream. */
    @Test
    public void countReturnsNumberOfElements()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        long result = vehicles.stream().count();
        
        assertEquals(3, result);
    }
    
    /** max() returns an optional maximal element in stream. */
    @Test
    public void maxReturnsTheMaximalElement()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Optional<Vehicle> result = vehicles.stream()
                .max(Comparator.comparing(v -> v.seats));
        
        assertTrue(result.isPresent());
        assertEquals(car, result.get());    // car has most seats
    }
    
    /** min() returns an optional minimal element in stream. */
    @Test
    public void minReturnsTheMinimalElement()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        Optional<Vehicle> result = vehicles.stream()
                .min((v1, v2) -> v1.seats - v2.seats);
        
        assertTrue(result.isPresent());
        assertEquals(bicycle, result.get());    // bicycle has least seats
    }
    
    /** forEach() loops all elements with a given function. Other than peek() it returns nothing. */
    @Test
    public void forEachLoopsAllElementsWithGivenFunction()    {
        Collection<Vehicle> vehicles = Set.of(
                bicycle,
                motorcycle,
                car);
        vehicles.stream().forEach(vehicle -> vehicle.setRanking(-1));
        
        for (Vehicle vehicle : vehicles)
            assertEquals(-1, vehicle.getRanking());
    }
}




Keine Kommentare: