Java 8 was released on March 2014 and it is about functional-style programming. It proposes a set of new features:
- lambda expressions
- method references
- the stream api and collectors
- a new tollbox an functional interfaces available in java.util.function
- default methods in interface
- parameterization
Lambdas
Lambda is a technique to passcode to methods.
Looking at lambda from the point of view of a developer it is an argument list, followed by the arrow token and a block a code, or a expression.
Example of lambda expression:
- Sum of two numbers: (int x, int y) -> x + y
- Sum of two numbers, short version: (x, y) -> x + y
- Concatenating two strings: (String s1, String s2) -> s1 + s2
- Square of a number: (Integer number) -> number * number
- (x, y) -> { System.out.println(x + y); }
- Check if a string contains another string: (String s) -> s.contains(“word”)
- Check if a string contains another string, short version: s -> s.contains(“word”)
An example of complex business logic with lambdas:
1 2 3 4 5 6 7 |
(List<Students> students) -> { persist(students); notify(); } |
Note: Lambda can refer to local variables that are not explicitly declared final, as long as they are never modified. This refers to the term of effectively final local variables.
Method Reference
Method references are a sub-feature of the lambda expression that make writing lambda easier. In term of definition, a method reference is a class name (or an object reference) followed by the double colon operator (::) and a method name.
The method reference technique can use a reference to a static method, an instance method or a constructor.
The syntax for method reference is as follow:
- ClassName::staticMethodName
- ContainingType::intanceMethod
- objectReference::methodName
- ClassName::new
The Stream API
Definition: A stream is a sequence of data that are conceptually produced one at a time.
Java 8 provides the Stream API (java.util.stream) that supports parallel operations to process data. Streams are a way of representing sequenced data and flexibly indicating whether these can be processed in parallel.
When you use a stream, the data become immutable, and you can use them only once.
There are three kind of operations that can be applied to a stream:
- build operations – these are operations that create a stream from a datasource.
- intermediate operations – these are the operations that convert one stream into another
- terminal operations – they convert a stream into something else (or nothing)
Java Stream offers three type of operations:
- Intermediate methods. These methods don’t get processed until a terminal method is called. Intermediate methods produce other streams.
- filter()
- map()
- peek()
- Terminal methods. When one of the terminal method is invoked, the stream is considered consumed and no more operations can be performed on it.
- forEach()
- count() – returns the number of element in the stream
- sum() – returns the sum of elements in the stream. used with primitive streams;
- average() – returns an Optional describing the arithmetic mean of elements of this stream. Returns an empty Optional if the stream is empty. Type returned depends on primitive class.
- min() – returns the minimum element of the stream, according to the provided Comparator
- max() – returns the maximum element of the stream, according to the provided Comparator
- collect()
- Terminal short-circuit methods
- findFirst() – returns the first element that meets the specified criteria;
- findAny() – returns the first element found that meets the specified criteria. Results may vary when performed in parallel;
- anyMatch() – returns true if any elements meet the criteria. Results may vary when performed in parallel;
- allMatch() – returns true if all the elements meet the criteria;
- noneMatch() – returns true of none of the elements meet the criteria.
Various methods in Stream API:
- IntStream
- LongStream
- DoubleStream
Streams can be:
- ordered or unordered – operations in a stream may have a fixed order or not. If they don’t have a fixed order, it is called encounter order;
- sequential or parallel – In a sequential stream, operations are performed on one object at a time. In a parallel stream, operations are performed on several objects in parallel.;
- lazy or eagerness.
Lazy operations only do the needful work. The lazy operations can be optimized
In lazy, only the required operations are performed.
Default methods
Prior to java 8, you could update an interface only if you update all the classes that implement that interface. This issue is resolved in java 8 with default methods. This is accomplished with the use of default keyword.
Parameterized behavior
Another feature of Java 8 is the ability to pass a piece of code (methods) as arguments to other methods. This concept is known as behavior parameterization.
Behavior parameterization means the ability to tell a method to take multiple behaviors as parameters and use them internally to accomplish different behaviors.
Optional Type
Optionals, either stores a T, store nothing. They are useful for methods that may, or may not find a value. There are two ways of making an optional:
1 2 3 |
Optional<String> optionalValue = Optional.of(someOtherValue); Optional<String> optionalValue = Optional.empty(); // missing value |
Then, when you call
1 2 |
optionalValue.get(); // it returns value if present, otherwise throws exception. optionalValue.orElse(someElseValue); // it returns value if present, otherwise returns someElseValue. |
Take away:
The Stream class converts collection to a pipeline that can only be used once.
Go.claudiu, thanks so much for the post.Really thank you! Great.