September 18, 2021

flatMap() in Java Stream

When you use map operations in Java Stream resulting stream is obtained by applying the given function to all the elements of this stream. Java Stream API also provides a flatMap() method that apart from applying the given function to all the elements of this stream, flattens the resulting elements too so that all the nested elements are at the same level.

flatMap is an intermediate operation.

flatMap method signature

<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

Here mapper is a non-interfering, stateless function applied to each element of the stream.

R is the element type of the new stream.

flatMap Java examples

Let’s try to understand with few examples how flatMap() flattens the structure and how it helps.

Suppose there is an ArrayList that contains ArrayLists in turn and you want to count the total number of elements in the list. If you use map function then you will get the number of elements as 2 because map function will get each nested list as element of the stream.

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    long noOfElements = list.stream().map(a -> a.stream()).count();
    System.out.println("Number of elements- "+ noOfElements);
  }
}
Output
Number of elements- 2

When you use flatMap function, structure is flattened so that the number of elements is counted properly.

public class FlatMapExample {

  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    long noOfElements = list.stream().flatMap(a -> a.stream()).count();
    System.out.println("Number of elements- "+ noOfElements);
  }
}
Output
Number of elements- 4

If you want to display elements in nested ArrayLists in uppercase using map function returns List<Stream<String>>

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    List<Stream<String>> resultlist = list.stream()
                              .map(a -> a.stream()
                              .map(String::toUpperCase))
                              .collect(Collectors.toList());
    resultlist.forEach(a -> a.forEach(System.out::println));
  }
}

If you use flatMap in such scenario both lists are flattened so the return value is List

public class FlatMapExample {
  public static void main(String[] args) {
    List<List<String>> list = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    List<String> resultlist = list.stream()
                        .flatMap(a -> a.stream()
                        .map(String::toUpperCase))
                        .collect(Collectors.toList());
    resultlist.forEach(System.out::println);
  }
}
Output
A
B
C
D

Here is another example where we have a List of lists. There is a class Order which has a field items of type List. Now you want to display all the items in all the orders.

public class Order {
  private String orderId;
  private List<String> items;
  public String getOrderId() {
    return orderId;
  }
  public void setOrderId(String orderId) {
    this.orderId = orderId;
  }
  public List<String> getItems() {
    return items;
  }
  public void setItems(List<String> items) {
    this.items = items;
  }
}
public class FlatMapExample {
  public static void main(String[] args) {
    // Create list of orders
    List<Order> listOfOrders = new ArrayList<Order>();
    Order order = new Order();
    order.setOrderId("1");
    order.setItems(Arrays.asList("Book", "Shoes", "Watch"));
    listOfOrders.add(order);
    order = new Order();
    order.setOrderId("2");
    order.setItems(Arrays.asList("Mobile", "Book"));
    listOfOrders.add(order);

    List<String> listOfItems = listOfOrders.stream()
                          .flatMap(o -> o.getItems()
                          .stream())
                          .collect(Collectors.toList());
    listOfItems.forEach(System.out::println);
  }
}
Output
Book
Shoes
Watch
Mobile
Book

flatMap for primitive type stream

There are also flatMap() variants to be used for getting primitive type streams in Java.

  • flatMapToInt(Function<? super T,? extends IntStream> mapper)- Returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
  • flatMapToLong(Function<? super T,? extends LongStream> mapper)- Returns a LongStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
  • flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)- Returns a DoubleStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.

flatMapToInt Java example

Getting an IntStream by flattening a two dimensional array.

int[][] numbers = {{7,8}, {4,5}, {3,4}};
IntStream iStream = Stream.of(numbers).flatMapToInt(n -> Arrays.stream(n));
iStream.forEach(System.out::println);
Output
7
8
4
5
3
4

That's all for the topic flatMap() in Java Stream. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 17, 2021

map() Function in Java With Examples

In this post we’ll see examples of map() function in Java Stream API that is used to apply some transformation to the elements in a stream. When you use a map operation a new stream is returned consisting of the resultant elements after applying the given function to all the elements of source stream.

Generalized map() function in java.util.stream.Stream interface is-

<R> Stream<R> map(Function<? super T,? extends R> mapper)

Here R is the element type of the new interface.

mapper is a non-interfering, stateless function applied to each element, mapper is of type Function which is a functional interface and can be implemented as a lambda expression.

Apart from the generalized map() function there are also methods mapToInt(), mapToLong(), and mapToDouble() returning IntStream, LongStream and DoubleStream respectively which are specialized primitive type streams for these primitive data types.

In the primitive type streams there is also a mapToObj() method which Returns an object-valued Stream.

map() Java Stream examples

1- Converting each element in a Stream in upper case and collecting those elements in a List. For this requirement map() method can be used to apply upperCase functionality to all the elements of the stream and then collect the result of this transformation into a List using collect() method.

List<String> names = Stream.of("Jack", "Lisa", "Scott", "Nikita", "Tony")
			   .map(s -> s.toUpperCase())
			   .collect(Collectors.toList());	
names.forEach(System.out::println);
Output
JACK
LISA
SCOTT
NIKITA
TONY

2- Using map() method to get a new Stream having only the selected fields from the source stream. That way you can transform the stream to have elements of new type.

Let’s say there is an Employee class with name, dept, age fields and the source stream contains objects of type Employee. Requirement is to map name and dept fields to a new stream of EmpDept type.

class Employee {
  private String name;
  private String dept;
  private int salary;

