# Stream API in Java

In Java 8, every class which implements the `java.util.Collection` interface has a `stream` method which allows you to convert its instances into`Stream` objects.

- Technically: typed interface
- Extends: BaseStream
- Also has: IntStream, LongStream, DoubleStream based on primitive data types int, long and double

# Properties:
## Does not hold data
- pulls data from given source
- connects to source, consumes the data and processes it

## Does not modify data
- because data is processed in parallel with no visibility issues
- not enforced by compiler, merely a contract

## Source may be unbounded
- not finite meaning number of elements produced by the source is unknown at build time

# Patterns for building
- 
```
Stream.empty(); // an empty stream
``` 
- 
```
Stream.of("one"); // singleton stream
``` 
- 
```
Stream.of("one", "two", "three"); // stream with multiple elements
``` 
- 
```
Stream.generate(() -> "one"); // constant stream using Supplier
``` 
- 
```
Stream.iterate("+", s -> s + "+"); // a growing stream
``` 
Made using `UnaryOperator` which takes an element and returns another of the same type. `iterate` takes the current element of the stream as the first argument, gets the result from the `UnaryOperator` of the second argument and uses that as the next element in the stream.
- 
```
ThreadLocalRandom.current().ints(); // a random stream
``` 
- 
```
IntStream stream = "hello".chars();
``` 
`chars` method returns an int stream based on the letters of the characters.
- 
```
IntStream stream = "hello".chars();
``` 
`chars` method returns an int stream based on the letters of the characters.
-
```
Stream<String> words = Pattern.compile().splitAsStream(something); // stream on a regular expression
``` 
The Pattern class implements the regular expression engine in JDK. It provides a Pattern object by calling the `compile` static method. 
-
```
Stream<String> lines = Files.lines(path); // stream on the lines of a text file
``` 

# Terminal v/s Intermediate operation

A terminal operation must be called to trigger processing on the stream. Without it, no data is consumed, processed or returned.
## Example
`forEach` v/s `peek`. We cannot substitute `forEach` calls with `peek` calls as `peek` is an intermediate operation created for debugging purposes. 
## Differentiating

1. Javadoc specifies terminal or intermediate
2. A call that returns Stream -> intermediate. A call that returns something else or void -> terminal

# Functions
-  map
- filter
- peek
- forEach
- skip
- limit
- Match Reductions returning boolean -> anyMatch (any element), allMatch (all elements), noneMatch
^^^ may not evaluate predicate for all elements -> short circuiting terminal operations
- Find Reductions -> findFirst (returns any if the stream is unordered -> built on a set etc), findAny

## Reduce Reductions

1.
Provided the list has only positive numbers (since the identity for max is 0 over a positive range)
```
int maxNum = 
list.stream()
.reduce(0, (p1, p2) -> Integer.max(p1, p2));
``` 
 2.
If identity element is not provided, Optional is returned -> result of the reduction on an empty stream is not defined
```
Optional<Integer> maxNum = 
list.stream()
.reduce((p1, p2) -> Integer.max(p1, p2));
``` 

