- It is a sequence of elements supporting sequential and parallel aggregate operations.
- Streams provide new ways of accessing and extracting data from collections.
- Streams do not mutate their source, rather return new streams that holds the result.
- Purely functional, so thread safe.
- Streams operations are lazy whenever possible.
- By calling
stream()
method on any collection objects. - By Using static method
stream.of()
, we can get stream from sequence of arguments.
- Using
generate
function. It acceptsSupplier<T>
.
interface Supplier<T> {
T get();
}
class Main{
public static void main(String[] args){
Stream.generate(() -> "Echo").forEach(System.out::println);
}
}
- Using
iterate
function. It accepts a seed value ( of type T ) and aUnaryOperator<T>
argument.
interface UnaryOperator<T>{
T apply(T t);
}
class Main{
public static void main(String[] args){
Stream.iterate(1, n -> n + 1).forEach(System.out::println);
}
}
class Main{
public static void main(String[] args){
IntStream ints = IntStream.of(1, 2, 4, 8);
IntStream ones = IntStream.generate(() -> 1);
Stream<Integer> integers = IntStream.range(0,100).boxed();
}
}
limit(n)
: Returns a new stream that ends after n elements or when original stream ends if it is shorter.skip(n)
: Returns a new stream that starts after n elements.Stream.concat(s1,s2)
: Returns a new stream after concatenating streams s1 and s2.
filter
: extract a sub stream that satisfies specified criteria. it accepts aPredicate<T>
interface and returns another new stream, thus filters can be chained.map
: transforms each element of a stream and returns a new stream.flatMap
: transform each element of a sub stream and flatten the result.
class Main{
public static void main(String[] args){
Stream.of(1,2,3).flatMap(x-> Stream.of(x,x*x)).forEach( System.out::println);
// output: 1 1 2 4 3 9
}
}
skip
,limit
,distinct
andsorted
.
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3).skip(2).forEach(System.out::println); // 3
Stream.of(1, 2, 3).limit(2).forEach(System.out::println); // 1 2
Stream.of(1, 2, 3, 1, 2).distinct().forEach(System.out::println); // 1 2 3
Stream.of(1, 2, 3, 1, 2).sorted().forEach(System.out::println); // 1 2 3
Stream.of(1, 2, 3, 1, 2).sorted((x, y) -> y - x).forEach(System.out::println); // 3 2 2 1 1
Stream.of(1, 2, 3, 1, 2).sorted(Comparator.naturalOrder()).forEach(System.out::println);
Stream.of(1, 2, 3, 1, 2).sorted((x, y) -> x - y).forEach(System.out::println); // 1 1 2 2 3
Stream.of(1, 2, 3, 1, 2).sorted(Comparator.reverseOrder()).forEach(System.out::println);
List<String> words= Arrays.asList("Tom", "Joseph", "Richard");
words.stream().sorted((x, y) -> x.length() - y.length()).forEach(System.out::println);
words.stream().sorted(Comparator.comparingInt(String::length).reversed()).forEach(System.out::println);
words.stream().sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
}
}
-
Once, terminal operations are called on streams, streams are terminated.
-
a.k.a reduction methods because they reduce the stream to some final value.
-
collect
,count
,max
,min
,findFirst
,findAny
,reduce
:
class Main{
public static void main(String[] args){
List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());
long count = list.stream().filter((x) -> x > 1).count();
Optional<Integer> max = list.stream().max(Integer::compare);
Optional<Integer> min = list.stream().min(Integer::compare);
Optional<Integer> first = list.stream().findFirst();
Optional<Integer> any = list.stream().findAny();
}
}
- Reduce:
- first argument is the initial value. This is the value that is returned if the stream is empty and is the starting point for the computation.
-
second argument is the lambda of type
BinaryOperator<T>
interface BinaryOperator<T> { T apply(T a, T b); } public class Test { public static void main(String[] args){ List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList()); int sum = list.stream().reduce(0,(x,y)->x+y); Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y); System.out.println(sum); } }
-
- first argument is the initial value. This is the value that is returned if the stream is empty and is the starting point for the computation.
import javax.swing.text.html.parser.TagElement;
import java.util.stream.Collectors;
class Person {
public int id;
public String name;
public int age;
Person(int id, String name, int age) {
this.id = id;
this.age = age;
this.name = name;
}
}
class Main {
public static void main(String[] args) {
List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());
Set<Integer> set = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toSet());
Stream<Person> personStream = Stream.of(new Person(1,"Bob",28),new Person(2,"Ben",29));
Map<Integer, String> idToName = personStream.collect(Collectors.toMap(Person::getId, Person::getName));
Map<Integer, Person> idToPerson = personStream.collect(Collectors.toMap(Person::getId, Function.identity()));
}
}
identity
is a static method on Function that returns a function that always returns its input argument. In the example, it is the function (Person p) -> p
- Optionals are a way to handle null values.
class Main{
public static void main(String[] args){
List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());
long count = list.stream().filter((x) -> x > 1).count();
Optional<Integer> max = list.stream().max(Integer::compare);
if(max.isPresent()){
System.out.println(max.get());
}
}
}
- using orElse
OptionalValue.orElse(defaultValue)
- ifPresent(Consumer)
OptionalValue.ifPresent(v-> System.out.println(v))