Swimming Upstream

A Beginner’s Guide to Understanding Stream Notation in Java

Streams are another way to do something to every member of a set (similar to forEach). You can process only as much of the stream as you want to to accomplish the goal. It’s like a forEach with an automatic break in the code. Streams can dramatically shorten the code that we have to create.

I spent some time diagramming the code from Friday’s stream examples to better show what each part of a stream statement is doing, and what equivalent logic looks like in loops. Since I know some of the other bootcampers had questions about the syntax, I though I’d post them on the blog to make them easier to find.

Example of .forEach()

The .forEach() method of Stream class does exactly what you’d expect it to do - it itereates through all the elements in a stream (just like the for each loop we’ve already learned about).

Stream statement diagram:

OriginalObject Streaming Logic loop Lambda(ƛ) parameter Lambda(ƛ) expression
numbers .stream() .forEach (x -> System.out.println(x));

Stream Code:

List <Integer> numbers = Arrays.asList(2,3,4,5);
numbers.stream().forEach(x -> System.out.println(x));

Output:

2
3
4
5

Works Like This Regular For Each Loop

List <Integer> numbers = Arrays.asList(2,3,4,5);
for  (int x: numbers){
   System.out.println(x*x);
}

Example of .map() & .collect()

The .collect() method of Stream class gathers elements of any Stream into a Collection. If you want to return a value, you will need a collector to collect the results.

New variable OriginalObject Streaming Map Function ƛ parameter & expression Get all the results Puts result in list
List newList = numbers .stream() .map( x -> x*x) .collect (Collectors.toList());

Stream Code

List <Integer> numbers = Arrays.asList(2,3,4,5);
List newList = numbers.stream().map(x -> x*x).collect(Collectors.toList());

Output

None, but now newList = [4,9,16,25]

Works Like This Regular For Each Loop

List <Integer> numbers = Arrays.asList(2,3,4,5);
List newList = new ArrayList();
for(int x : numbers){
    newList.add(x*x);
}

Example of .map() and .forEach()

The .map() method is used when we want to convert a stream of x to stream of f(x) (aka y).

OriginalObject Streaming Map Function ƛ parameter & expression (input ->output) Logic loop print out the result of x*x
numbers .stream() .map( x -> x*x) .forEach (y -> System.out.println(y);)

Stream Code

    List <Integer> numbers = Arrays.asList(2,3,4,5);
    numbers.stream().map(x -> x*x).forEach(y -> System.out.println(y));

Output

4
9
16
25

Works Like This Regular For Each Loop

List <Integer> numbers2 = Arrays.asList(2,3,4,5);
List newList = new ArrayList();
for(int x : numbers2){
    System.out.println(x*x);
}

Example of .filter() & .collect()

The filter method is used to select elements as per the Predicate passed as argument.

OriginalObject Streaming filter ƛ parameter & expression Collecting
names .stream() .filter( s -> s.startsWith(“S”)) .collect(Collectors.toList());

Stream Code

List <String> names = Arrays.asList("Reflection","Collection","Stream");
List result = names.stream().filter(s->s.startsWith("S")).collect(Collectors.toList());

Output

Output: none, but result = [Stream] 

Works Like This Regular For Each Loop

List <String> names = Arrays.asList("Reflection","Collection","Stream");
List result = new ArrayList();
for  (String name: names){
    if (name.startsWith("S")){
        result.add(name);
    }
}

Example of .filter() & .reduce()

The reduce method is used to reduce the elements of a stream to a single value. The reduce method takes a binary operator as a parameter.

OriginalObject Streaming filter ƛ parameter & expression .reduce
int even = .stream() .filter (x-> x%2 ==0) .reduce(0,*ans, i)->ans+1);

Stream Code

List number = Arrays.asList(2,3,4,5);
int even = number.stream().filter(x -> x%2 == 0).reduce(0, (ans, i) -> ans + i));

Output

Output: none, but even = 6 

This is becuase the function first filters out the even numbers (2 & 4), then adds them.

Works Like This Regular For Each Loop

List numbers = Arrays.asList(2,3,4,5);
List result = new ArrayList();
for  (Integer x: numbers){
     if (x%2==0){
       result.add(x);
     }
}

Example of .sort() & .collect()

The .sort() method returns a stream consisting of the elements of the original stream, sorted according to natural order (numerical, alphabetical, etc.). For ordered streams, the sort method is works well, but for unordered streams, things can get wierd.

Original Object Streaming Using .sort() method List being sorted Collecting ordered results in a list
names .stream() .sort( myNames) .collect(Collectors.toList());

Stream Code

Stream Code:
    String[] family = {"Rachel", "Brian", "Molly", "Lucy", "Alice", "Elliott"};
    List<String> names = Arrays.asList(family);
    List<String> sortedNames = names.stream().sorted().collect(Collectors.toList());

Output

Output: none, sortedNames = [Alice, Brian, Elliott, Lucy, Molly, Rachel]

Works Like This Without Streams

String[] family = {"Rachel", "Brian", "Molly", "Lucy", "Alice", "Elliott"};
List<String> names = Arrays.asList(family);
names.sort(String.CASE_INSENSITIVE_ORDER);
Written on October 5, 2019