In this lesson we’ll introduce a new programming paradigm that is particular useful for working with data: streams.
We’ll manipulated linear collections of data using good old for loops.
But we can do better.
Let’s see how!
Many of the code and algorithms we’ve written together have operated on sequential data, stored in either arrays or Lists.
And we’ve seen and identified common patterns for working with this kind of data.
Such as counting:
importjava.util.List;
importjava.util.Arrays;
List<Integer>values=Arrays.asList(1, 2, 5);
intcount=0;
for (intvalue:values) {
if (value>=1) {
count++;
}
}
System.out.println(count);
And searching:
importjava.util.List;
importjava.util.Arrays;
List<Integer>values=Arrays.asList(1, 2, 5);
booleanfound=false;
for (intvalue:values) {
if (value==2) {
found=true;
break;
}
}
System.out.println(found);
And transforming:
importjava.util.List;
importjava.util.Arrays;
importjava.util.ArrayList;
List<Integer>values=Arrays.asList(1, 2, 5);
List<String>strings=newArrayList<>();
for (intvalue:values) {
strings.add(""+value+"ee");
}
System.out.println(strings);
And filtering:
importjava.util.List;
importjava.util.Arrays;
importjava.util.ArrayList;
List<Integer>values=Arrays.asList(1, 2, 5);
List<Integer>evens=newArrayList<>();
for (intvalue:values) {
if (value%2==0) {
evens.add(value);
}
}
System.out.println(evens);
And combining:
importjava.util.List;
importjava.util.Arrays;
List<Integer>values=Arrays.asList(1, 2, 5);
Stringcombined="";
for (intvalue:values) {
combined+=value;
}
System.out.println(combined);
And while these are fine building blocks for creating larger programs, there is something a bit repetitive and dull about them.
Every one has the same overall structure: the same loop, the same return structure.
Shouldn’t there be a better, more compact way of expressing these kind of patterns?
Next, let’s examine how to utilize common stream operations to replace the repetitive loop-based code we wrote above.
First, let’s look at how to set up a stream and one of the most basic stream operations—map:
// Stream Setup and map
We can also filter streams using… filter.
And count them using… count!
Let’s see how:
// filter
And, we can even reduce a Stream until a single value with reduce, a surprisingly powerful primitive.
Streams may seem alien to you at first.
That’s not surprising.
A famous silicon valley tech thought leader has pointed out that powerful programming ideas usually feel strange and even bizarre at first.
But, as you come to appreciate them, not only do they become more natural, but the older less-powerful ways of doing things start to see even more limited.
Compared to for loops, Streams are:
More succint: the common parts of the various for-loop based patterns we’ve listed above have been factored out, leaving only the decision-making logic that changes depending on the application
More composable: it is easier to reorder stream operations to accomplish different data processing tasks than it is to tease apart different parts of for loop
More efficient: Streams allow various kinds of operations (like map, for example) to be done in parallel, increasing the speed with which large collections can be processed
To wrap up, let’s have some fun with Streams working with one of our favorite data sets:
importjava.util.stream.Stream;
publicclassDog {
privateStringname;
privateintage;
publicDog(StringsetName, intsetAge) {
name=setName;
age=setAge;
}
publicStringgetName() {
returnname;
}
publicintgetAge() {
returnage;
}
}
Homework Restricted to Current CS 124 Students
A publicly-accessible version of this content is available at learncs.online.
Homework: Escape a Maze
Created By: Geoffrey Challen
/ Version: 2021.4.0
Let's get some more practice with algorithms by escaping from a maze!
Implement a public class MazeEscape that provides a single public class method named escape.
escape accepts a single parameter, a Maze object with methods explained below.
Your goal is to manipulate the maze until you reach the exit, and then return it when you are finished.
If the passed maze is null, throw an IllegalArgumentException.
To navigate the maze, using the following Maze methods:
isFinished(): returns true when you have reached the exit of the maze
turnRight() rotates your character 90 degrees to the right
turnLeft() rotates your character 90 degrees to the left
canMove() returns true if you can move one cell forward, false otherwise. Your path may be blocked by a wall!
move() moves your character one cell forward and increases the step counter
The passed Maze object represents a simply-connected or perfect maze: one that contains no loops. As a result,
we suggest that you pursue a classic maze escape algorithm: wall following. Simply put, in a maze that contains no
loops, as long as you continue following a wall you will eventually reach the exit. In a corn maze, you might
implement this by simply maintaining contact with a wall (right or left) until you complete the maze. However,
you'll need to think a bit about how to implement this algorithm to finish this problem.