0% found this document useful (0 votes)
7 views

P2 04 Java8 5 StreamsAPI Ua

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

P2 04 Java8 5 StreamsAPI Ua

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

Java 8 - Stream API

Stream API
• Stream - A sequence of elements supporting
sequential and parallel aggregate operations

• A stream is not a collection (not a data structure)


– it takes input from the Collections, Arrays or I/O
channels

• Streams don’t change the original data structure


– they only provide the result as per the pipelined
methods
Stream API – приклад

List<String> languages = Arrays.asList("Python", "c++", "C#",


"JavA", "Javascript", "C");

languages.stream()
.filter((s) -> s.length() < 5)
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
Stream API
• No storage
– A stream is not a data structure that stores elements; instead, it conveys elements from a
source such as a data structure, an array, a generator function, or an I/O channel, through a
pipeline of computational operations.
• Functional in nature
– An operation on a stream produces a result, but does not modify its source. For example,
filtering a Stream obtained from a collection produces a new Stream without the filtered
elements, rather than removing elements from the source collection.
• Laziness-seeking
– Many stream operations, such as filtering, mapping, or duplicate removal, can be
implemented lazily, exposing opportunities for optimization. For example, "find the first String
with three consecutive vowels" need not examine all the input strings. Stream operations are
divided into intermediate (Stream-producing) operations and terminal (value- or side-effect-
producing) operations. Intermediate operations are always lazy.
• Possibly unbounded
– While collections have a finite size, streams need not. Short-circuiting operations such as
limit(n) or findFirst() can allow computations on infinite streams to complete in finite time.
• Consumable
– The elements of a stream are only visited once during the life of a stream. Like an Iterator, a
new stream must be generated to revisit the same elements of the source.
Stream Data Types
• Stream<T>
• IntStream
• LongStream
• DoubleStream

* Примітка: Пригадайте
функціональні інтерфейси
Pipeline
• Джерело: створення/отримання стріма (1)
• Проміжні операції (0..n)
– стрім на вході
– стрім на виході
• Термінальна операція (1)
– стрім на вході
– на виході або нічього або результат (не стрім)
Pipeline - Приклад
public static void main(String[] args) {

Stream.of("Boo! ", " Lambda", " Abrakadabra", "C ", "C++")


.map(String::trim)
.filter(s -> s.length() < 7)
.sorted()
.forEach(System.out::println);

}
Створення стрімів
• From a Collection via the stream() and parallelStream() methods

• From an array via Arrays.stream(Object[])

• From static factory methods on the stream classes, such as Stream.of(Object[]),


IntStream.range(int, int) or Stream.iterate(Object, UnaryOperator)

• The lines of a file can be obtained from BufferedReader.lines()

• Streams of file paths can be obtained from methods in Files

• Streams of random numbers can be obtained from Random.ints()

• Numerous other stream-bearing methods in the JDK, including BitSet.stream(),


Pattern.splitAsStream(java.lang.CharSequence), and JarFile.stream().
Cтворення стрімів - приклади
List<String> list = Arrays.asList("C", "C++", "C#", "Java", "JavaScript", "Python");
list.stream()
.filter((s) -> s.length() < 5)
.forEach(System.out::println);

int[] array = {1, 3, 5, 7, 9};


Arrays.stream(array).forEach(System.out::println);

Stream.of("C", "C++", "C#", "Java").forEach(System.out::println);

IntStream.range(5, 10).forEach(System.out::println);

IntStream.iterate(1, i -> i << 1)


.limit(17)
.forEach(System.out::println);
Проміжні операції
• Ледачі (lazy)
– Intermediate operations are lazy. This means that they will be invoked only if it
is necessary for the terminal operation execution.

System.out.println("Hi");
IntStream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0);
System.out.println("Bye");

System.out.println("Hi again");
IntStream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0)
.forEach(i -> {});
System.out.println("Bye again");
Проміжні операції
• Стрім на «вході» – стрім на «виході»
Stream<String> s1 = Stream.of("#4", "#11", "#41", "#999");
Stream<String> s2 = s1.map(s -> s.substring(1));
IntStream s3 = s2.mapToInt(Integer::parseInt);
IntStream s4 = s3.map(i -> i + 1);
Stream<String> s5 = s4.mapToObj(i -> "#" + i);
s5.forEach(System.out::println);

Stream.of("#4", "#11", "#41", "#999")


.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.map(i -> i + 1)
.mapToObj(i -> "#" + i)
.forEach(System.out::println);
Проміжні операції
• Один «вхід» - один «вихід»
– Можна будувати ланцюги
– Не можна будувати більш складні графи

IntStream is = IntStream.range(1, 10);


IntStream is2 = is.map(i -> i + 1); // ok
IntStream is3 = is2.map(i -> i * 2); // ok
IntStream is4 = is2.map(i -> i % 3); // NOT ok

• Щоб випадково не наступити на такі «граблі», краще усі операції зі стрімами


записувати одним великим виразом:

IntStream.range(1, 10)
.map(i -> i + 1)
.map(i -> i * 2)
.map(i -> i % 3)
.forEach(System.out::println);
Проміжні операції
• Stateless / Stateful
– Stateless: filter(), map(),…
• Наступні операції не залежать від попередніх
• Дуже добре масштабуються
– Stateful: distinct(), sorted(), …
• Наступні операції залежать від попередніх
• Можуть вимагати багато RAM або CPU

• Short-circuiting
– limit(), skip()
• Також є термінальні short-circuit операції, наприклад
findFirst()
Проміжні операції
• filter()
• map()
• flatMap()
• sorted()
• distinct()
• limit()
• skip()
• peek()
• sequential(), parallel(), unordered()
filter()
Stream<T> filter(Predicate<? super T> predicate)