  Employee(String name, String dept, int salary){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getSalary() {
    return salary;
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
}

class EmpDept {
  private String name;
  private String dept;
  EmpDept(String name, String dept){
    this.name = name;
    this.dept = dept;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
}

public class EmpStream {
  public static void main(String[] args) {
    List<Employee> employeeList = new ArrayList<>(); 

    employeeList.add(new Employee("Jack", "Finance", 5500)); 
    employeeList.add(new Employee("Lisa", "Finance", 5600)); 
    employeeList.add(new Employee("Scott", "Finance", 7000));
    employeeList.add(new Employee("Nikita", "IT", 4500));
    employeeList.add(new Employee("Tony", "IT", 8000)); 

    List<EmpDept> emp = employeeList.stream()
             .map(e -> new EmpDept(e.getName(), e.getDept()))
             .collect(Collectors.toList());
    emp.forEach(e -> System.out.println("Name- " + e.getName() + 
                        " Department- " + e.getDept()));
  }
}
Output
Name- Jack Department- Finance
Name- Lisa Department- Finance
Name- Scott Department- Finance
Name- Nikita Department- IT
Name- Tony Department- IT

3- map() with filter example- Using map method to get a new stream having employee names in finance department. Filter method is used to filter those employees not matching the given predicate.

List<String> emp = employeeList.stream()
				.filter(e -> e.getDept().equals("Finance"))
				.map(e -> e.getName())
				.collect(Collectors.toList());
							   
emp.forEach(System.out::println);
Output
Jack
Lisa
Scott

Java mapToInt() example

1- If you want to get the average of salaries for the employees, using mapToInt() method you can get an IntStream consisting of salaries and then apply average() method on that int stream.

List<Employee> employeeList = new ArrayList<>(); 

employeeList.add(new Employee("Jack", "Finance", 5500)); 
employeeList.add(new Employee("Lisa", "Finance", 5600)); 
employeeList.add(new Employee("Scott", "Finance", 7000));
employeeList.add(new Employee("Nikita", "IT", 4500));
employeeList.add(new Employee("Tony", "IT", 8000)); 

double avgSalary = employeeList.stream()
                               .mapToInt(e -> e.getSalary())
                               .average()
                               .getAsDouble();
							   
System.out.println("Average salary- " + avgSalary);
Output
Average salary- 6120.0

2- If you want to get the maximum salary, using mapToInt() method you can get an IntStream consisting of salaries and then apply max() method on that int stream.

List<Employee> employeeList = new ArrayList<>(); 

employeeList.add(new Employee("Jack", "Finance", 5500)); 
employeeList.add(new Employee("Lisa", "Finance", 5600)); 
employeeList.add(new Employee("Scott", "Finance", 7000));
employeeList.add(new Employee("Nikita", "IT", 4500));
employeeList.add(new Employee("Tony", "IT", 8000)); 

int maxSalary = employeeList.stream()
                            .mapToInt(e -> e.getSalary())
                            .max()
                            .getAsInt();
							   
System.out.println("Maximum salary- " + maxSalary);
Output
Maximum salary- 8000

That's all for the topic map() Function in Java With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 16, 2021

Java Stream Collectors.teeing() Examples

In this tutorial we’ll see how to use Collectors.teeing() method which is added in Java 12 to the Collectors class in the Java Stream API.

Collectors.teeing() method

The teeing() method let you create a composite of two Collectors and there is also a third argument; a merging function. Every element passed to the method is processed by both downstream collectors, then their results are merged using the specified merge function into the final result.

Method syntax

public static <T,R1,R2,R> Collector<T,?,R> teeing(Collector<? super T,?,R1> downstream1, Collector<? super T,?,R2> downstream2, BiFunction<? super R1,? super R2,R> merger)

Here parameters are-

  • downstream1- the first downstream collector
  • downstream2- the second downstream collector
  • merger- the function which merges two results into the single one

Collectors.teeing() Java examples

1. Getting count and sum of elements in a List using Collectors.teeing function. By passing Collectors.counting() and Collectors.summingInt() as two downstream Collectors you can do the job of both counting the number of elements and getting the sum of elements in a single operation. Merging operation does the job of storing both sum and count in a List and returning that List.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TeeingDemo {

  public static void main(String[] args) {
     List<Integer> listOfNumbers = Arrays.asList(10, 25, 9, 87, 56);
     List<Integer> list = listOfNumbers.stream()
                          .collect(Collectors.teeing(
                             Collectors.counting(), 
                             Collectors.summingInt(n -> n), 
                             (count, sum) -> {
                                List<Integer> l = new ArrayList<>();
                                l.add(count.intValue());
                                l.add(sum);
                                return l;
                              }));
     System.out.println("Number of elements in the list- " + list.get(0));
     System.out.println("Sum of elements in the list- " + list.get(1));
  }
}
Output
Number of elements in the list- 5
Sum of elements in the list- 187

2. Getting average of elements in a List. Here with in the teeing method first Collector does the job of counting elements, second Collector does the job of getting the sum of elements and the merger operation does the job of calculating average.

import java.util.List;
import java.util.stream.Collectors;

public class TeeingDemo {

  public static void main(String[] args) {
     List<Integer> listOfNumbers = List.of(10, 25, 9, 87, 56);
     Double average = listOfNumbers.stream()
                        .collect(Collectors.teeing(
                           Collectors.counting(), 
                           Collectors.summingDouble(n -> n), 
                           (count, sum) -> sum/count));
     System.out.println("Average of elements in the list- " + average);
  }
}
Output
Average of elements in the list- 37.4

3. Using Collectors.teeing() to get the employees with the maximum and minimum salaries from the List of Employee objects.

Employee class used is as given below.

public class Employee{
  private String name;
  private String dept;
  private int salary;
  private int age;
  Employee(String name, String dept, int salary, int age){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.age = age;
  }
  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
  public int getSalary() {
    return salary;
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
}

To get the maximum and minimum values Collectors.maxBy() and Collectors.minBy() methods are used.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class TeeingDemo {

  public static void main(String[] args) {
    List<Employee> empList =  getEmployeeList();
    List<Optional<Employee>> list = empList.stream()
                       .collect(Collectors.teeing(
                         Collectors.maxBy(Comparator.comparingInt(Employee::getSalary)), 
                         Collectors.minBy(Comparator.comparingInt(Employee::getSalary)), 
                            (emp1, emp2) -> {
                               List<Optional<Employee>> l = new ArrayList<>();
                                 l.add(emp1);
                                 l.add(emp2);
                                 return l;
                            }));
     System.out.println("Employee with max salary- " + (list.get(0).isPresent()? list.get(0).get().getName():null));
     System.out.println("Employee with min salary- " + (list.get(1).isPresent()? list.get(1).get().getName():null));
  }
  
    // Method to create list of employee objects
    private static List<Employee> getEmployeeList(){
        List<Employee> empList = Arrays.asList(new Employee("Ram", "IT", 12000, 34), 
                                       new Employee("Tina", "HR", 15000, 42), 
                                       new Employee("Roger", "IT", 9000, 25), 
                                       new Employee("Troy", "Accounts", 7000, 35));
        
        return empList;
    }
}
Output
Employee with max salary- Tina
Employee with min salary- Troy

That's all for the topic Java Stream Collectors.teeing() Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 15, 2021

Java Stream Collectors.partitioningBy() Examples

In this tutorial we’ll see examples of Collectors.partitioningBy() method which is part of the Collectors class in the Java Stream API.

Collectors.partitioningBy() method partitions the input elements according to a passed Predicate (which defines the condition for partitioning), and organizes them into a Map<Boolean, List> with values assigned to two keys "false" and "true" based on whether the input element passes the condition or not.

There are two overloaded Collectors.partitioningBy() methods-

1. Collector<T,?,Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)- Partitions the input elements according to the passed Predicate.

2. Collector<T,?,Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T,A,D> downstream)- In this method along with a Predicate another Collector is also passed as an argument that reduces the values in each partition, and organizes them into a Map<Boolean, D> whose values are the result of the downstream reduction.

Collectors.partitioningBy() Java examples

1. In this simple example we’ll use the partitioningBy() method to partition the list of integers into a map of even and odd numbers.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PartitioningDemo {

  public static void main(String[] args) {
    List<Integer> listOfNumbers = Arrays.asList(10, 25, 9, 87, 56, 2, 31);
    Map<Boolean, List<Integer>> numbers = listOfNumbers.stream()
                               .collect(Collectors.partitioningBy(n -> n%2 == 0));
    // false key - returns list with odd numbers
    System.out.println("Odd Numbers- " + numbers.get(false));
    // true key - returns list with even numbers
    System.out.println("Even Numbers- " + numbers.get(true));
  }
}
Output
Odd Numbers- [25, 9, 87, 31]
Even Numbers- [10, 56, 2]

In the example n -> n%2 == 0 is an implementation of the Predicate functional interface using lambda expression.

2. Partition a list of Students into those who are studying science and those who are not.

Student class used is as given below
public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getStream() {
    return stream;
  }
  public void setStream(String stream) {
    this.stream = stream;
  }
  public int getMarks() {
    return marks;
  }
  public void setMarks(int marks) {
    this.marks = marks;
  }
  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() + " Name: " + getName();
  }
}
public class PartitioningDemo {

