Java / Java8 streams
Refer the below program.
import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class FilterNull { public static void main(String[] args) { Stream<String> streamOfStrings = Stream.of("One", "Two", "Three", null, "Five", null); List<String> notEmptyStrings = streamOfStrings.filter(x -> x != null).collect(Collectors.toList()); notEmptyStrings.forEach(System.out::println); } }
A stream represents a sequence of elements and supports a different kind of operations to perform computations upon those elements.
In Java 8, each Stream class represents a single-use sequence of data and supports several I/O operations.
A Stream should be operated o only once. A Stream implementation may throw IllegalStateException if it detects that the Stream is being reused.
Whenever a terminal operation is called on a Stream object, the instance gets consumed and closed. Therefore, it is allowed to perform a single operation that consumes a Stream, otherwise, an exception is encountered that states that the Stream has already been operated upon or closed.
public class LargestAndSmallest { public static void main(String[] args) { Stream<Integer> myIntStream = Stream.of(1, 2, 3, 44, 556, -1, 0, 2234); System.out.println("Largest = " + myIntStream.reduce(Integer::max)); // The below line will throw java.lang.IllegalStateException System.out.println("Smallest = " + myIntStream.reduce(Integer::min)); } }
Create new stream whenever required as shown below.
public class LargestAndSmallest { public static void main(String[] args) { Supplier<Stream<Integer>> myIntStream = () -> Stream.of(1, 2, 3, 44, 556, -1, 0, 2234); System.out.println("Largest = " + myIntStream.get().reduce(Integer::max)); System.out.println("Smallest = " + myIntStream.get().reduce(Integer::min)); } }
Output: Largest = Optional[2234] Smallest = Optional[-1]
Default methods are the method defined in the interfaces with method body and using the default keyword. The implementing class may choose to override the default method or they may invoke the default method itself.
Default method can call methods from the interfaces they are enclosed in. Also in default method, this keyword refers to the declaring interface.
See the below code snippet.
@Override public boolean equals (Object obj) { return Optional.ofNullable(obj) .filter(that -> that instanceof Employee) .map(that -> (Employee) that) .filter(that -> this.fName.equals(that.fName)) .filter(that -> this.lName.equals(that.lName)) .isPresent(); } }
Inside a lambda expression, you can access final variables and also effectively final variables. Effectively final variables are initialized once however not marked final, second initialization lead to compilation error when used inside a lambda expression.
Yes. After the operation is performed, the stream pipeline is considered consumed, and no longer be used.
Stream operations are 2 types, intermediate and terminal operations, and together they form stream pipelines.
Intermediate operations return new are eam which allows you to call multiple operations in a form of a query. This operation does not get executed until a terminal operation is invoked. All Intermediate operations are lazy, so they are not executed until a result of a processing is actually needed, that is, traversal of the Stream does not start until the terminal operation of the pipeline is executed.
Examples of Stream intermediate operations include filter(), , map(), flatMap(), limit(), skip(), distinct(), sorted()peek().
Terminal operations are eagerly executed, and is always the last operation in a Stream pipeline. It can return a primitive type value (boolean, long), a concrete type (Optional value object), or nothing (void).
Examples of Terminal operations like Stream.forEach, IntStream.sum, may traverse the stream to produce a result or a side-effect. After the terminal operation is completed, the stream pipeline is considered consumed, and can no longer be used.
There are 2 types, stateful and stateless.
Stateful intermediate operations maintain information (state) from a previous invocation to use again in a future invocation of the method. For example, Stream.distinct()
needs to remember the previous elements it encountered, thus have to store state from previous passes. Another example of stateful intermediate operation is Streams.sorted()
.
filter(), map(), findAny()
.
A steam pipeline is a sequence of aggregate operations. Examples of aggregate operations include filter and forEach.
A pipeline has the following components:
- A source represented by collection, an array, a generator function, or an I/O channel.
- 0 or more intermediate operations such as filter that produces a new stream.
- A terminal operation, such as forEach, produces a non-stream result, such as a primitive value (boolean or double), a collection, or in the case of forEach, no value at all.
stream.forEach and iterator works similar in terms of functionality. The below are the differences in how they operate.
Aggregate operations. | Iterator. |
They process elements from the stream not directly on the collection.. | Iterator directly process the collection. |
Aggregate operation use internal iteration/internal delegation, JDK determines how to iterate the collection through stream . | Iterator use external iteration in which your application code determines both what collection it iterates and how it iterates it. . |
Parallel computing is possible by divide and conquer strategy. | It supports only sequential iteration. |
You may customize the behavior of an aggregate operation by passing behavior as lambda expression in parameter. | Not applicable. |
Reduction operations are terminal operations such as average, sum, min, max, and count that return one value by combining the contents of a stream. There are 2 general-purpose reduction operations, Stream.reduce
and Stream.collect
.
Lambda expressions are used to define inline implementation of a functional interface, an interface with a only one (non static) method, that eliminates the need of anonymous class and brings a very simple and powerful functional programming capabilities into Java.
The limit(long n)
method of java.util.stream.Stream
object performs stream reduction operation and returns a reduced stream of first n elements from the stream.
The skip(long n)
method of java.util.stream.Stream
object returns a stream of remaining elements after skipping first n elements.
Both methods limit
and skip
will throw an exception if n is negative
Thanks for your question. Consider the below example. Kindly share your feedback/suggestions in the comment section.
package net.javapedia.streams; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; class Employee { public Employee(String empName, Sex sex, String city) { super(); this.empName = empName; this.sex = sex; this.city = city; } String empName; public String getEmpName() { return empName; } Sex sex; String city; public String getCity() { return city; } } enum Sex { M, F; } public class GroupbyCountingExample { public static void main(String[] str) { List<Employee> myEmployees = new ArrayList<>(); myEmployees.add(new Employee("Name1", Sex.M, "New York")); myEmployees.add(new Employee("Name2", Sex.F, "Dallas")); myEmployees.add(new Employee("Name3", Sex.F, "Charlotte")); myEmployees.add(new Employee("Name4", Sex.F, "Charlotte")); myEmployees.add(new Employee("Name5", Sex.M, "New York")); myEmployees.add(new Employee("Name5", Sex.M, "New York")); Map<String, Long> empCountByCity = myEmployees.stream() .collect(Collectors.groupingBy(Employee::getCity, Collectors.counting())); for (String city : empCountByCity.keySet()) { System.out.println("Employee count in " + city + " :" + empCountByCity.get((city))); } } }
Output: Employee count in New York :3 Employee count in Charlotte :2 Employee count in Dallas :1
Java 8 Collectors.partitioningBy method accepts a predicate and returns a Collector by partitioning the element of the stream using Predicate so it will have 2 keys at most in Map. The key of the map can be only true and false and each key's value is a list of elements.
public static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(Predicate<? super T> predicate)
Consider the below example. This program checks if each item of list1 exists in list2 and partition with predicate.
public class PartitioningByEx1 { public static void main(String[] args) { List<String> list1 = Arrays.asList("A", "B", "C", "D"); List<String> list2 = Arrays.asList("A", "D", "E"); list1.stream().collect(Collectors.partitioningBy(item -> list2.contains(item))) .forEach((key, val) -> System.out.println(key + "-->>" + val)); } }
Output:
false-->>[B, C] true-->>[A, D]
We can pass the custom message to the Exception constructor when created as shown below.
orElseThrow(() -> new EntityNotFoundException("Entity doesn't Exist"));
Example:
import java.util.Optional; public class OrElseThrowCustomMessage { public static void main(String[] args) { Optional<String> str = Optional.empty(); str.orElseThrow(()-> new NullPointerException("Empty String")); System.out.println(str); } }
Inspired from Haskell and Scala, Java SE 8 introduces a new class in util package, java.util.Optional, whose instance hold an object so that it either contains a value or not (empty). It eliminates NullPointerException and the null check constructs.
Example of an empty optional:
Optional<String> str= Optional.empty();
Optional non-empty object:
String str = "javapedia.net"; Optional<String> oStr = Optional.of(str);
public static void main(String[] args) { Optional<String> emptyO = Optional.empty(); System.out.println(emptyO); System.out.println(emptyO.isPresent()); System.out.println(emptyO.orElseGet(()->"AssignThisIfEmpty")); Optional<String> strO = Optional.of("javapedia.net"); System.out.println(strO); System.out.println(strO.isPresent()); System.out.println(strO.get()); }
Output:
Optional.empty false AssignThisIfEmpty Optional[javapedia.net] true javapedia.net
Collection contains its elements but stream doesn't. Stream act on a view while elements are actually stored in the Collection or array.
Any change made on streams does not reflect on the underlying collection.
Yes. Java8 stream does NOT execute just by defining the steam pipeline. Stream works only when you call a terminal operation on the Stream.
Java 8 Collectors main components are,
- Stream.collect() method,
- Collector interface,
- and Collectors class.
collect() method, a terminal operation in Stream interface, is a special case of reduction operation called mutable reduction operation because it returns mutable result container such as List, Set or Map according to supplied Collector.
java.util.stream.Collector interface contains functions that work together to accumulate input elements into a mutable result container.
java.util.stream.Collectors class contains static factory methods that perform some common reduction operations such as accumulating elements into Collection, finding min, max, average, the sum of elements, etc. All the methods of Collectors class return Collector type which will be supplied to collect() method as an argument.
List<String> empNameList = employeeList.stream().map(emp-> emp.getName()).collect(Collectors.toList());
DoubleToIntFunction functional interface accepts a double-valued argument and produces an int-valued result.
IntConsumer.
Refer the below program.
public class SortinJava8 { public static void main(String[] args) { List<String> names = Arrays.asList(new String[]{"Banana", "Apple", "Cantalope"}); Collections.sort(names, (s1, s2) -> s1.compareTo(s2)); System.out.println(names); } }
Collection has its own elements, but Stream doesn't have. Stream works on a view, which points to elements that are actually stored by Collection or array. Any changes made on Stream don't reflect on the original Collection.
A Predicate is a functional interface that represents a function, which takes an Object and returns a boolean. It is used in several Stream methods like filter(), which uses Predicate to filter unwanted elements.
public boolean test(T object){ return boolean; }
Predicate has test() method which takes an object and returns a boolean. The method is used to test a condition if it passes; it returns true otherwise false.
public class Java8PredicateExample { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List<Integer> collect = list.stream().filter(x -> x > 5).collect(Collectors.toList()); System.out.println(collect); // [6, 7, 8, 9, 10] } }
In the above example, filter method takes a predicate x -> x > 5 as argument and filters value if it is less than 5 or not.
Java interface can have any number of abstract methods however functional interface must have only one abstract method.
The findFirst() method returns the first element that meets the criterion (i.e). Predicate, while the findAny() method return any element that meets the criterion. findAny() is very useful while working with a parallel stream.
The filter method is used to filter elements that satisfy a certain condition that is specified using a Predicate function.
A predicate function is nothing but a function that takes an Object and returns a boolean.
public class Java8FilterExample { public static void main(String[] args) { List<String> list = Arrays.asList("One","Two","Three"); List<String> filteredList = list.stream().filter(x -> x.length()>=5).collect(Collectors.toList()); System.out.println(filteredList); // prints [Three] } }
Old API. | New Date and Time API (Java 8). |
Date object is mutable. | In Java 8, all date and time classes like LocalDate, LocalTime, or LocalDateTime are Immutable. |
SimpleDateFormat is not thread-safe. | Formatter is thread-safe. |
Old Date and Calendar API has just one class Date to represent date and time. | Java 8 has separated classes for Date and Time e.g. LocalDate and LocalTime. |
In the old Date and Calendar API, the Year starts with 1900, month starts from 0, and day starts from 1. | Java 8 has got corrected numbers. |
Java 8 provides the following features:
- DateTime API,
- Lambda expressions,
- Method references,
- Functional interfaces,
- Stream API,
- Base64 Encode Decode,
- Default and Static methods in interface,
- Optional class,
- Collectors class,
- ForEach() method in Iterable interface ,
- Nashorn JavaScript Engine,
- Parallel Array Sorting,
- Type and Repating Annotations,
- IO and ConcurrencyEnhancements,
- JDBC Enhancements etc.