-
Notifications
You must be signed in to change notification settings - Fork 1
Java Streams Crash Course
alexv-anderson edited this page Feb 24, 2016
·
2 revisions
#Table of Contents
- Explanations
- A Stream is a Fancy for Loop
- Streams Break the Rules
- Examples
- Filtering, Mapping, and Collecting
- Why is it worth it?
###Explanations #####A Stream is a Fancy for Loop In the simplest sense, streams in Java are just sugar syntax to replace a compressed for loop. So, if you have this list,
List<String> myListOfStrings = new LinkedList<>();
then there is essentially no difference between this for loop
for(String s : myListOfStrings) {
System.out.println(s);
}
and this stream operation
myListOfStrings.stream().forEach((String s) -> { System.out.println(s); });
#####Streams Break the Rules
- Since Java already knows the type of the objects in the list, you don't have to specify the type. This means that both of the lines below are legal and preserve Java's type safety.
myListOfStrings.stream().forEach((String s) -> System.out.println(s));
myListOfStrings.stream().forEach(s -> System.out.println(s));
- Also, operations on streams (
.forEach()
etc) only accept functions as arguments, so technically brackets and semicolons are required; however, if the function is only one line long, neither are required
myListOfStrings.stream().forEach(s -> { System.out.println(s); });
myListOfStrings.stream().forEach(s -> System.out.println(s));
###Examples #####Filtering Mapping and Collecting
- Using a filter allows you to apply a
forEach
to only certain items in a list. For example, here is a for loop translated into a stream operation
/* Using loops */
for(String s : myListOfStrings) { //myStrings.stream()
if(s.startsWith("Hello")) //filter(s -> contains("Hello"))
System.out.println(s); //forEach(s -> System.out.println(s))
}
/* Translation */
myListOfStrings.stream().filter(s -> s.contains("Hello")).forEach(s -> System.out.println(s));
- Using a mapping allows you to transform one object into a second and perform stream operations on the second objects
interface Person {}
class FormalGreeting {
public FormalGreeting(Person);
public String getGreeting();
}
/* Using loops */
for(Person person : myListOfPeople) {
System.out.println(new FormalGreeting(person).getGreeting());
}
/* Translation */
myListOfPeople.stream().map(person -> new FormalGreeting(person))
.forEach(fg -> System.out.println(fg.getGreeting());
- Collectors allow you to create new lists from a stream result
interface Person {}
class FormalGreeting {
public FormalGreeting(Person);
public String getGreeting();
}
/* Using loops */
List<FormalGreeting> formalGreetings = new LinkedList<>();
for(Person person : myListOfPeople) {
formalGreetings.add(new FormalGreeting(person));
}
/* Translation */
List<FormalGreeting> formalGreetings = myListOfPeople.stream().map(person -> new FormalGreeting(person))
.collect(Collectors.toList());
#####Why is it worth it? Streams start to pay off big when you start stacking stream operations. For example,
interface Person {
public isVIP();
public isPresent();
}
class FormalGreeting {
public FormalGreeting(Person);
public String getGreeting();
public boolean willInflateEgo();
}
List<Person> people = new LinkedList<>();
/* Using loops */
List<FormalGreeting> greetings4HumbleVIPs = new LinkedList<>();
for(Person person : people) { //people.stream()
if(person.isPresent() && person.isVIP()) { //filter(p -> p.isPresent() && p.isVIP())
FormalGreeting fg = new FormalGreeting(person); //map(p -> new FormalGreeting(p))
if(!fg.willInflateEgo()) //filter(fg -> !fg.willInflateEgo())
greetings4HumbleVIPs.add(fg); //collect(Collectors.toList())
}
}
/* Translation */
greetings4HumbleVIPs = people.stream().filter(p -> p.isPresent() && p.isVIP())
.map(p -> new FormalGreeting(p))
.filter(fg -> !fg.willInflateEgo())
.collect(Collectors.toList());