  public static void main(String[] args) {
      List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Mahesh", "Art", 62),
              new Student(5, "Scott", "Commerce", 72));
    // List with resulting elements
    Map<Boolean, List<Student>> numbers = studentList.stream()
                             .collect(Collectors.partitioningBy(s -> s.getStream().equals("Science")));

    System.out.println("In Science stream- " + numbers.get(true));
    System.out.println("Not in Science stream- " + numbers.get(false));
  }
}
Output
In Science stream- [Roll Number: 1 Name: Peter, Roll Number: 2 Name: Ram]
Not in Science stream- [Roll Number: 3 Name: Priscilla, Roll Number: 4 Name: Mahesh, Roll Number: 5 Name: Scott]

3. Using the partitioningBy() method with two arguments. If you want to get the count of students studying science and those who are not then you can pass Collectors.counting() as the second argument.

public class PartitioningDemo {

  public static void main(String[] args) {
      List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Mahesh", "Art", 62),
              new Student(5, "Scott", "Commerce", 72));

    Map<Boolean, Long> numbers = studentList.stream()
                        .collect(Collectors.partitioningBy(s -> s.getStream().equals("Science"),
                             Collectors.counting()));

    System.out.println("Count of students in Science stream- " + numbers.get(true));
    System.out.println("Count of students not in Science stream- " + numbers.get(false));
  }
}
Output
Count of students in Science stream- 2
Count of students not in Science stream- 3

That's all for the topic Java Stream Collectors.partitioningBy() Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 14, 2021

Java Stream Collectors.groupingBy() Examples

In this tutorial we’ll see some examples of Collectors.groupingBy() method in Java Stream API. Collectors.groupingBy() method works similarly to "group by" statement in SQL which groups the elements as per the specified columns. This method also groups the elements according to the passed property and returns grouped result as a Map.

There are three overloaded Collectors.groupingBy() method-

  • Collector<T,?,Map<K,List>> groupingBy(Function<? super T,? extends K> classifier)- This method groups elements according to a classification function and returns the results in a Map. The collector produces a Map<K, List> where key specifies a group and List contains the elements which map to the associated key
  • Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)- In this groupingBy() method first elements are grouped according to a passed classification function and then reduction operation is performed on the values associated with a given key using the Collector passed as second argument.
  • Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier mapFactory, Collector<? super T,A,D> downstream)- In this variant first elements are grouped according to a passed classification function then reduction operation is performed on the values associated with a given key using the Collector passed as second argument. The resulting Map produced by the Collector is created with the supplied factory function.

Note that the returned Collector, in all the above methods, is not concurrent. There is a groupingByConcurrent() method with the same 3 overloaded methods which may offer better parallel performance. In case of groupingByConcurrent() methods a ConcurrentMap is returned.

Collectors.groupingBy() Java examples

For the example we’ll use the objects of the Student class.

public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getStream() {
    return stream;
  }
  public void setStream(String stream) {
    this.stream = stream;
  }
  public int getMarks() {
    return marks;
  }
  public void setMarks(int marks) {
    this.marks = marks;
  }
}

1. If we need to group student according to the subject stream we can use the first Collectors.groupingBy() method where only a single argument classifier function is passed.

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, List<Student>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream));
    // Iterating the returned Map
    names.entrySet().forEach(es->{System.out.println("Stream- " + es.getKey());
    System.out.println("**Students**");
    es.getValue().forEach(e->System.out.println(e.getName()));});

  }
}
Output
Stream- Art
**Students**
Priscilla
Mahesh
Stream- Science
**Students**
Peter
Ram
Stream- Commerce
**Students**
Scott

2. If you want the count of students in each stream then you need to group student according to the subject stream and also pass Collectors.counting() (which returns a collector) as a second argument.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Long> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, Collectors.counting()));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey() + 
                  " Number of Students- " + es.getValue());
              });
  }
}
Output
Stream- Art Number of Students- 2
Stream- Science Number of Students- 2
Stream- Commerce Number of Students- 1

3. If you want the Max marks in each stream then you need to group student according to the stream and also pass Collectors.maxBy (which returns a collector) as a second argument.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Optional<Student>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, Collectors.maxBy(Comparator.comparingInt(Student::getMarks))));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey() + 
                  " Student Name- " + es.getValue().get().getName() +
                  " Marks- " + es.getValue().get().getMarks());
              });
  }
}
Output
Stream- Art Student Name- Priscilla Marks- 68
Stream- Science Student Name- Ram Marks- 99
Stream- Commerce Student Name- Scott Marks- 72

4. If you want sorting to be done by keys you can return a TreeMap as a result of using groupingBy() method. In that case you have to pass one more argument which is of type Supplier and acts as a factory function.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Set<String>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, TreeMap::new, Collectors.mapping(Student::getName, Collectors.toSet())));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey());
              System.out.println("**Students**");
                es.getValue().forEach(name -> System.out.println(name));
                });
  }
}
Output
Stream- Art
**Students**
Priscilla
Mahesh
Stream- Commerce
**Students**
Scott
Stream- Science
**Students**
Peter
Ram

Collectors.groupingByConcurrent() Java example

1. If you need to group student according to the stream in parallel we can use the Collectors.groupingByConcurrent() method where only a single argument classifier function is passed.

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

public class GroupingDemo {

    public static void main(String[] args) {
        List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
                new Student(2, "Ram", "Science", 99),
                new Student(3, "Priscilla", "Art", 68),
                new Student(4, "Mahesh", "Art", 62),
                new Student(5, "Scott", "Commerce", 72));
        ConcurrentMap<String, List<Student>> names = studentList.parallelStream()
            .collect(Collectors.groupingByConcurrent(Student::getStream));
        // Iterating the returned Map
        names.entrySet().forEach(es->{System.out.println("Stream- " + es.getKey());
        System.out.println("**Students**");
        es.getValue().forEach(e->System.out.println(e.getName()));});

    }
}

That's all for the topic Java Stream Collectors.groupingBy() Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 13, 2021

Java Stream Collectors.joining() Method With Examples

In this tutorial we’ll see how to use Collectors.joining() method to concatenate the input elements into a String. It is a handy utility method provided by the Collectors class in Java Stream API to quickly convert array elements or elements in a collection to String.

There are three overloaded Collectors.joining() method-

  • Collector<CharSequence,?,String> joining()- Concatenates the input elements into a String, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter)- In this method you can also pass a delimiter, it concatenates the input elements, separated by the specified delimiter, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)- This method concatenates the input elements, separated by the specified delimiter, with the specified prefix and suffix, in encounter order.

Collectors.joining() Java Stream API examples

1. In this example we’ll pass a character array as a stream to the collect method where Collectors.joining() method is used to get a single string concatenating all the characters of the character array.

import java.util.stream.Collectors;
import java.util.stream.Stream;

public class JoiningDemo {