Stream.of("Pascal", "Java", "Cobol", "C++", "Ada")


.filter(s -> s.contains("a"))
.filter(s -> s.length() < 5)
.forEach(System.out::println);
map()
Stream<T>
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
IntStream mapToInt(ToIntFunction<? super T> mapper)
LongStream mapToLong(ToLongFunction<? super T> mapper)
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)

IntStream
IntStream map(IntUnaryOperator mapper)
LongStream mapToLong(IntToLongFunction mapper)
DoubleStream mapToDouble(IntToDoubleFunction mapper)
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper)

LongStream
….

DoubleStream
….
map()

Stream.of("#4", "#11", "#41", "#999")


.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.map(i -> i + 1)
.mapToObj(i -> "#" + i)
.forEach(System.out::println);
flatMap()
Stream<T>
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)
LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper)
DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)

IntStream
IntStream flatMap(IntFunction<? extends IntStream> mapper)

LongStream
LongStream flatMap(LongFunction<? extends LongStream> mapper)

DoubleStream
DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper)
flatMap()
Stream.of("Java is a cool programming language",
"Python is cool too")
.flatMap(s -> Arrays.stream(s.split(" ")))
.forEach(System.out::println);

IntStream.of(3, 2, 2)
.flatMap(i -> IntStream.range(1, i+1))
.forEach(System.out::println);
sorted()
Stream<T>
Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)

IntStream
IntStream sorted()

LongStream
LongStream sorted()

DoubleStream
DoubleStream sorted()
sorted()
Stream.of("Java is a cool programming language",
"Python is cool too")
.flatMap(s -> Arrays.stream(s.split(" ")))
.sorted()
.forEach(System.out::println);

Stream.of("Java is a cool programming language",


"Python is cool too")
.flatMap(s -> Arrays.stream(s.split(" ")))
.sorted(String::compareToIgnoreCase)
.forEach(System.out::println);
distinct()

Stream.of(1, 2, 3, 1, 2, 5)
.distinct()
.forEach(System.out::println);
limit()

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.limit(5)
.forEach(System.out::println);
skip()

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.skip(5)
.forEach(System.out::println);
limit() + skip()
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.skip(5)
.limit(5)

?
.forEach(System.out::println);

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.limit(5)
.skip(5)
.forEach(System.out::println);
peek()
Stream<T>
Stream<T> peek(Consumer<? super T> action)

IntStream
IntStream peek(IntConsumer action)

LongStream
LongStream peek(LongConsumer action)

DoubleStream
DoubleStream peek(DoubleConsumer action)
peek()

Stream.of(1, 2, 3, 4, 5, 6)
.peek(i -> System.out.println("Peek before filter: " + i))
.filter(i -> i % 2 == 0)
.peek(i -> System.out.println("Peek after filter : " + i))
.forEach(i -> System.out.println("For Each : " + i));

Stream.of(1, 2, 3, 4, 5, 6)

?
.peek(i -> System.out.println("Peek before filter: " + i))
.filter(i -> i % 2 == 0)
.peek(i -> System.out.println("Peek after filter : " + i));
sequential(), parallel(), unordered()
• Можуть суттєво вплинути на швидкодію
Характеристики стрімів
• Ледащі
– до виклика термінальної операції нічого не
відбувається
• Одноразові
– Можуть бути використані тільки один раз
• Послідовні / паралельні
– Collection.parallelStream(), Stream.parallel()
• Впорядковані / невпорядковані
– із ordered можна зробити unordered для
підвищення ефективності (Stream.unordered())
Терминальные операции
• Прості
– forEach, forEachOrdered
– min, max, count
– average, sum (для числових)
– allMatch, anyMatch
– findAny, findFirst
• Трошки складніші ☺
– reduce (immutable reduction)
– collect (mutable reduction)
reduce

Optional<T> reduce(BinaryOperator<T> accumulator)

T reduce(T identity, BinaryOperator<T> accumulator)

reduce(
U identity,
<U> U
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
Приклад reduce 1
int sum = IntStream.range(1, 6)
.reduce((x,y)->x+y)
.orElse(-1);
System.out.println(sum);
Приклад reduce 2
int sum = IntStream.range(1, 6)
.reduce(0, (x,y)->x+y);
System.out.println(sum);
Приклад reduce 3 (map-reduce)
public class Emp {

String ename;
int sal;

public Emp(String ename, int sal) {


this.ename = ename;
this.sal = sal;
}

public static void main(String[] args) {


List<Emp> emps = Arrays.asList(
new Emp("King", 5000), new Emp("Smith", 800), new Emp("Clark", 1000));

Integer sumSal = emps.stream()


.reduce(0, (sum, emp) -> sum + emp.sal, Integer::sum);
System.out.println(sumSal);
}
}
Collector
<R> R collect(
Supplier<R> supplier,
BiConsumer<R,? super T> accumulator,
BiConsumer<R,R> combiner)
Приклад collect
public class Emp {

String ename;
int sal;

public Emp(String ename, int sal) {


this.ename = ename;
this.sal = sal;
}

public static void main(String[] args) {


List<Emp> emps = Arrays.asList(
new Emp("King", 5000), new Emp("Smith", 800), new Emp("Clark", 1000));

List<String> names = emps.stream().collect(


ArrayList::new, // supplier
(list, emp) -> list.add(emp.ename), // accumulator
ArrayList::addAll); // combiner
System.out.println(names);
}
}

You might also like