https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/IntStream.html
- method of stand vs method of class?
- generic streams vs primitive streams
Imperative (state-changing) looping
Having statements that will change the variable
Declaratively
Java uses streams instead of assignments.
int summation(int n) {
return IntStream.rangeClosed(1, n).sum();
}
Construct Streams
Avoid Array because they are mutable.
IntStream
IntStream is a stream of primitive int values. It’s like a pipeline where integers flow through and you can perform operations on them.
range and rangeClosed
IntStream.range(1,10) // stops at 9
IntStream.rangeClosed(1, 10) // stops at 10
IntStream.of(5)
IntStream.of(5, 6, 9)
// iterate, generate
Data source (e.g. rangeClosed, iterate, generate, ...)
Intermediate Operations (e.g. limit, filter, map, ...)
Terminal operations (e.g. sum, reduce, forEach, ...)
Source and intermediate operations return a new stream.
iterate
IntStream.iterate(start, i -> i > end, i -> i - 1)
IntStream.iterate(5, i -> i >= 0, i -> i - 1)
// creates 5, 4, 3, 2, 1, 0
Stream.iterate(start, f)
// seed = starting value
// f = what happens each round
Intermediate Operations
(return a new stream):
.filter(i -> i > 2) // Keep only values > 2
.map(i -> i * 2) // Transform each value
.distinct() // Remove duplicates
.sorted() // Sort values
.limit(3) // Stops after 3 rounds
Filter: Letting the right values pass
IntStream.range(1,10).filter(x -> x % 2 == 0)
Test a predicate that produces boolean output
Map
IntStream.range(1,10).map(x -> x * x)
Affects all elements
Reduce: Takes in two arguments and their interaction.
IntStream.range(1,10).reduce(0, (x, y) -> x + y)
Applies a binary function on a value of type U
Left to right reduction
Seed
[0] 1 2 3 4
[0 1] 2 3 4
[1 2] 3 4
[3 3] 4
[6 4]
10
Terminal operations
(return a result, end the stream):
.count() // Count how many (returns long)
.sum() // Add them all up
.max() // Find maximum
.min() // Find minimum
.forEach(i -> {...}) // Do something with each
.toArray() // Convert to array
Limit: Stop at
IntStream.range(1,10).limit(5)
forEach
IntStream.range(1,10).forEach(x -> System.out.println(x))
Full Pipeline Example
IntStream.range(1, 20)
.filter(x -> x % 2 == 0)
.map(x -> x * x)
.reduce(0, (x, y) -> x + y)
Lambda Expressions
Options:
inferred parameter type with body: (x, y) -> { return x * y; }
body contains a single return expression: (x, y) -> x * y
only one parameter: x -> 2 * x
no parameter: () -> 1
You can add a body into the lambda declaration
map(x -> { return x * x: })
Example: Cumulative Sum
Multiple sums
int SCS(int n) {
return IntStream.rangeClosed(1, n) // IntStream
.map(x -> IntStream
.rangeClosed(1, x) // IntStream
.sum() // int
) // IntStream
sum(); // int
}
flatMap method: flattens all the streams
Input and output must be of the same type
int SCS(int n) {
return IntStream.rangeClosed(1, n) // IntStream
.flatMap(x -> IntStream.rangeClosed(1, x)) // IntStream
.sum(); // int
}
Example: Prime Number
boolean isPrime(int n) {
return n > 1 && IntStream.range(2, n)
.noneMatch(x -> n % x == 0)
}
Lazy Evaluation
Creates infinite streams
iterate
iterate(1, x -> x + 1)
limit(n)
It actually goes in a pair-rotate system.
Iter: 1
limit: 1
Iter: 2
...
Only evaluated when needed.
generate(() -> 1)
Domain and Co-domain
Empty Stream or Java Optional
IntStream.rangeClosed(110, 120)
.filter(x -> isPrime(x))
.findFirst()
OptionalInt.empty
Return optionalint if no prime is found.
int findFirstPrime(int a, int b) {
return IntStream.rangeClosed(a, b)
.filter(x -> isPrime(x))
.findFirst()
.orElse(-1);
}
Return -1 if no prime is found.
Generic Streams
Stream< >
Primitive Streams
maptoObj
It converts each int in an IntStream into an Object (like a String).
intStream.mapToObj(i -> /* convert i to an Object */)
1. Convert ints to Strings:
IntStream.range(0, 3) // IntStream: 0, 1, 2
.mapToObj(i -> "Number " + i) // Stream<String>: "Number 0", "Number 1", "Number 2"
2. Get characters from a string:
String str = "abc";
IntStream.range(0, str.length()) // IntStream: 0, 1, 2
.mapToObj(i -> str.charAt(i)) // Stream<Character>: 'a', 'b', 'c'
Or as Strings:
IntStream.range(0, str.length()) // IntStream: 0, 1, 2
.mapToObj(i -> str.substring(i, i + 1)) // Stream<String>: "a", "b", "c"
3. Create objects from indices:
IntStream.range(0, 3) // IntStream: 0, 1, 2
.mapToObj(i -> new Point(i, i * 2)) // Stream<Point>: Point(0,0), Point(1,2), Point