  public static void main(String[] args) {
    char[] ch = { 'T', 'h', 'i', 's', ' ',
                  'i', 's', ' ',
                  'S', 't', 'r', 'i', 'n', 'g' };
    String str1 = Stream.of(ch).map(c->new String(c)).collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
  }
}
Output
Concatenated String- This is String

2. In this example we’ll pass an array of String as a Stream to the collect method to get a single string. We’ll also use the joining method where delimiter is passed as an argument.

public class JoiningDemo {

  public static void main(String[] args) {
    String[] strArr = { "This", "is", "a", "String" };
    String str1 = Stream.of(strArr).collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
    
    // Passing Space as delimiter
    String str2 = Stream.of(strArr).collect(Collectors.joining(" "));
    System.out.println("Concatenated String with delimiter- " + str2);
    // Passing pipe as delimiter
    str2 = Stream.of(strArr).collect(Collectors.joining("|"));
    System.out.println("Concatenated String with delimiter- " + str2);
    
    // Passing delimiter, suffix and prefix
    String str3 = Stream.of(strArr).collect(Collectors.joining("|", "[", "]"));
    System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}
Output
Concatenated String- ThisisaString
Concatenated String with delimiter- This is a String
Concatenated String with delimiter- This|is|a|String
Concatenated String with delimiter and suffix, prefix- [This|is|a|String]

3. In this example we’ll join the elements of an ArrayList using Collectors.joining() method of the Java Stream API.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JoiningDemo {

  public static void main(String[] args) {
    List<String> cityList = Arrays.asList("Delhi", "Mumbai", "London", "New York","Bengaluru");
    String str1 = cityList.stream().collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
    
    // Passing Space as delimiter
    String str2 = cityList.stream().collect(Collectors.joining(" "));
    System.out.println("Concatenated String with delimiter- " + str2);
    // Passing pipe as delimiter
    str2 = cityList.stream().collect(Collectors.joining("|"));
    System.out.println("Concatenated String with delimiter- " + str2);
    
    // Passing delimiter, suffix and prefix
    String str3 = cityList.stream().collect(Collectors.joining("|", "[", "]"));
    System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}
Output
Concatenated String- DelhiMumbaiLondonNew YorkBengaluru
Concatenated String with delimiter- Delhi Mumbai London New York Bengaluru
Concatenated String with delimiter- Delhi|Mumbai|London|New York|Bengaluru
Concatenated String with delimiter and suffix, prefix- [Delhi|Mumbai|London|New York|Bengaluru]

That's all for the topic Java Stream Collectors.joining() Method With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 11, 2021

Java Stream Sort on Multiple Fields

In this tutorial you’ll see how to sort stream of objects on multiple fields.

Sort stream of objects on multiple fields

To sort a stream of objects on multiple fields you need to use two methods-

1. Stream<T> sorted(Comparator<? super T> comparator)- sorts the elements of this stream according to the provided Comparator.

2. Since sorting is to be done on multiple fields for that you can compose several Comparators using thenComparing(Comparator<? super T> other) method.

Comparator.comparing(COMPARISON_LOGIC)
          .thenComparing(COMPARISON_LOGIC);

Java Stream sorting with multiple fields example

For the example we’ll use the object of User class which has two fields name and age.

public class User {
  private String name;
  private int age;
  User(String name, int age){
    this.name = name;
    this.age = age;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  @Override
  public String toString() {
    return getName() + " " + getAge() + " \n";
  } 
}

If we want to sort on name as well as on age in descending order then it can be done using sorted method of the Java Stream API as given below.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSort {

  public static void main(String[] args) {
      List<User> userList = Arrays.asList(new User("Peter", 75),
              new User("Ram", 19),
              new User("Peter", 68),
              new User("Mahesh", 32),
              new User("Scott", 32));
      userList = userList.stream()
                         .sorted(Comparator.comparing(User::getName)
                                  .thenComparing(Comparator.comparingInt(User::getAge).reversed()))
                         .collect(Collectors.toList());
      System.out.println(userList);

  }
}
Output
[Mahesh 32 
, Peter 75 
, Peter 68 
, Ram 19 
, Scott 32 
]

To make it clearer here is the elongated version with pre-defined Comparators.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSort {

  public static void main(String[] args) {
      List<User> userList = Arrays.asList(new User("Peter", 75),
              new User("Ram", 19),
              new User("Peter", 68),
              new User("Mahesh", 32),
              new User("Scott", 32));
      
      Comparator<User> compByName = Comparator.comparing(User::getName);
      Comparator<User> compByAge = Comparator.comparingInt(User::getAge).reversed();
      userList = userList.stream()
                         .sorted(compByName
                               .thenComparing(compByAge))
                         .collect(Collectors.toList());
      System.out.println(userList);
  }
}

That's all for the topic Java Stream Sort on Multiple Fields. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 10, 2021

Java Stream sorted() With Examples

In this tutorial we’ll see how to use Java Stream sorted() method with the help of few examples.

Syntax of sorted() method in Java Stream API

There are two variants of sorted() method.

  1. Stream<T> sorted()- Used to sort the elements of the stream according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
  2. Stream<T> sorted(Comparator<? super T> comparator)- Used to sort the elements of the stream according to the provided Comparator.

sorted() in Java Stream is a stateful intermediate operation which means it may incorporate state from previously seen elements when processing new elements.

Let us try to understand sorted() method better with the help of some Java examples.

Sort List of integers in natural order

import java.util.List;
import java.util.stream.Collectors;

public class SortedDemo {

  public static void main(String[] args) {
    // Till Java 8
    //List<Integer> myList = Arrays.asList(11, 1, 9, 1, 4, 11, 17);
    // From Java 9
    List<Integer> myList = List.of(11, 1, 9, 1, 4, 11, 17);
    List<Integer> sortedList = myList.stream().sorted().collect(Collectors.toList());
    System.out.println(sortedList);
  }
}
Output
[1, 1, 4, 9, 11, 11, 17]

Since Integer class implements Comparable (compareTo() method) so that becomes the natural ordering for the element while sorting them using sorted() method.

Sort List of integers in reverse order

Sort List of integers in reverse order using sorted() method where Comparator is passed.

public class SortedDemo {

  public static void main(String[] args) {
    // Till Java 8
    //List<Integer> myList = Arrays.asList(11, 1, 9, 1, 4, 11, 17);
    // From Java 9
    List<Integer> myList = List.of(11, 1, 9, 1, 4, 11, 17);
    List<Integer> sortedList = myList.stream()
                     .sorted(Comparator.reverseOrder())
                     .collect(Collectors.toList());
    System.out.println(sortedList);
  }
}
Output
[17, 11, 11, 9, 4, 1, 1]

Sort List of Strings

Since String class in Java also implements Comparable interface so that becomes the natural ordering for the element while sorting them using sorted() method.

public class SortedDemo {

  public static void main(String[] args) {
    // Till Java 8
    //List<String> myList = Arrays.asList("Ram", "Madan", "Jack", "Ram", "Jack");
    // From Java 9
    List<String> myList = List.of("Ram", "Madan", "Jack", "Ram", "Jack");
    List<String> sortedList = myList.stream()
                    .sorted()
                    .collect(Collectors.toList());
    System.out.println(sortedList);
  }
}
Output
[Jack, Jack, Madan, Ram, Ram]

Sorting List of custom objects

With List containing Integers and Strings sorting doesn’t require any extra effort as both of these classes already implement Comparable defining the natural ordering. With custom objects you do need to implement Comparable and provide natural ordering.

Student class used in the example is as given below-

public class Student implements Comparable<Student> {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

  public String getStream() {
    return stream;
  }
  public void setStream(String stream) {
    this.stream = stream;
  }
  public int getMarks() {
    return marks;
  }
  public void setMarks(int marks) {
    this.marks = marks;
  }
  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
  @Override
  public int compareTo(Student student) {
    return this.getName().compareTo(student.getName());
  }
}

As you can see compareTo() method implementation provides sorting on name so that is the natural ordering for the Student class objects.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SortedDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Ajay", "Art", 67),
              new Student(5, "Dan", "Biology", 77));
    List<Student> sortedList = studentList.stream()
                                          .sorted()
                                          .collect(Collectors.toList());
    for(Student student: sortedList) {
      System.out.println(student);
    }  
  }
}
Output
Roll Number: 4 Name: Ajay Marks: 67
Roll Number: 5 Name: Dan Marks: 77
Roll Number: 1 Name: Peter Marks: 75
Roll Number: 3 Name: Priscilla Marks: 68
Roll Number: 2 Name: Ram Marks: 99

