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