September 20, 2021

Java Stream - Get Last Element

In this tutorial we’ll see what options are there to get the last element of the stream using the Java Stream API.

1. Using reduce() method

reduce method in the Java Stream API is used to perform a reduction on the elements of the stream so that the stream is reduced to a single value. Thus it can be used to reduce the stream to a last value.

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

public class StreamLastDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12);
    int lastElement = numList.stream().reduce((f, s) -> s).orElse(-1);
    System.out.println("Last element in the Stream- " + lastElement);
  }
}
Output
Last element in the Stream- 12

2. Using skip() method

You can also use skip method to skip to the last element and then return that element. This approach is not very efficient though.

public class StreamLastDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    // get the stream element count
    long elementCount = numList.stream().count();
    int lastElement = -1;
    // Return -1 if not able to find last element
    if(elementCount != 0) {
      lastElement = numList.stream().skip(elementCount - 1)
                        .findFirst()
                        .orElseThrow(()->new RuntimeException("Exception Occurred"));
    }
    System.out.println("Last element in the Stream: " + lastElement);
  }
}

Output
Last element in the Stream: 22

3. Using Streams.findLast() method of Guava library

In Guava library there is a Streams class with many utility methods to be used with Stream instances. There is a findLast() method to get the last element of the stream.

import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Streams;

public class StreamLastDemo {

  public static void main(String[] args) {
    List numList = Arrays.asList(6, 10, 5, 6, 7, 8, 12, 22);
    int lastElement = Streams.findLast(numList.stream()).orElse(-1);
    System.out.println("Last element in the Stream: " + lastElement);
  }
}
Output
Last element in the Stream: 22

That's all for the topic Java Stream - Get Last Element. If something is missing or you have something to share about the topic please write a comment.


You may also like

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