You can also provide your own Comparator implementation by using the sorted method that takes Comparator as an argument. For example suppose you want the List of students sorted by marks.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SortedDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Ajay", "Art", 67),
              new Student(5, "Dan", "Biology", 77));
    List<Student> sortedList = studentList.stream()
                                          .sorted((s1, s2) -> s1.getMarks()-s2.getMarks())
                                          .collect(Collectors.toList());
    for(Student student: sortedList) {
      System.out.println(student);
    }  
  }
}
Output
Roll Number: 4 Name: Ajay Marks: 67
Roll Number: 3 Name: Priscilla Marks: 68
Roll Number: 1 Name: Peter Marks: 75
Roll Number: 5 Name: Dan Marks: 77
Roll Number: 2 Name: Ram Marks: 99

Sorting a Set using Java Stream sorted() method

Sorting a Set is similar to sorting a List. You can create a Stream using the Set and call the sorted() method.

import java.util.HashSet;
import java.util.Set;

public class SortedDemo {
  public static void main(String[] args) {
      Set<String> nameSet = new HashSet<>();
      nameSet.add("Ram");
      nameSet.add("Peter");
      nameSet.add("Ajay");
      nameSet.add("Priscilla");
      nameSet.add("Dan");
      
      nameSet.stream()
             .sorted()
             .forEach(System.out::println);
  }
}
Output
Ajay
Dan
Peter
Priscilla
Ram

Sorting a Map using Java Stream sorted() method

You can sort a HashMap using sorted() method too. In the following example a HashMap is sorted on its values.

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class SortedDemo {

  public static void main(String[] args) {
    Map<Integer, String> nameMap = new HashMap<>();
      nameMap.put(1, "Ram");
      nameMap.put(2, "Peter");
      nameMap.put(3, "Ajay");
      nameMap.put(4, "Priscilla");
      nameMap.put(5, "Dan");
      
      System.out.println("-- Original Map --");
      for(Map.Entry<Integer, String> name : nameMap.entrySet()) {
        System.out.println("Key- " + name.getKey() + 
                        " Value- " + name.getValue());
      }
      
      Map<Integer, String> newMap = nameMap.entrySet()
                         .stream()
                         .sorted(Map.Entry.comparingByValue())
                         .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, 
                                  (k,v)->k, LinkedHashMap<Integer, String>::new));
      System.out.println("-- Sorted Map --");
      newMap.entrySet().forEach((e)->{System.out.println("Key- " + e.getKey() + " Value- " + e.getValue());});
  }
}
Output
-- Original Map --
Key- 1 Value- Ram
Key- 2 Value- Peter
Key- 3 Value- Ajay
Key- 4 Value- Priscilla
Key- 5 Value- Dan
-- Sorted Map --
Key- 3 Value- Ajay
Key- 5 Value- Dan
Key- 2 Value- Peter
Key- 4 Value- Priscilla
Key- 1 Value- Ram

To sort on key you can use Map.Entry.comparingByKey() method.

That's all for the topic Java Stream sorted() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 8, 2021

Java Stream max() and min() With Examples

Java Stream API provides two methods max() and min() where-

  • max()- Returns the maximum element of this stream according to the provided Comparator.
  • min()- Returns the minimum element of this stream according to the provided Comparator.

Java Stream max() method

Syntax of the max() method in Java Stream API is as given below

Optional<T> max(Comparator<? super T> comparator)

Method returns an Optional describing the maximum element of this stream, or an empty Optional if the stream is empty. This is a terminal operation.

max() method Java examples

