Ethickfox kb page with all notes
The mechanism that allows you to work with data in a functional style. Stream is an iterator whose role is to accept a set of actions to apply on each of the elements it contains. It can be used to process the data flow. The stream represents a sequence of objects from a source such as a collection, which supports aggregate operations. They were designed to make collection processing simple and concise.
Another important distinction from collections is that streams are inherently lazily loaded and processed.
Operations that can be performed any number of times as they return stream
| Method stream | Description |
|---|---|
| filter | Filters records, returns only records that match the condition |
| skip | Skips N first elements |
| distinct | Returns stream without duplicates (for the equals method) |
| map | Convert each stream element |
| peek | Returns the same stream, but applies the function to each element of the stream |
| limit | Allows you to limit the sample to a certain number of first elements |
| sorted | Allows you to sort the values either in natural order or by setting Comparator |
| mapToInt,mapToDouble, mapToLong | Analog map, but returns a primitives stream (i.e., a stream from numeric primitives) |
| flatMap, flatMapToInt,flatMapToDouble | Similar to map, but can convert stream of Collections to stream of items of these collections |
Operations that return the resulting value
| Method stream | Description |
|---|---|
| findFirst | Returns the first element of a stream (returns Optional) |
| findAny | Returns any matching element from the stream (returns Optional) |
| collect | Presentation of results as collections and other data structures |
| count | Returns the number of elements in a stream |
| anyMatch | Returns true if the condition is fulfilled for at least one element |
| noneMatch | Returns true if none of the elements are true |
| allMatch | Returns true if the condition is met for all elements |
| min | Returns the minimum element, the condition is used by the comparator |
| max | Returns the maximum element, the condition is a comparator |
| forEach | Applies function to each stream object, order in parallel execution is not guaranteed |
| forEachOrdered | Applies the function to each stream object, keeping the order of the elements ensures |
| reduce | Allows you to perform aggregate functions on the entire collection and return one result |
| toArray | Returns a string of values |
| Aggregating | Terminal operations that allow the collection of the resulting data, after the impact on them stream. - Run with collect, it can be implemented manually, or with the Collector class. - Which accepts the resulting flow type, intermediate type, and type. |
| toList, toMap, toSet, toCollection | |
| joining | соединяет элементы стрима в CharSequence |
| counting | возвращает к-во элементов |
| groupingBy | группирует объекты по свойству и складывает их в map. В отличие от toMap принимает вторым параметром коллектор |
| partitioningBy | тот же groupingBy, но разделяет коллекцию по предикату на true и false |
| Streams | Loops |
|---|---|
| Declarative | Imperative |
| Easier to Maintain | Better raw performance |
| Better performance for huge lists by using parallel streams | Fully controlled by developer |
| Functional in nature | More readable for nested logic |
| Operations performed on a stream do not modify the source. | |
| Stream is lazy and evaluates code only when required. | |
| The elements of a stream 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 | |
| Uses extra memory for intermediate operations |
In case of Parallel stream, several threads are spawned simultaneously and it internally using Fork and Join pool to create and manage threads.Parallel streams create ForkJoinPool instance via static ForkJoinPool.commonPool() method.
IntStream intParallelStream = Arrays.stream(array).parallel();
intParallelStream.forEach(s ->
System.out.println(s + " " + Thread.currentThread().getName())
);
// =================================
// 2 main
// 1 ForkJoinPool.commonPool-worker-1
// 3 ForkJoinPool.commonPool-worker-2
// =================================
Parallel Stream takes the benefits of all available CPU cores and processes the tasks in parallel. If number of tasks exceeds the number of cores, then remaining tasks wait for currently running task to complete.
You need to consider parallel Stream if and only if:
You could use custom fork join pool
ForkJoinPool fjp1 = new ForkJoinPool(5);
Callable<Integer> callable1 = () -> data.parallelStream()
.map(i -> (int) Math.sqrt(i))
.map(number -> performComputation(number))
.peek(i -> {
System.out.println("Processing with "+Thread.currentThread()+" "+ i);})
.reduce(0, Integer::sum);
try {
sumFJ1 = fjp1.submit(callable1).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
A default method is a method with an implementation, which can be found in an interface. We can use a default method to add a new functionality to an interface, while maintaining backward compatibility with classes that are already implementing the interface. When a class implements several interfaces that define the same default methods, the code simply won't compile, as there's a conflict caused by multiple interface inheritance (a.k.a the Diamond Problem). To solve this ambiguity, we must explicitly provide an implementation methods.
A function that we can reference and pass around as an object. lambda expressions are a natural replacement for anonymous classes such as method arguments. One of their main uses is to define inline implementations of functional interfaces.
A method reference is a Java 8 construct that can be used for referencing a method without invoking it. It’s used for treating methods as Lambda Expressions. They only work as syntactic sugar to reduce the verbosity of some lambdas.
String::new;String::valueOf;str::toString;String::toString;A functional interface is an interface with one single abstract method (default methods do not count), no more, no less.
Where an instance of such an interface is required, a Lambda Expression can be used instead. More formally put: Functional interfaces provide target types for lambda expressions and method references.
The arguments and return type of such an expression directly match those of the single abstract method.
Functional interfaces are usually annotated with the @FunctionalInterface annotation, which is informative and doesn’t affect the semantics.
| Interface | Parameters | Returns |
|---|---|---|
| Supplier | () | T |
| Consumer | T | void |
| Predicate | T | Boolean |
| Function | T | R |
| Operator | T | T |
Опциональные значения (optionals) являются удобным средством обертывания результата операции для предотвращения NullPointerException.
In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation. It encapsulates an effect — computation that may either result in an exception or return a successfully computed value. This is what Monad does — wraps a value and gives it some effect. That’s it. You just take a value, put it into a monad and get back an amplified value. An “amplified” means that the power of value’s type is increased. All it takes be a Monad is to provide two functions which conform to three laws.
flatMap(n -> Optional.of(n + 1))Laws
Left-identity and right-identity laws basically say that Optional.of function doesn’t change the value in a monad:
Optional.of(x).flatMap(f) == f(x)monad.flatMap(val -> Optional.of(val)) == monad
Associativity law says that when we have a chain of flatMap functions it shouldn’t matter how they’re nested:
monad.flatMap(f).flatMap(g) == monad.flatMap(x ⇒ f(x).flatMap(g))
May me used in some data pipelines for ex streams to prevent failures due to exceptions.
//todo add