1. In this simple example we’ll use a List as a source of Stream and get the maximum element of the List.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class MaxDemo {

  public static void main(String[] args) {
    // Till Java 8
    //List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
    // From Java 9
    List<Integer> myList = List.of(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
    Optional<Integer> max = myList.stream().max(Integer::compare);
    if(max.isPresent()){
      System.out.println("Maximum element in the List " + max.get());
    }
  }
}
Output
Maximum element in the List 98

2. In this example we’ll get the maximum salary from the List of Employee objects.

Employee class used is as given below.

public class Employee{
  private String name;
  private String dept;
  private int salary;
  private int age;
  Employee(String name, String dept, int salary, int age){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.age = age;
  }
  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
  public int getSalary() {
    return salary;
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
  @Override
  public String toString() {
    // TODO Auto-generated method stub
    return "Name- " + getName() + " Dept- " + getDept() + 
        " Salary- " + getSalary();
  }
}

To get the maximum salary you can first use mapToInt() method to get an IntStream consisting of employee salaries, then use max() method.

import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;

public class MaxDemo {

  public static void main(String[] args) {

    List<Employee> empList =  getEmployeeList();
    OptionalInt maxSal = empList.stream()
                                .mapToInt(Employee::getSalary)
                                .max();
    if(maxSal.isPresent()){
      System.out.println("Maximum Salary: " + maxSal.getAsInt());
    }
  }
  
    // Method to create list of employee objects
    private static List<Employee> getEmployeeList(){
        List<Employee> empList = Arrays.asList(new Employee("Ram", "IT", 12000, 34), 
                                       new Employee("Tina", "HR", 15000, 42), 
                                       new Employee("Roger", "IT", 9000, 25), 
                                       new Employee("Troy", "Accounts", 7000, 35));
        
        return empList;
    }
}
Output
Maximum Salary: 15000

If you want the employee object for the employee having maximum salary that can be done as given below-

Optional emp = empList.stream().max(Comparator.comparing(Employee::getSalary));
if(emp.isPresent()){
    System.out.println("Employee With Maximum Salary: " + emp.get());
}

Java Stream min() method

Syntax of the min() method in Java Stream API is as given below.

Optional<T> min(Comparator<? super T> comparator)

This method returns an Optional describing the minimum element of this stream, or an empty Optional if the stream is empty. This is a terminal operation.

min() method Java examples

1. In this simple example we’ll use a List as a source of Stream and get the minimum element of the List.

import java.util.List;
import java.util.Optional;

public class MinDemo {
  public static void main(String[] args) {
    // Till Java 8
    //List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
    // From Java 9
    List<Integer> myList = List.of(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
    Optional<Integer> max = myList.stream().min(Integer::compare);
    if(max.isPresent()){
      System.out.println("Minimum element in the List " + max.get());
    }
  }
}
Output
Minimum element in the List 0

2. From the list of employees get the youngest employee. Employee class used is same as already displayed above.

import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;

public class MinDemo {
  public static void main(String[] args) {

    List<Employee> empList =  getEmployeeList();
    OptionalInt minAge = empList.stream()
                                .mapToInt(Employee::getAge)
                                .min();
    if(minAge.isPresent()){
      System.out.println("Employee with minimum age: " + minAge.getAsInt());
    }
  }
  
    // Method to create list of employee objects
    private static List<Employee> getEmployeeList(){
        List<Employee> empList = Arrays.asList(new Employee("Ram", "IT", 12000, 34), 
                                       new Employee("Tina", "HR", 15000, 42), 
                                       new Employee("Roger", "IT", 9000, 25), 
                                       new Employee("Troy", "Accounts", 7000, 35));
        
        return empList;
    }
}
Output
Employee with minimum age: 25

That's all for the topic Java Stream max() and min() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 6, 2021

Java Stream filter() With Examples

In the Java Stream API tutorial we have gone through the intermediate and terminal operations, in this tutorial we’ll go through Java Stream filter() method in detail.

Java Stream filter method

filter() is an intermediate operation which returns a stream consisting of the elements of this stream that match the given condition.

Stream<T> filter(Predicate<? super T> predicate)

Condition passed as argument to the filter method is an implementation of the Predicate which is a functional interface where you implement a boolean valued function.

Java Stream filter method examples

1. In this simple example we have a List of numbers and using filter method we get a new Stream of only those numbers which are greater than 5.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class FilterDemo {
  public static void main(String[] args) {
    // List of numbers
    List<Integer> myList = Arrays.asList(17, 4, 23, 34, 1, 5, 8, 10);  
    Stream<Integer> myStream = myList.stream().filter(n -> n > 5);
    myStream.forEach(System.out::println);
  }
}
Output
17
23
34
8
10

2. Filtering and collecting to a List. You can also convert the returned stream from the filter() method to a list by using Collectors.toList() method.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterDemo {
  public static void main(String[] args) {
    // List of numbers
    List<Integer> myList = Arrays.asList(17, 4, 23, 34, 1, 5, 8, 10);  
    // List with resulting elements
    List<Integer> newList = myList.stream().filter(n -> n > 5).collect(Collectors.toList());
    newList.forEach(System.out::println);
  }
}

3. Java Stream filter example with multiple conditions. You can also combine several conditions by using conditional operators and(&&), or(||). For example from the list of numbers if you want only those numbers which are greater than 5 and also even.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilterDemo {
  public static void main(String[] args) {
    // List of numbers
    List<Integer> myList = Arrays.asList(17, 4, 23, 34, 1, 5, 8, 10);  
    // List with resulting elements
    List<Integer> newList = myList.stream().filter(n -> n > 5 && n % 2 == 0).collect(Collectors.toList());
    newList.forEach(System.out::println);
  }
}
Output
34
8
10

Predicate interface also provide methods to compose more than one Predicate. There are the following methods in Predicate which can also be used.

and(Predicate<? super T> other), or(Predicate<? super T> other), not(Predicate<? super T> target)

Here is the example shown above written using Predicate.and() method.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class FilterDemo {
  public static void main(String[] args) {
    // List of numbers
    List<Integer> myList = Arrays.asList(17, 4, 23, 34, 1, 5, 8, 10); 
    Predicate<Integer> p1 = n -> n > 5;
    Predicate<Integer> p2 = n -> n % 2 == 0;
    // List with resulting elements
    List<Integer> newList = myList.stream().filter(p1.and(p2)).collect(Collectors.toList());
    newList.forEach(System.out::println);
  }
}

4. Here is another example of using multiple conditions with filter method. For the example we’ll use the objects of the Student class.

public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getStream() {
    return stream;
  }
  public void setStream(String stream) {
    this.stream = stream;
  }
  public int getMarks() {
    return marks;
  }
  public void setMarks(int marks) {
    this.marks = marks;
  }
  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() + " Name: " + getName();
  }
}

If you want to get the list of Students that belong to Science stream or Commerce stream that can be done by joining conditions using or.

public class FilterDemo {
  public static void main(String[] args) {
      List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Mahesh", "Art", 62),
              new Student(5, "Scott", "Commerce", 72));
    // List with resulting elements
    List<Student> newList = studentList.stream().filter(s -> s.getStream().equals("Science") || s.getStream().equals("Commerce"))
                          .collect(Collectors.toList());
    newList.forEach(System.out::println);
  }
}
Output
Roll Number: 1 Name: Peter
Roll Number: 2 Name: Ram
Roll Number: 5 Name: Scott

If you want to use Predicate.or() method then the same example can be written as given below.

public class FilterDemo {
  public static void main(String[] args) {
      List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Mahesh", "Art", 62),
              new Student(5, "Scott", "Commerce", 72));
    Predicate<Student> p1 = s -> s.getStream().equals("Science");
    Predicate<Student> p2 = s -> s.getStream().equals("Commerce");
    // List with resulting elements
    List<Student> newList = studentList.stream().filter(p1.or(p2)).collect(Collectors.toList());
    newList.forEach(System.out::println);
  }
}

That's all for the topic Java Stream filter() With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 4, 2021

Java Stream skip() Method With Examples

The skip(long n) method in the Java Stream API skips the first n element of the stream and returns a new stream consisting of the remaining elements of this stream.

skip method in Java Stream

Syntax of the method is as given below.

Stream<T> skip(long n)

Here n is the number of leading elements to skip. If you pass n as negative then IllegalArgumentException is thrown.

Points about skip method

  1. It is a stateful intermediate operation which means it will return a new Stream.
  2. If number of elements to skip (n) is greater than the elements contained in the Stream then an empty stream will be returned.
  3. skip(n) is constrained to skip not just any n elements, but the first n elements in the encounter order.
  4. skip() is generally a cheap operation on sequential stream pipelines.
  5. skip() can be quite expensive on ordered parallel pipelines, if n is a fairly large values, because of the constraint to skip first n elements in the encounter order.

skip() Java Example

Here we’ll try to get a sublist from a List using skip method. Method getSubListBySkipping() is a generic method that can work with any type of List, second argument passed to the method is the number of elements to be skipped. Results of the stream returned by skip() method are collected to a list and that new list is returned.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SkipDemo {

  public static void main(String[] args) {
    SkipDemo sd = new SkipDemo();
    // Used with list of Strings
    List<String> cityList = Arrays.asList("Delhi", "Mumbai", "London", "New York","Bengaluru");
    List<String> newList = sd.getSubListBySkipping(cityList, 3);
    System.out.println("List after skipping elements- " + newList);
    // Used with list of Integers
    List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    List<Integer> tempList = sd.getSubListBySkipping(numList, 7);
    System.out.println("List after skipping elements- " + tempList);
  }

  // This method uses skip method to skip n elements
  public <T> List<T> getSubListBySkipping(List<T> originalList, long n){
    return originalList.stream().skip(n).collect(Collectors.toList());
  }
}
Output
List after skipping elements- [New York, Bengaluru]
List after skipping elements- [8, 9, 10]
That's all for the topic Java Stream skip() Method With Examples. If something is missing or you have something to share about the topic please write a comment.
You may also like

September 3, 2021

Java Stream - Reduction Operations And Reduce Method

In this post we’ll see what are reduction operations in Java Stream API and how to use general-purpose reduction operation Stream.reduce() method.

Reduction operations in Java Stream

With in the Java Stream API there are many terminal operations (like average, sum, min, max, and count) that return one value by combining the contents of a stream. These operations are called reduction operations.

For example using the count reduction operation to count the number of elements in a List.

List<Integer> myList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
long count = myList.stream().count();
System.out.println("Count of elements in the list- " + count);
Output
Count of elements in the list- 10

Reduce methods in Java Stream

Java Stream API also has a general purpose reduce method to perform a reduction on the elements of the stream using the passed accumulator and returns a reduced value. Reduce method is overloaded and has 3 variants.

1. Optional<T> reduce(BinaryOperator<T> accumulator)- Performs a reduction on the elements of this stream, using an associative accumulation function and returns an Optional describing the reduced value, if any.

Accumulator is of type BinaryOperator which is a functional interface representing an operation upon two operands of the same type. The accumulator function takes two parameters: a partial result of the reduction and the next element of the stream.

Stream.reduce() with Accumulator example

Let’s say there is an Employee class with name, dept, salary fields. You need to find out the total salary using the Stream.reduce() method.

public class Employee {
  private String name;
  private String dept;
  private int salary;

  Employee(String name, String dept, int salary){
    this.name = name;
    this.dept = dept;
    this.salary = salary;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getSalary() {
    return salary;
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
  public String getDept() {
    return dept;
  }
  public void setDept(String dept) {
    this.dept = dept;
  }
}

Using reduce method by passing an accumulator function, which is a lambda expression in this example that adds two Integer values and returns an Integer value, you can get the total salary.

List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee("Jack", "Finance", 5500));
employeeList.add(new Employee("Lisa", "Accounts", 5600));
employeeList.add(new Employee("Nikita", "IT", 4500));
employeeList.add(new Employee("Tony", "HR", 8000));
Optional<Integer> totalSalary = employeeList.stream().map(e -> e.getSalary()).reduce((a,b) -> a+b);
if(totalSalary.isPresent()){
  System.out.println("Total Salary- " + totalSalary.get());
}
Output
Total Salary- 23600

2. reduce(T identity, BinaryOperator<T> accumulator)- Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value.

  • identity- The identity element is both the initial value of the reduction and the default result if there are no elements in the stream.
  • accumulator- The accumulator function is an implementation of BinaryOperator which is a functional interface representing an operation upon two operands of the same type. The accumulator function takes two parameters: a partial result of the reduction and the next element of the stream

Stream.reduce() with Identity and Accumulator example

We can use the same example as above, only change is in the reduce method which now also passes an identity element as 0. This is the initial value of the sum of salaries and the default value if no members exist in the collection employeeList. Now the return type of the reduce method is also int.

List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee("Jack", "Finance", 5500));
employeeList.add(new Employee("Lisa", "Accounts", 5600));
employeeList.add(new Employee("Nikita", "IT", 4500));
employeeList.add(new Employee("Tony", "HR", 8000));
int totalSalary = employeeList.stream().map(e -> e.getSalary()).reduce(0, (a,b) -> a+b);
System.out.println("Total Salary- " + totalSalary);

3. reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)- Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions.

Combiner function is used for combining results of accumulator function, it must be compatible with the accumulator function. Combiner function is necessary when parallel stream is used in order to combine result of accumulators running in parallel.

Stream.reduce() with Identity, Accumulator and Combiner example

int value = Stream.of(1, 2, 3, 4, 5).parallel().reduce(1, (a, b) -> a*b, 
				(x,y) -> { System.out.println("In combiner function");
				           return x*y;});
System.out.println("Value- " + value);
Output
In combiner function
In combiner function
In combiner function
In combiner function
Value- 120

That's all for the topic Java Stream - Reduction Operations And Reduce Method. If something is missing or you have something to share about the topic please write a comment.


You may also like

September 1, 2021

Java Stream API With Examples

The way Lambda expressions in Java brought functional programming to Java another addition in Java 8, Stream API in Java brought functional approach to processing collections of objects. Using Java Stream API you can create a stream over an object and then you just need to specify what needs to be done not how it has to be done.

For example if you want to count the elements in the stream, you need to specify the source for obtaining a stream and the function to count the elements. Stream API takes care of executing stream pipeline in an optimized way.

List<Integer> myList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
long count = myList.stream().count();
System.out.println("Count of elements in the list- " + count);

In the above example List myList is the data source for the stream and count is the stream operation performed on the stream.

In this Java Stream API tutorial we’ll see how to create streams, types of streams and various stream operation examples. Since the examples use lambda expressions and functional interfaces so make sure that you are familiar with those topics.

Java Stream API – Interfaces and Classes

Java Stream API contains several interfaces and classes which are packaged with in the java.util.stream package. At the top of the hierarchy is interface BaseStream providing basic functionality for all the Streams.

BaseStream interface is extended by interfaces- DoubleStream, IntStream, LongStream and Stream. Stream interface is a generic interface which is used for all reference types.

DoubleStream, IntStream and LongStream are primitive specializations of Stream that can store primitive values.

Read more about Primitive Streams in this post- Primitive Type Streams in Java

One of the important class with in Java Stream API is Collectors class that is an implementation of Collector interface, this class implements various useful reduction operations.

Read more about Collectors class in this post- Collectors Class And collect() Method in Java

Creating a Stream

With in the Java Stream API there are number of ways to obtain a stream.

1. Stream from Collection- Stream can be created from any type of Collection via the stream() and parallelStream() methods.

List<Integer> myList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
Stream<Integer> myStream = myList.stream();

2. Stream from an array- Stream can be obtained from an array via Arrays.stream(Object[]);

String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);

3. Using Stream.of() method- Stream can also be created using static factory method Stream.of(Object[])

Stream<String> stream = Stream.of("a", "b", "c");

4. Using range and iterate methods- Using range method you can get a primitive stream.

IntStream stream = IntStream.range(1, 10);

Same thing (getting stream of integers 1-9) can be achieved by using the iterate method-

Stream<Integer> stream = Stream.iterate(1, n-> n < 10, n->n+1);

5. Creating empty stream- You can create an empty stream using empty method.

Stream<Integer> stream = Stream.empty();

6. To get lines of a file as a stream you can use BufferedReader.lines() method.

Path path = Paths.get("D:\\KnpCode\\test.txt");
Stream<String> lines = Files.newBufferedReader(path).lines();

Types of Stream operations

Stream operations are divided into two types-

  • intermediate operations
  • terminal operations

Intermediate operations in Java Streams

Intermediate operations return a new stream. This new stream is a result of applying intermediate operation on the source stream. Intermediate operations are always lazy and these operations are executed only when a terminal operation is executed.

For example executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

Intermediate operations are further divided into two categories-

  1. Stateless operations- Stateless operations, such as filter and map, retain no state from previously seen element when processing a new element, each element can be processed independently of operations on other elements.
  2. Stateful operations- Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when processing new elements.

Some of the examples of intermediate operations in Java Stream API are filter, map, flatMap, distinct, sorted, limit.

Examples of intermediate stream operations

1. filter()- In filter method Predicate is passed as an argument and method returns a stream consisting of the elements of this stream that match the given predicate. Predicate is a functional interface which can be implemented as a lambda expression.

From an ArrayList you want to filter elements less than 5.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);  
Stream<Integer> myStream = myList.stream().filter(n -> n > 5);
myStream.forEach(System.out::println);
Output
11
9
98
17
8

2. map()- Using map method you can map (convert) each element in the stream to another object. Method returns a stream consisting of the results of applying the given function to the elements of this stream.

If you have a List of Strings and you want to apply upper case function to each string.

List<String> myList = Arrays.asList("rose", "lotus", "lily", "orchid");  
myList.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
Output
ROSE
LOTUS
LILY
ORCHID

3. flatMap()- The flatMap() operation applies a one-to-many transformation to the elements of the stream and also flattens the resulting structure into a new stream. If you have an object with many nested objects flatMap() operation brings all the nested level objects to the same level by flattening the structure.

If you want to produce a stream of the words contained in the Strings in the array.

Stream<String> lineStream = Arrays.stream(lines);
Stream<String> str = lineStream.flatMap(line -> Stream.of(line.split(" +")));

4. distinct()- Returns a stream consisting of the distinct elements of this stream.

distinct() method of the Java Stream API provides a best option to remove duplicates from a List.

List<Integer> ListWithDuplicates = Arrays.asList(7, 8, 9, 7, 4, 2, 4, 1);
List<Integer> uniqueElementList = ListWithDuplicates.stream().distinct().collect(Collectors.toList());
System.out.println("List after removing duplicates : " + uniqueElementList);
Output
List after removing duplicates : [7, 8, 9, 4, 2, 1]

5. sorted()- Returns a stream consisting of the elements of this stream, sorted according to natural order. This is a stateful intermediate operation.

List<Integer> myList = Arrays.asList(7, 8, 9, 7, 4, 2, 4, 1);
myList.stream().sorted().forEach(System.out::println);
Output
1
2
4
4
7
7
8
9

6. limit()- Using limit() method you can limit the number of elements in a Stream to the size passed with limit() method.

List<Integer> myList = Arrays.asList(7, 8, 9, 7, 4, 2, 4, 1);
myList.stream().limit(3).forEach(System.out::println);
Output
7
8
9

Terminal operations in Java Streams

Once the terminal operation is performed in a Stream, the stream pipeline is considered consumed. Same stream can no longer be used; if you need to traverse the same data source again, you must return to the data source to get a new stream.

Terminal operations are eager (except iterator() and spliterator() methods) , completing their traversal of the data source and processing of the pipeline before returning.

Some of the examples of terminal operations in Java Stream API are forEach, reduce, collect, min, max, count, findFirst.

Examples of Terminal stream operations

1. forEach()- In the forEach method a Consumer is passed as an argument and this Consumer action is performed on each element of this stream.

List<String> myList = Arrays.asList("rose", "lotus", "lily", "orchid");
myList.stream().forEach(System.out::println);
Output
rose
lotus
lily
orchid

2. reduce()- Reduce operation reduce the stream to a single non-stream value. This method returns an Optional describing the result of the reduction.

You can find max element in a Collection using reduce method.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
Optional<Integer> max = myList.stream().reduce((n1, n2) -> n1 > n2 ? n1:n2);
if(max.isPresent()){
  System.out.println("Max element in the List " + max.get());
}
Output
Max element in the List 98

3. collect()- Java Stream API’s collect() method is used to collect the Stream elements in a mutable container like a List, StringBuilder.

In the example list is filtered to filter out all the elements less than 5 and the stream elements are collected in a TreeSet which sorts the resulting elements.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
Set<Integer> sortedSet = myList.stream().filter(n->n>5).collect(Collectors.toCollection((TreeSet::new)));
System.out.println("Sorted set- " + sortedSet);
Output
Sorted set- [8, 9, 11, 17, 98]

4. min()- Returns the minimum element of this stream according to the provided Comparator. This method returns an Optional describing the minimum element of this stream.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
Optional<Integer> min = myList.stream().min(Integer::compare);
if(min.isPresent()){
  System.out.println("Minimum element in the List " + min.get());
}
Output
Minimum element in the List 0

5. max()- Returns the maximum element of this stream according to the provided Comparator. This method returns an Optional describing the maximum element of this stream.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
Optional<Integer> max = myList.stream().max(Integer::compare);
if(max.isPresent()){
  System.out.println("Maximum element in the List " + max.get());
}
Output
Maximum element in the List 98

6. count()- Returns the count of elements in this stream.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
long count = myList.stream().count();
System.out.println("Count of elements in the list- " + count);
Output
Count of elements in the list- 10

7. findFirst()- Java Stream API's findFirst() method returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
Optional<Integer> value = myList.stream().findFirst();
if(value.isPresent()){
  System.out.println("First Element- " + value.get());
}
Output
First Element- 11

Stream pipeline in Java Stream

A data source (such as a Collection, an array, a generator function, or an I/O channel) followed by zero or more intermediate operations and a terminal operation together form a stream pipeline.

Java Stream API
Stream pipeline example

In the following example stream source is an ArrayList. First intermediate operation is a map operation which adds 10 to each element in the Stream, in another operation elements are sorted. Then the elements are displayed using forEach terminal operation, at this point the stream is consumed.

List<Integer> myList = Arrays.asList(11, 1, 9, 4, 98, 0, 17, 8, 2, 3);
myList.stream().map(n -> n + 10).sorted().forEach(System.out::println);

Collection Vs Stream API

Streams differ from collections on several points-

  1. No Storage- Unlike Collections a stream is not a data structure that stores elements. In a stream, elements from a data source are moved through a pipeline while going through computational operations at each intermediate step.
  2. Functional in nature- Java Stream API is functional in nature bringing functional approach to processing collections of objects. An operation on a stream produces a result, but does not modify its source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection.
  3. Lazy invocation- Intermediate operations in the Java Stream API are always lazy providing opportunities for optimization.
  4. Possibly unbounded- While collections have a finite size, streams need not. Short-circuiting operations such as limit(n) or findFirst() can allow computations on infinite streams to complete in finite time.
  5. Streams are Consumable- The elements of a stream are only visited once during the life of a stream, once a terminal operation is encountered with in a Stream pipeline, stream is considered consumed. After a stream is consumed a new stream must be generated to revisit the same elements of the source.
Reference: https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/util/stream/package-summary.html

That's all for the topic Java Stream API With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like