Stream – Java2Blog https://java2blog.com A blog on Java, Python and C++ programming languages Thu, 20 May 2021 17:43:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.9 https://java2blog.com/wp-content/webpc-passthru.php?src=https://java2blog.com/wp-content/uploads/2022/09/cropped-ICON_LOGO_TRANSPARENT-32x32.png&nocache=1 Stream – Java2Blog https://java2blog.com 32 32 A In-Depth guide to Java 8 Stream API https://java2blog.com/java-8-stream/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream https://java2blog.com/java-8-stream/#comments Thu, 27 Aug 2020 18:30:48 +0000 https://java2blog.com/?p=9554 In this post, we will see an in-depth overview of Java 8 streams with a lot of examples and exercises.

Introduction

You may think that Stream must be similar to InputStream or OutputStream, but that’s not the case.

A Stream represents a sequence of elements supporting sequential and parallel aggregate operations. Stream does not store data, it operates on source data structures such as List, Collection, Array etc.

Most stream operations accept functional interfaces that make it a perfect candidate for lambda expressions.

If you are not well versed with functional interfaces, lambda expressions, and method references, you may want to read the following tutorials before moving ahead.

Types of Stream operations

There are two types of Stream operations.

  1. Intermediate operations: return a stream that can be chained with other intermediate operations with dot .
  2. Terminal operations: return void or non stream output.

Let’s understand with the help of simple example.

package org.arpit.java2blog.stream;

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

public class StreamOperations {

    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("John", "Martin", "Mary", "Steve");

        stringList.stream()
                   .map((s) -> s.toUpperCase())
                   .forEach(System.out::println);
    }
}

Output:

JOHN
MARTIN
MARY
STEVE

Here,
To perform a computation, stream operations are built into a Stream pipeline. Stream pipeline consists of:

  1. source
  2. zero or more intermediate operations
  3. terminal operation.

In our example, Stream pipeline consists of:
Source: stringList
1 Intermediate operation: Map
1 terminal operation: forEach

The below diagram will make it more clear.
map is intermediate operation and foreach is terminal opertion.
StreamBasic

Most stream operations accept parameters as that describes user-defined behaviour, such as lambda expression map((s)->s.toUpperCase()) is passed to map operation.

To get correct behavior, streams parameters should be:
non-interfering: Stream source should not be modified while execution of Stream pipline. You can learn more about interference.
Stateless: In most cases, lambda expressions should be stateless. Its output should not depend on state that might change during execution of Stream pipeline. I have already covered stateful lambda expression in Parallel Stream tutorial.

Stream creation

There are multiple ways to create the Stream.

Empty Stream

empty() method can be used to create an empty stream.

Stream s = Stream.empty()

It is generally used to return Stream with zero elements rather than null.

Collection Stream

Stream can be created from Collection by calling .stream() or .parallelStream()

List stringList=Arrays.asList("Andy","Peter","Amy","Mary");

stringList.stream()
.map((s)->s.toUpperCase())
.forEach(System.out::println);

stringList.stream() will return you regular object stream.

Stream.of

You don’t need to create collection to get a Stream. You can also use .of()

Stream streamArray =Stream.of("X","Y","Z");

Stream.generate()

generate() method accepts Supplier for element generation. It creates infinite Stream and you can limit it by calling limit() function.

Stream<Integer> intStream=Stream.generate(() -> 1).limit(5);
intStream.forEach(System.out::println);
// Output
// 1
// 1
// 1
// 1
// 1

This will create Integer stream with 10 elements with value 1.

Stream.iterate()

Stream.iterate() can also be used to generate infinite stream.

Stream<Integer> intStream = Stream.iterate(100 , n -> n+1).limit(5);
intStream.forEach(System.out::println);
// Output
// 100
// 101
// 102
// 103
// 104

First parameter of iterate method represents first element of the Stream. All the following elements will be generated by lambda expression n->n+1 and limit() is used to convert infinite Stream to finite Stream with 5 elements.

Lazy evaluation

Streams are lazy; intermediate operation are not executed until terminal operation is encounterd.

Each intermediate operation generates a new stream, stores the provided operation or function. When terminal operation is invoked, stream pipeline execution starts and all the intermediate operations are executed one by one.

Let’s understand with the help of example:

Stream<String> nameStream = Stream.of("mohan","john","vaibhav","amit");
Stream<String> nameStartJ = nameStream.map(String::toUpperCase)
                                    .peek( e -> System.out.println(e))
                                  .filter(s -> s.startsWith("J"));

System.out.println("Calling terminal operation: count");
long count = nameStartJ.count();
System.out.println("Count: "+ count);
// Output
// Calling terminal operation: count
// MOHAN
// JOHN
// VAIBHAV
// AMIT
// Count: 1

In preceding output, you can see that unless and until terminal operation count is called, nothing was printed on console.

In the preceding example, peek() method is used to print the element of stream. peek() method is generally used for logging and debugging purpose only.

Order of operations

Let’s see how stream processes the order of operations.
Could you guess output of the program?

Stream<String> nameStream = Stream.of("mohan","john","vaibhav","amit");
Stream<String> nameStartJ = nameStream.map(
        (s) ->
        {
            System.out.println("Map: "+s);
            return s.toUpperCase();

        })
        .filter(
        (s) ->
        {
             System.out.println("Filter: "+s);
             return s.startsWith("J");
        } 
    );

Optional<String> findAny = nameStartJ.findAny();
System.out.println("Final output: "+findAny.get());

Output will be:

Map: mohan
Filter: MOHAN
Map: john
Filter: JOHN
JOHN

Here order of operations might be surprising. A common approach will be to perform intermediate operation on all elements and then perform next operation, but instead each element moves vertically.

This kind of behavior can reduce actual number of operation.
For example:
In preceding example, Strings vaibhav and amit did not go through map and filter operation as we already got result(findAny()) with String john.

Some of the intermediate operations such as sorted are executed on the entire collection. As succeding operations might depend on the result of sorted operation.

Primitive Streams

Apart from regular Stream, Java 8 also provides primitive Stream for int, long and double.
Primitive Streams are:

  1. IntStream for int
  2. LongStream for long
  3. DoubleStream for double

All the primitive Streams are similar to regular Stream with following differences.

  • It supports few terminal aggregate functions such sum(), average(), etc.
  • It accepts specialized function interface such as IntPredicate instead of Predicate, IntConsumer instead of Consumer.

Here is an example of an IntStream.

int sum = Arrays.stream(new int[] {1,2,3})
                .sum();
System.out.println(sum);

// Output 
// 6

Convert Stream to IntStream

You may need to convert Stream to IntStream to perform terminal aggregate operations such as sum or average. You can use mapToInt(), mapToLong() or mapToDouble() method to convert Stream to primitive Streams.
Here is an example:

Stream.of("10","20","30")
      .mapToInt(Integer::parseInt)
      .average()
      .ifPresent(System.out::println);
// Output
// 20.0

Convert IntStream to Stream

You may need to convert IntStream to Stream to use it as any other datatype. You can use mapToObj() convert primitive Streams to regular Stream.
Here is an example:

String collect = IntStream.of(10,20,30)
                          .mapToObj((i)->""+i)
                          .collect(Collectors.joining("-"));
System.out.println(collect);
// Output
// 10-20-30

Employee class

Consider a Employee class which has two fields name, age, listOfCities.

Here listOfCities denotes cities in which Employee has lived so far.

package org.arpit.java2blog.stream;

import java.util.List;

public class Employee implements Comparable{

    private String name;
    private int age;
    private List listOfCities;

    public Employee(String name, int age,List listOfCities) {
        super();
        this.name = name;
        this.age = age;
        this.listOfCities=listOfCities;
    }

    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;
    }

    public List getListOfCities() {
        return listOfCities;
    }

    public void setListOfCities(List listOfCities) {
        this.listOfCities = listOfCities;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int compareTo(Employee o) {
        return this.getName().compareTo(o.getName());
    }
}

This Employee class will be used in all succeeding examples.
Let’s create employeesList on which we are going to perform intermediate and terminal operations.

package org.arpit.java2blog.stream;

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

public class StreamGetListOfEmployees {

    public static void main(String[] args) {
        List employeesList=getListOfEmployees();

        // Write stream code here
    }

    public static List getListOfEmployees() {

        List listOfEmployees = new ArrayList<>();

        Employee e1 = new Employee("Mohan", 24,Arrays.asList("Newyork","Banglore"));
        Employee e2 = new Employee("John", 27,Arrays.asList("Paris","London"));
        Employee e3 = new Employee("Vaibhav", 32,Arrays.asList("Pune","Seattle"));
        Employee e4 = new Employee("Amit", 22,Arrays.asList("Chennai","Hyderabad"));

        listOfEmployees.add(e1);
        listOfEmployees.add(e2);
        listOfEmployees.add(e3);
        listOfEmployees.add(e4);

        return listOfEmployees;
    }
}

Common intemediate operations

Map()

Map() operation is used to convert Stream<T> to Stream<R>. It produces one output result of type 'R' for each input value of type 'T'. It takes Function interface as parameter.
For example:
You have stream of list of employees and you need a list of employee names, you simply need to convert Stream to Stream.

List<String> employeeNames = employeesList.stream()
                                .map(e -> e.getName())
                               .collect(Collectors.toList());
System.out.println(employeeNames);

// Output
// [Mohan, John, Vaibhav, Amit]
StreamMap
Logical representation of Map operation

You can also use map even if it produces result of same type.
In case, you want employee name in uppercase, you can use another map() function to convert string to uppercase.

List<String> employeeNames = employeesList.stream()
                                .map(e -> e.getName())
                                .map(s -> s.toUpperCase())
                                .collect(Collectors.toList());
System.out.println(employeeNames);

// Output
// [MOHAN, JOHN, VAIBHAV, AMIT]

Filter()

Filter() operation is used to filter stream based on conditions. Filter method takes Predicate() interface which returns boolean value.
Let’s say you want to employees whose name starts with ‘A’.
You can write following functional code to achieve the same.

List<String> employeeNames = employeesList.stream()
                                .map(e -> e.getName())
                                .filter(s -> s.startsWith("A"))
                               .collect(Collectors.toList());
System.out.println(employeeNames);

// Output
// [AMIT]
StreamFilter
Logical representation of Filter operation
[![StreamFilter]

sorted()

You can use sorted() method to sort list of objects. sorted method without arguments sorts list in natural order. sorted() method also accepts comparator as parameter to support custom sorting.

💡 Did you know?

Natural order means sorting the list based on comparable interface implemented by list element type.
For example:
List will be sorted on the basis of comparable interface implemented by Integer class.

Here is the sorted() method example

List<Employee> employees = employeesList.stream()
                                            .sorted()
                                            .collect(Collectors.toList());
System.out.println(employees);

// Output
// [Employee [name=Amit, age=22], Employee [name=John, age=27], Employee [name=Mohan, age=24], Employee [name=Vaibhav, age=32]]

Here is the sorted() method example with Comparator as a parameter.

List<Employee> employees = employeesList.stream()
                              .sorted((e1,e2)->e1.getAge() - e2.getAge())
                               .collect(Collectors.toList());
System.out.println(employees);

// Output
// [Employee [name=Amit, age=22], Employee [name=Mohan, age=24], Employee [name=John, age=27], Employee [name=Vaibhav, age=32]]

You can also rewrite this with method reference as below:

List<Employee> employees = employeesList.stream()
                                                .sorted(Comparator.comparing(Employee::getAge))
                                                .collect(Collectors.toList());
System.out.println(employees);

// Output
// [Employee [name=Amit, age=22], Employee [name=Mohan, age=24], Employee [name=John, age=27], Employee [name=Vaibhav, age=32]]

limit()

You can use limit() to limit the number of elements in the stream.
For example:
limit(3) returns first 3 elements in the list.

Let’s see with the help of an example:

List<Employee> employees = employeesList.stream()
                                     .limit(3)
                                  .collect(Collectors.toList());
System.out.println(employees);

// Output
// [Employee [name=Mohan, age=24], Employee [name=John, age=27], Employee [name=Vaibhav, age=32]]

Skip()

skip(int n) method is used to discard first n elements from the stream.
For example:
skip(3) discards first 3 elements from stream.

Let’s see with help of example:

List<Employee> employees = employeesList.stream()
                                     .skip(3)
                                  .collect(Collectors.toList());
System.out.println(employees);

// Output
// [Employee [name=Amit, age=22]]

flatmap()

map() operation generates one output for each input element.

What if you want more than one output for each input?
flatmap() operation is exactly used for this purpose. It is used to map multiple-output for each input.
For example:
We want to accumulate list of cities in which all employees have lived. One employee could have lived in multiple cities so that we may have more than one city for each employee.

Let’s see with help of example:

List<String> listOfCities = employeesList.stream()
                                           .flatMap(e -> e.getListOfCities().stream())
                                           .collect(Collectors.toList());

System.out.println("listOfCities: " +listOfCities);

// Output
// listOfCities: [Newyork, Banglore, Paris, London, Pune, Seattle, Chennai, Hyderabad]

Common terminal operations

foreach

foreach() is terminal operation which is used to iterate over collection/stream of objects. It takes consumer as a parameter.

Let’s say you want to print elements of the stream.

employeesList.stream()
             .forEach(System.out::println);

// Output
// Employee [name=Mohan, age=24]
// Employee [name=John, age=27]
// Employee [name=Vaibhav, age=32]
// Employee [name=Amit, age=22]

collect

collect() is terminal operation which performs mutable reduction on the elements of Stream using Collector. Collectors is utility class which provides inbuilt Collector.
For example:
Collectors.toList() provides a Collector which converts Stream to a list object.
Following code accumultates Employee names into a Arraylist

List<String> employeeNames = employeesList.stream()
                                          .map(Employee::getName)
                                          .collect(Collectors.toList());
System.out.println(employeeNames);

// Output
// [Mohan, John, Vaibhav, Amit]

Reduce

The reduce operation combines all elements of Stream and produces single result.
Java 8 has three overloaded version of reduce method.

  1. Optional<T> reduce(BinaryOperator<T> accumulator):
    This method takes BinaryOperator accumulator function. BinaryOperator is BiFunction where both the operands are of same type. First parameter is result till current execution, and second parameter is the current element of the Stream.

    Let’s find name of Person with minimum age.

    employeesList.stream()
    .reduce( (e1,e2)-> (e1.getAge() < e2.getAge()? e1:e2))
    .ifPresent(System.out::println);
    // Output
    // Employee [name=Amit, age=22]
  2. T reduce(T identity, BinaryOperator accumulator):
    This method takes identity value and accumulator function. identity value is initial value of the reduction. If Stream is empty,then identity value is the result.
    Let’s find sum of all ages of Employees

    int sumAge = employeesList.stream()
    .mapToInt(Employee::getAge)
    .reduce(0, (age1,age2)-> (age1 + age2));
    
    System.out.println("Sum of ages of all Employees: "+sumAge);
    // Output
    // Sum of ages of all Employees: 105
  3. <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner):
    This method takes identity value and accumulator function and combiner. Combiner is mainy used in case of Parallel Streams. Combiner comibnes the result of sub-stream that run in Parallel.

count

count() is used to count number of elements in the stream.

long empCountStartJ = employeesList.stream()
                                   .map(Employee::getName)
                                   .filter(s -> s.startsWith("J"))
                                   .count();
System.out.println(empCountStartJ);

// Output
// 1

allMatch()

allMatch() returns true when all the elements in the stream meet provided condition.

This is a short-circuiting terminal operation because operation stops as soon as it encounters any unmatched element.

boolean allMatch = employeesList.stream()
                                .allMatch(e ->e.getAge()>18);

System.out.println("Are all the employess adult: " +allMatch);

// Output
// Are all the employess adult: true

nonMatch()

nonMatch() returns true when all the elements in the stream do not meet provided condition.

This is a short-circuiting terminal operation because operation stops as soon as it encounters any matched element.

boolean noneMatch = employeesList.stream()
                                 .noneMatch(e ->e.getAge()>60);

System.out.println("Are all the employess below 60: " +noneMatch);

// Output
// Are all the employess below 60: true

anyMatch()

anyMatch() returns true when any element in the stream meets provided condition.

This is a short-circuiting terminal operation because operation stops as soon as it encounters any matched element.

boolean anyMatch = employeesList.stream()
                                 .anyMatch(e ->e.getAge()>30);

System.out.println("is any employee's age greater than 30: " +anyMatch);

// Output
// is any employee's age greater than 30: true

min()

min(Comparator) returns minimum element in the stream based on the provided comparator. It returns an object which contains actual value.

Optional<Employee> minEmpOpt = employeesList.stream()
                                            .min(Comparator.comparing(Employee::getAge));

Employee minAgeEmp = minEmpOpt.get();
System.out.println("Employee with minimum age is: " +minAgeEmp);

// Output
// Employee with minimum age is: Employee [name=Amit, age=22]

max()

max(Comparator) returns maximum element in the stream based on the provided comparator. It returns an object which contains actual value.

Optional<Employee> maxEmpOpt = employeesList.stream()
                                            .max(Comparator.comparing(Employee::getAge));

Employee maxAgeEmp = maxEmpOpt.get();
System.out.println("Employee with maxium age is: " +maxAgeEmp);

// Output
// Employee with maxium age is: Employee [name=Vaibhav, age=32]

Parallel Streams

You can create Parallel Stream using .parallel() method on Stream object in java.
Here is an example:

int[] array= {1,2,3,4,5};

System.out.println("=================================");
System.out.println("Using Parallel Stream");
System.out.println("=================================");
IntStream intParallelStream=Arrays.stream(array).parallel();
intParallelStream.forEach((s)->
{
    System.out.println(s+" "+Thread.currentThread().getName());
}
);

Here is a comprehensive article on Java 8 Parallel Stream.

Exercises

Let’s practice some exercises on Stream.

Exercise 1

Given a list of employees, you need to find all the employees whose age is greater than 30 and print the employee names.(Java 8 APIs only)
Answer:

Exercise 2

Given the list of employees, find the count of employees with age greater than 25?
Answer:

Exercise 3

Given the list of employees, find the employee whose name is John.

Exercise 4

Given a list of employees, You need to find highest age of employee?
Answer:

Excercise 5

Given a list of employees, you need sort employee list by age? Use java 8 APIs only
Answer:

Excercise 6

Given the list of Employees, you need to join the all employee names with ","?
Answer:

Excercise 7

Given the list of employees, you need to group them by name

]]>
https://java2blog.com/java-8-stream/feed/ 2
Java Stream sorted example https://java2blog.com/java-stream-sorted/?utm_source=rss&utm_medium=rss&utm_campaign=java-stream-sorted https://java2blog.com/java-stream-sorted/#respond Sat, 25 Apr 2020 19:14:51 +0000 https://java2blog.com/?p=9495 In this post, we will see how to sort a list with Stream.sorted() method.

Java 8 has introduced Stream.sort() method to sort list of elements conveniently. It helps us to write short and concise functional style code rather than boilerplate code.
java.util.Stream has two overloaded versions of sorted() method.

  1. sorted(): Returns a stream having elements sorted by natural order
  2. sorted(Comparator comparator): Returns a stream having elements sorted by provided comparator

💡 Did you know?

If you sort list of Integers using Stream.sorted() method then Comparable interface, implemented by Integer class, will define natural ordering of list of Integers .

Let’s understand how can we use Stream.sorted() to sort list of elements.

Sort List of Integers

We can simply use sorted() method to sort list of integers.

List result = listOfIntegers.stream()
                                         .sorted()
                                         .collect(Collectors.toList());

Here, List of Integers is sorted by Comparable interface implemented by Integer class.

public final class Integer extends Number implements Comparable {
....
/**
     * Compares two {@code Integer} objects numerically.
     *
     * @param   anotherInteger   the {@code Integer} to be compared.
     * @return  the value {@code 0} if this {@code Integer} is
     *          equal to the argument {@code Integer}; a value less than
     *          {@code 0} if this {@code Integer} is numerically less
     *          than the argument {@code Integer}; and a value greater
     *          than {@code 0} if this {@code Integer} is numerically
     *           greater than the argument {@code Integer} (signed
     *           comparison).
     * @since   1.2
     */
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

    /**
     * Compares two {@code int} values numerically.
     * The value returned is identical to what would be returned by:
     * 
     * Integer.valueOf(x).compareTo(Integer.valueOf(y))
     *
     *
     * @param  x the first {@code int} to compare
     * @param  y the second {@code int} to compare
     * @return the value {@code 0} if {@code x == y};
     *         a value less than {@code 0} if {@code x < y}; and
     *         a value greater than {@code 0} if {@code x > y}
     * @since 1.7
     */
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

As you can see, Integers are compared on this basis of (x < y) ? -1 : ((x == y) ? 0 : 1) logic.

You can pass Comparator.reverseOrder() to sorted method to reverse sort list of Integers.

List reverseOrder = listOfIntegers.stream()
                                               .sorted(Comparator.reverseOrder())
                                               .collect(Collectors.toList());

Comparator.reverseOrder() is static method and provides a comparator that imposes reverse of natural ordering.

Let’s see complete example to sort list of integers.

package org.arpit.java2blog;

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

public class SortListOfIntegers {

    public static void main(String[] args) {
        List listOfIntegers = Arrays.asList(new Integer[] {40,34,21,37,20});

        List result = listOfIntegers.stream()
                                                .sorted()
                                                .collect(Collectors.toList());
        System.out.println(result);

        List reverseOrder = listOfIntegers.stream()
                                                     .sorted(Comparator.reverseOrder())
                                                     .collect(Collectors.toList());
        System.out.println(reverseOrder);
    }

}

Output:

[20, 21, 34, 37, 40] [40, 37, 34, 21, 20]

Sort List of Strings

We can simply use sorted() method to sort list of Strings.

List result = listOfStrings.stream()
                                         .sorted()
                                         .collect(Collectors.toList());

Here, List of Strings is sorted by Comparable interface implemented by String class.

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
....
/**
     * Compares two strings lexicographically.
     *
     * @param   anotherString   the {@code String} to be compared.
     * @return  the value {@code 0} if the argument string is equal to
     *          this string; a value less than {@code 0} if this string
     *          is lexicographically less than the string argument; and a
     *          value greater than {@code 0} if this string is
     *          lexicographically greater than the string argument.
     */
    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

As you can see, Integers are compared on this basis of (x < y) ? -1 : ((x == y) ? 0 : 1) logic.

You can pass Comparator.reverseOrder() to sorted method to reverse sort list of Integers.

List reverseOrder = listOfStrings.stream()
                                               .sorted(Comparator.reverseOrder())
                                               .collect(Collectors.toList());

Comparator.reverseOrder() is static method and provides a comparator that imposes reverse of natural ordering.

Let’s see complete example to sort list of integers.

package org.arpit.java2blog;

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

public class SortListOfStrings {

    public static void main(String[] args) {
        List listOfLanguages = Arrays.asList(new String[] { "Python", "C++", "Java", "PHP" });

        List sortedListOfLanguages = listOfLanguages.stream()
                                                              .sorted()
                                                              .collect(Collectors.toList());
        System.out.println(sortedListOfLanguages);

        List sortedListOfLanguagesRev = listOfLanguages.stream()
                                                                 .sorted(Comparator.reverseOrder())
                                                                 .collect(Collectors.toList());
        System.out.println(sortedListOfLanguagesRev);  
    }

}

Output:

[C++, Java, PHP, Python] [Python, PHP, Java, C++]

Sort List of custom objects

Sort list of Students by natural order

Create a class named Student.java

package org.arpit.java2blog;

public class Student{

    String name;
    int age;

    public Student(String name, int age) {
        super();
        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 "Student [name=" + name + ", age=" + age + "]";
    }
}

Let’s use Stream’s sorted() to sort the list of Students now.

package org.arpit.java2blog;

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

public class SortListOfStudents {

    public static void main(String[] args) {
        List studentsList = getListOfStudents();

        List sortedStudentsList= studentsList.stream()
                                                          .sorted()
                                                          .collect(Collectors.toList());
        System.out.println(sortedStudentsList);
    }

    public static List getListOfStudents()
    {
        List studentList=new ArrayList<>();

        Student s1=new Student("Peter",21);
        Student s2=new Student("Harshal",18);
        Student s3=new Student("Andy",17);
        Student s4=new Student("Mary",20);
        Student s5=new Student("Peter",19);

        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);
        studentList.add(s5);

        return studentList;
    }
}

Let’s run above program.

Exception in thread “main” java.lang.ClassCastException: org.arpit.java2blog.Student cannot be cast to java.lang.Comparable
at java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:353)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
at org.arpit.java2blog.SortListOfStudents.main(SortListOfStudents.java:14)

Did you know why we got exception here?
We got the ClassCastException exception because we did not implement Comparable interface in Student class.

Let’s implement Comparable interface in Student class.

package org.arpit.java2blog;

public class Student implements Comparable{

    String name;
    int age;

    public Student(String name, int age) {
        super();
        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 "Student [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int compareTo(Student o) {
        return this.getName().compareTo(o.getName());
    }

}

Run SortListOfStudents again, and you will get below output.

[Student [name=Andy, age=17], Student [name=Harshal, age=18], Student [name=Mary, age=20], Student [name=Peter, age=21], Student [name=Peter, age=19]]

As you can see, list of Students is sorted by student name.

Sort list of Students by reverse natural order

Sort list of Students by name in descending order.

package org.arpit.java2blog;

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

public class SortListOfStudents {

    public static void main(String[] args) {
        List studentsList = getListOfStudents();

        List sortedListOfStudent2 = listOfStudents.stream()
                                                           .sorted(Comparator.reverseOrder())
                                                           .collect(Collectors.toList());
        System.out.println(sortedStudentsList);
    }

    public static List getListOfStudents()
    {
        List studentList=new ArrayList<>();

        Student s1=new Student("Peter",21);
        Student s2=new Student("Harshal",18);
        Student s3=new Student("Andy",17);
        Student s4=new Student("Mary",20);
        Student s5=new Student("Peter",19);

        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);
        studentList.add(s5);

        return studentList;
    }
}

Output:

[Student [name=Peter, age=21], Student [name=Peter, age=19], Student [name=Mary, age=20], Student [name=Harshal, age=18], Student [name=Andy, age=17]]

Sort list of Students by age using comparator

package org.arpit.java2blog;

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

public class SortListOfStudents {

    public static void main(String[] args) {
        List studentsList = getListOfStudents();

        List studentsListByAge = studentsList.stream()
                                                         .sorted((s1,s2) -> s1.getAge()-s2.getAge())
                                                         .collect(Collectors.toList());
        System.out.println(studentsListByAge);
    }

    public static List getListOfStudents()
    {
        List studentList=new ArrayList<>();

        Student s1=new Student("Peter",21);
        Student s2=new Student("Harshal",18);
        Student s3=new Student("Andy",17);
        Student s4=new Student("Mary",20);
        Student s5=new Student("Peter",19);

        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);
        studentList.add(s5);

        return studentList;
    }
}

Output:

[Student [name=Andy, age=17], Student [name=Harshal, age=18], Student [name=Peter, age=19], Student [name=Mary, age=20], Student [name=Peter, age=21]]

You can also use Comparator.comparing(Function<? super T, ? extends U> keyExtractor) to sort it on the basis of age.
Comparator.comparing() accepts a function that maps a sort key from a type, and returns a Comparator that compares by that sort key.
Let’s say you want to sort list of Students on the basis of age. You can extracts sort key age from Student object and Comparator.comparing() will return a comparator which will sort by that sort key.

Function fun = (s) -> s.getAge();
    List studentsListByAge = studentsList.stream()
                                               .sorted(Comparator.comparing(fun))
                                               .collect(Collectors.toList());

Here Comparator.comparing() returns a new Comparator to sort based on age.

We can also use method reference here as we are just calling s.getAge() in the functional interface.

Function fun = Student::getAge
    List studentsListByAge = studentsList.stream()
                                            .sorted(Comparator.comparing(fun))
                                                .collect(Collectors.toList());

Let’s say you want to sort list of Students on the basis of age in descending order. You can pass another comparator to Comparator.comparing() to make custom sorting based on sort key.

List sortedListOfStudent5 = listOfStudents.stream()
                                                           .sorted(Comparator.comparing(Student::getAge,(age1,age2) -> age2 - age1))
                                                           .collect(Collectors.toList());

Here,
Comparator.comparing() has two arguments.
Student::getAge to define sort key.
(age1,age2) -> age2 - age1) to define custom sorting on the basis of sort key.

Here is the complete example.

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class SortListOfStudents {

    public static void main(String[] args) {
        List sList = getListOfStudents();

        Function fun = (s) -> s.getAge();
        List sListByAge = sList.stream()
                                         .sorted(Comparator.comparing(fun))
                                         .collect(Collectors.toList());
        System.out.println("Sorted list by age ascending: "+sListByAge);

        List sListByAgeRev = sList.stream()
                                           .sorted(Comparator.comparing(Student::getAge
                                                                         ,(age1,age2) -> age2 - age1))
                                           .collect(Collectors.toList());

        System.out.println("Sorted list by age descending: "+sListByAgeRev);
    }

    public static List getListOfStudents()
    {
        List studentList=new ArrayList<>();

        Student s1=new Student("Peter",21);
        Student s2=new Student("Harshal",18);
        Student s3=new Student("Andy",17);
        Student s4=new Student("Mary",20);
        Student s5=new Student("Peter",19);

        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);
        studentList.add(s5);

        return studentList;
    }
}

Output:

Sorted list by age ascending: [Student [name=Andy, age=17], Student [name=Harshal, age=18], Student [name=Peter, age=19], Student [name=Mary, age=20], Student [name=Peter, age=21]] Sorted list by age descending: [Student [name=Peter, age=21], Student [name=Mary, age=20], Student [name=Peter, age=19], Student [name=Harshal, age=18], Student [name=Andy, age=17]]

Sort list of Students by name and age

Let’s say you want to list of students by name and if name is same, then you need to sort by age.

You can use Comparator.thenComparing() with Comparator.comparing() to achieve the same.

Let’s see with the help of example.

package org.arpit.java2blog;

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

public class SortListOfStudents {

    public static void main(String[] args) {
        List sList = getListOfStudents();

        List sListByNameAge = sList.stream()
                                           .sorted(Comparator.comparing(Student::getName)
                                                             .thenComparing(Student::getAge))
                                           .collect(Collectors.toList());

        System.out.println(sListByNameAge);
    }

    public static List getListOfStudents()
    {
        List studentList=new ArrayList<>();

        Student s1=new Student("Peter",21);
        Student s2=new Student("Harshal",18);
        Student s3=new Student("Andy",17);
        Student s4=new Student("Mary",20);
        Student s5=new Student("Peter",19);

        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);
        studentList.add(s5);

        return studentList;
    }
}

Output:

[Student [name=Andy, age=17], Student [name=Harshal, age=18], Student [name=Mary, age=20], Student [name=Peter, age=19], Student [name=Peter, age=21]]

As you can see, there are two students named Peter in the list then, sorted by age.

Excercise

Given a list of Employee objects, you need to sort them of Employee’s name in descending order and return a sorted list of Employee(List)
Here is the definition of Employee class.

package org.arpit.java2blog;

public class Employee {

    String name;

    public Employee(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + "]";
    }
}

That’s all about Java Stream sorted example.

]]>
https://java2blog.com/java-stream-sorted/feed/ 0
Java Parallel Stream https://java2blog.com/java-8-parallel-stream/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-parallel-stream https://java2blog.com/java-8-parallel-stream/#respond Tue, 07 Nov 2017 05:13:19 +0000 https://www.java2blog.com/?p=4418 In this post, we will see about Parallel Stream in java.

Java Parallel Stream introduction

Java 8 introduces the concept of parallel stream to do parallel processing. As we have more number of cpu cores nowadays due to cheap hardware costs, parallel processing can be used to perform operation faster.

Let’s understand with help of simple example

package org.arpit.java2blog.java8;

import java.util.Arrays;
import java.util.stream.IntStream;

public class Java8ParallelStreamMain {

    public static void main(String[] args) {

        System.out.println("=================================");
        System.out.println("Using Sequential Stream");
        System.out.println("=================================");
        int[] array= {1,2,3,4,5,6,7,8,9,10};
        IntStream intArrStream=Arrays.stream(array);
        intArrStream.forEach(s->
        {
            System.out.println(s+" "+Thread.currentThread().getName());
        }
                );

        System.out.println("=================================");
        System.out.println("Using Parallel Stream");
        System.out.println("=================================");
        IntStream intParallelStream=Arrays.stream(array).parallel();
        intParallelStream.forEach(s->
        {
            System.out.println(s+" "+Thread.currentThread().getName());
        }
                );
    }
}

When you run above program, you will get below output

=================================
Using Sequential Stream
=================================
1 main
2 main
3 main
4 main
5 main
6 main
7 main
8 main
9 main
10 main
=================================
Using Parallel Stream
=================================
7 main
6 ForkJoinPool.commonPool-worker-3
3 ForkJoinPool.commonPool-worker-1
9 ForkJoinPool.commonPool-worker-2
2 ForkJoinPool.commonPool-worker-3
5 ForkJoinPool.commonPool-worker-1
10 ForkJoinPool.commonPool-worker-2
1 ForkJoinPool.commonPool-worker-3
8 ForkJoinPool.commonPool-worker-2
4 ForkJoinPool.commonPool-worker-1

If you notice the output,main thread is doing all the work in case of sequential stream. It waits for current iteration to complete and then work on next iteration.
In case of Parallel stream,4 threads are spawned simultaneously and it internally using Fork and Join pool to create and manage threads.Parallel streams create ForkJoinPool instance via static ForkJoinPool.commonPool() method.

Parallel Stream takes the benefits of all available CPU cores and processes the tasks in parallel. If number of tasks exceeds the number of cores, then remaining tasks wait for currently running task to complete.

Parallel Streams are cool, so should you use it always?

A big No!!
It is easy to convert sequential Stream to parallel Stream just by adding .parallel, does not mean you should always use it.
There are lots of factors you need to consider while using parallel streams otherwise you will suffer from negative impacts of parallel Streams.

Parallel Stream has much higher overhead than sequential Stream and it takes good amount of time to coordinate between threads.
You need to consider parallel Stream if and only if:

  • You have large dataset to process.
  • As you know that Java uses ForkJoinPool to achieve parallelism, ForkJoinPool forks sources stream and submit for execution, so your source stream should be splittable.
    For example:
    ArrayList is very easy to split, as we can find a middle element by its index and split it but LinkedList is very hard to split and does not perform very well in most of the cases.
  • You are actually suffering from performance issues.
  • You need to make sure that all the shared resources between threads need to be synchronized properly otherwise it might produce unexpected results.

Simplest formula for measuring parallelism is "NQ" model as provided by Brian Goetz in his presentation.

NQ Model:

N x Q > 10000

where,
N = number of items in dataset
Q = amount of work per item

It means if you have a large number of datasets and less work per item(For example: Sum), parallelism might help you run program faster and vice versa is also true. So if you have less number of datasets and more work per item(doing some computational work), then also parallelism might help you in achieving results faster.

Let’s see with the help of another example.

In this example, we are going to see how CPU behaves when you perform long computations in case of parallel Stream and sequential stream.We are doing some arbit calculations to make CPU busy.

package org.arpit.java2blog.java8;
import java.util.ArrayList;
import java.util.List;

public class PerformanceComparisonMain {

    public static void main(String[] args) {

        long currentTime=System.currentTimeMillis();
        List<Integer> data=new ArrayList<Integer>();
        for (int i = 0; i < 100000; i++) {
            data.add(i);
        }

        long sum=data.stream()
                .map(i ->(int)Math.sqrt(i))
                .map(number->performComputation(number))
                .reduce(0,Integer::sum);

        System.out.println(sum);
        long endTime=System.currentTimeMillis();
        System.out.println("Time taken to complete:"+(endTime-currentTime)/(1000*60)+" minutes");

    }

    public static int performComputation(int number)
    {
        int sum=0;
        for (int i = 1; i < 1000000; i++) {
            int div=(number/i);
            sum+=div;

        }
        return sum;
    }
}

When you run above program, you will get below output.

117612733
Time taken to complete:6 minutes

But we are not interested in output here, but how CPU behaved when above operation performed.

As you can see CPU is not fully utilized in case of Sequential Stream.

Let’s change at 16 line no. and make the stream parallel and run the program again.

long sum=data.stream()
                .parallel()
                .map(i ->(int)Math.sqrt(i))
                .map(number->performComputation(number))
                .reduce(0,Integer::sum);

You will get below output when you run Stream in parallel.

117612733
Time taken to complete:3 minutes

Let’s check CPU history when we ran program using parallel stream.

Parallel Stream

As you can see parallel stream used all 4 CPU cores to perform computation.

Custom Thread pool in Parallel Stream

The parallel stream by default uses ForkJoinPool.commonPool which has one less thread than number of processor. This means parallel stream uses all available processors because it uses the main thread as well.

In case, you are using multiple parallel streams, then they will share same ForkJoinPool.commonPool .This means you may not be able to use all the processors assigned to each parallel stream.

To solve this issue, you can create own thread pool while processing the stream.

ForkJoinPool fjp = new ForkJoinPool(parallelism);

This will create ForkJoinPool with target parallelism level. If you don’t pass parallelism, it will equal to the number of processors by default.

Now you can submit parallel stream to this custom ForkJoinPool.

ForkJoinPool fjp1 = new ForkJoinPool(5);
Callable callable1 = () -> data.parallelStream()
                   .map(i -> (int) Math.sqrt(i))
                   .map(number -> performComputation(number))
                   .peek( (i) -> {
                      System.out.println("Processing with "+Thread.currentThread()+" "+ i);

                    })
                    .reduce(0, Integer::sum);

        try {
            sumFJ1 = fjp1.submit(callable1).get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

Let’s understand with the help of example.

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;

public class PerformanceComparisonMain {

    public static void main(String[] args) {

        List data = new ArrayList();
        for (int i = 0; i < 10; i++) {
            data.add(i);
        }

        System.out.println("================");
        System.out.println("Parallel stream 1");
        System.out.println("================");
        long sum1 =data.parallelStream()
        .map(i -> (int) Math.sqrt(i))
        .map(number -> performComputation(number))
        .peek( (i) -> {
           System.out.println("Processing with "+Thread.currentThread()+" "+ i);

           })
        .reduce(0, Integer::sum);

        System.out.println("Sum: "+sum1);

        System.out.println("================");
        System.out.println("Parallel stream 2");
        System.out.println("================");

        long sum2 = data.parallelStream()
                .map(i -> ((int) Math.sqrt(i)*10))
                .map(number -> performComputation(number))
                .peek( (i) -> {
                   System.out.println("Processing with "+Thread.currentThread()+" "+ i);

                   })
                .reduce(0, Integer::sum);

        System.out.println("Sum: "+sum2);

        System.out.println("================");
        System.out.println("Parallel stream with custom thread pool 1");
        System.out.println("================");

        ForkJoinPool fjp1 = new ForkJoinPool(5);
        long sumFJ1 = 0;

        Callable callable1 = () -> data.parallelStream()
                   .map(i -> (int) Math.sqrt(i))
                   .map(number -> performComputation(number))
                   .peek( (i) -> {
                      System.out.println("Processing with "+Thread.currentThread()+" "+ i);

                    })
                    .reduce(0, Integer::sum);

        try {
            sumFJ1 = fjp1.submit(callable1).get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("Sum: "+sumFJ1);

        System.out.println("================");
        System.out.println("Parallel stream with custom thread pool 2");
        System.out.println("================");

        Callable callable2 = () -> data.parallelStream()
                .map(i -> (int) Math.sqrt(i)*10)
                .map(number -> performComputation(number))
                .peek( (i) -> {
                   System.out.println("Processing with "+Thread.currentThread()+" "+ i);

                   })
                .reduce(0, Integer::sum);

        long sumFJ2 = 0;

        ForkJoinPool fjp2 = new ForkJoinPool(4);

        try {
            sumFJ2 = fjp2.submit(callable2).get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("Sum: "+sumFJ2);
    }

    public static int performComputation(int number) {
        int sum = 0;
        for (int i = 1; i < 100000; i++) {
            int div = (number / i);
            sum += div;

        }
        return sum;
    }
}

When you run the program, you will get below output:

================
Parallel stream 1
================
Processing with Thread[ForkJoinPool.commonPool-worker-2,5,main] 3
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 1
Processing with Thread[ForkJoinPool.commonPool-worker-2,5,main] 5
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 1
Processing with Thread[ForkJoinPool.commonPool-worker-2,5,main] 3
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 3
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 0
Processing with Thread[ForkJoinPool.commonPool-worker-2,5,main] 1
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 3
Processing with Thread[main,5,main] 3
Sum: 23
================
Parallel stream 2
================
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 66
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 111
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 66
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 27
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 27
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 66
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 0
Processing with Thread[ForkJoinPool.commonPool-worker-1,5,main] 27
Processing with Thread[ForkJoinPool.commonPool-worker-3,5,main] 66
Processing with Thread[main,5,main] 66
Sum: 522
================
Parallel stream with custom thread pool 1
================
Processing with Thread[ForkJoinPool-1-worker-1,5,main] 3
Processing with Thread[ForkJoinPool-1-worker-3,5,main] 3
Processing with Thread[ForkJoinPool-1-worker-4,5,main] 1
Processing with Thread[ForkJoinPool-1-worker-3,5,main] 5
Processing with Thread[ForkJoinPool-1-worker-4,5,main] 0
Processing with Thread[ForkJoinPool-1-worker-1,5,main] 3
Processing with Thread[ForkJoinPool-1-worker-3,5,main] 3
Processing with Thread[ForkJoinPool-1-worker-2,5,main] 1
Processing with Thread[ForkJoinPool-1-worker-3,5,main] 3
Processing with Thread[ForkJoinPool-1-worker-2,5,main] 1
Sum: 23
================
Parallel stream with custom thread pool 2
================
Processing with Thread[ForkJoinPool-2-worker-1,5,main] 66
Processing with Thread[ForkJoinPool-2-worker-3,5,main] 66
Processing with Thread[ForkJoinPool-2-worker-1,5,main] 66
Processing with Thread[ForkJoinPool-2-worker-3,5,main] 111
Processing with Thread[ForkJoinPool-2-worker-0,5,main] 66
Processing with Thread[ForkJoinPool-2-worker-1,5,main] 27
Processing with Thread[ForkJoinPool-2-worker-3,5,main] 0
Processing with Thread[ForkJoinPool-2-worker-2,5,main] 27
Processing with Thread[ForkJoinPool-2-worker-0,5,main] 66
Processing with Thread[ForkJoinPool-2-worker-1,5,main] 27
Sum: 522

As you can see, first two parallel streams are using ForkJoinPool.commonPool and next 2 are using custom thread pools i.e. ForkJoinPool-1 and ForkJoinPool-2

Things you should keep in mind while using Parallel Stream

Stateful lambda expressions

You should avoid using stateful lambda expressions in stream operations.A Stateful lambda expressions is one whose output depends on any state that might change during execution of stream operations.

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ListOfIntegersStatefulLambda {

    public static void main(String[] args) {

        List listOfIntegers = Arrays.asList(new Integer[] {40,34,21,37,20});
        List syncList = Collections.synchronizedList(new ArrayList<>());
        listOfIntegers.parallelStream()

                // You shou! It uses a stateful lambda expression.
                .map(e -> {
                    syncList.add(e);
                    return e;
                })
        .forEachOrdered(e -> System.out.print(e + " "));

        System.out.println("");

        syncList.stream().forEachOrdered(e -> System.out.print(e + " "));
        System.out.println("");
    }
}

Output:

40 34 21 37 20
40 34 37 20 21

forEachOrdered processes the elements in order imposed bt stream. .map(e -> {syncList.add(e); return e;}) is stateful lambda and order in which .map(e -> {syncList.add(e); return e;}) adds element to
syncList can vary, so you should not use stateful lambda operations while using parallel stream.

Interference

Lambda expression in stream operation should not modify source of stream.
Following code tries to add element to list of integer and throw concurrentModification exception.

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.List;

public class ListOfIntegersStatefulLambda {

    public static void main(String[] args) {

        List listOfIntegers = new ArrayList<>();
        Integer[] intArray =new Integer[] {40,34,21,37,20};
        for(Integer in:intArray)
        {
            listOfIntegers.add(in);
        }
        listOfIntegers.parallelStream()

        .peek( i -> listOfIntegers.add(7))      
        .forEach(e -> System.out.print(e + " "));

        System.out.println("");

    }
}
Output:

34 21 40 20 37 Exception in thread “main” java.util.ConcurrentModificationException: java.util.ConcurrentModificationException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
at org.arpit.java2blog.ListOfIntegersStatefulLambda.main(ListOfIntegersStatefulLambda.java:19)
Caused by: java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Please note that all the intermediate operations are lazy, execution of streams begins when foreach is invoked. As argument of peek tries to modifies stream source during execution of stream, which causes Java to throw ConcurrentModificationException

Conclusion

You have learnt about parallel streams when to use parallel streams with examples. You should be careful while using parallel streams. Parallel streams are very powerful if used in the correct context.

That’s all about parallel stream in java.

]]> https://java2blog.com/java-8-parallel-stream/feed/ 0 Java 8 Stream of example https://java2blog.com/java-8-stream-of/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream-of https://java2blog.com/java-8-stream-of/#comments Tue, 17 Oct 2017 10:07:10 +0000 https://www.java2blog.com/?p=4196 In this post, we will see about Java 8 Stream‘s of method example.
stream‘s of method is static method and used to create stream of given type.
For example:

Stream<String> stringStream=Stream.of("India","China","Bhutan","Nepal");
Stream<Integer> integerStream=Stream.of(1,2,3,4,5);

There are two overloaded version of Stream’s of method.
1) static <T> Stream<T> of(T… values)
Returns a sequential ordered stream whose elements are the specified values.
2) static <T> Stream<T> of(T t)
Returns a sequential Stream containing a single element.

Java Stream of example

Create a class named Java8StreamOfExample as below:

package org.arpit.java2blog;

import java.util.stream.Stream;

public class Java8StreamOfExample {
    public static void main(String[] args)
    {
        Stream<String> stringStream=Stream.of("India","China","Bhutan","Nepal");

        stringStream.forEach((e) -> System.out.println(e));
    }
}

When you run above program, you will get below output:

India
China
Bhutan
Nepal

Another example

package org.arpit.java2blog.flatMap;

import java.util.stream.Stream;

public class Java8StreamOfExample {
    public static void main(String[] args)
    {
        Stream<Double> doubleStream=Stream.of(2.0,3.4,4.3);

        doubleStream.
        map(e -> 2*e)
        .forEach((e) -> System.out.println(e));
    }
}

When you run above program, you will get below output:

4.0
6.8
8.6
]]>
https://java2blog.com/java-8-stream-of/feed/ 1
Java 8 Stream flatMap https://java2blog.com/java-8-stream-flatmap/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream-flatmap https://java2blog.com/java-8-stream-flatmap/#respond Sun, 15 Oct 2017 17:56:22 +0000 https://www.java2blog.com/?p=4170 In this post, we will see about Java 8 Stream flatMap function.Before understanding flatMap, you should go through stream’s map function

Stream‘s flatMap method takes single element from input stream and produces any number of output values and flattens result to output stream.When you apply flatMap function on each of element of the stream, it results in stream of values rather than single value as in case of Stream’s map function.

Java 8 Stream flatMap function

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

As per java docs, Stream’s flatMap returns a stream 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.

Confused? Don’t worry, example will make it very clear.
Function is a functional interface available in Java 8 java.util.function.Function accepts one input and produce a result.
Let’s understand with the help of a simple example.

Java 8 Stream flatMap example

Let’s say you have an employee class. Each employee has list of cities where they have lived in past.You need to find list of all cities where Employees have lived in.

For example:
Let’s say Ramesh has lived in Delhi, Mumbai and Rekha has lived in Pune, Delhi, then the output will be Delhi, Mumbai, Pune.

So we will use flatMap function to map each employee to list of cites to flatten it and then collection it in form of set.

  1. Create a class named "Employee.java"
    package org.arpit.java2blog.flatMap;

import java.util.List;

public class Employee {

String name;
int age;
List<String> listOfCities;

public Employee(String name, int age,List<String> listOfCities) {
    super();
    this.name = name;
    this.age = age;
    this.listOfCities=listOfCities;
}

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;
}

public List<String> getListOfCities() {
    return listOfCities;
}

public void setListOfCities(List<String> listOfCities) {
    this.listOfCities = listOfCities;
}

}

  1. Create main class named "Java8StreamMapMain.java"
    package org.arpit.java2blog.flatMap;

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

public class Java8StreamMapMain {

public static void main(String args[])
{
    List<Employee> listOfEmployees = createListOfEmployees();

    Set<String> listOfCities=listOfEmployees.stream()
                                    .flatMap(e -> e.getListOfCities().stream()) 
                                    .collect(Collectors.toSet());
    listOfCities.forEach(System.out::println);
}       

public static List<Employee> createListOfEmployees()
{
    List<Employee> listOfEmployees=new ArrayList<>();
    Employee emp1= new Employee("Ankit",20,Arrays.asList("Delhi","Mumbai"));
    Employee emp2= new Employee("Shilpa",24,Arrays.asList("Kolkata","Pune"));
    Employee emp3= new Employee("Megha",20,Arrays.asList("Delhi","Patna"));
    Employee emp4= new Employee("Mohan",20,Arrays.asList("Banglore","Pune"));
    listOfEmployees.add(emp1);
    listOfEmployees.add(emp2);
    listOfEmployees.add(emp3);
    listOfEmployees.add(emp4);
    return listOfEmployees;
}

}

When you run above program, you will get below output:

Delhi
Patna
Banglore
Kolkata
Pune
Mumbai

Another example

Let’s say you have 2D array of integers and you need to create a flattened list of integers after doubling each element.

package org.arpit.java2blog.flatMap;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Java8StreamFlatMapNumber {

    public static void main(String[] args)
    {
        int[][] numbers={
                {1,2},
                {3,4},
                {5,6}
        };
         //Stream<int[]>
        Stream<int[]> temp = Arrays.stream(numbers);
        List<Integer> listOfIntegers= temp
                .flatMap( x -> Arrays.stream(x).boxed())
                .map(e -> 2*e)
                .collect(Collectors.toList());

        System.out.println(listOfIntegers);

    }
}

When you run above program, you will get below output:

[2, 4, 6, 8, 10, 12]

If you notice, we have used flatMap to flatten the 2D array and then used map function to double of input number in above example.

That’s all about Java 8 Java 8 stream flatMap example.

]]>
https://java2blog.com/java-8-stream-flatmap/feed/ 0
Java 8 Stream Map https://java2blog.com/java-8-stream-map/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream-map https://java2blog.com/java-8-stream-map/#respond Sat, 14 Oct 2017 19:14:37 +0000 https://www.java2blog.com/?p=4162 In this post, we will see about Java 8 Stream map function.

stream‘s map method takes single element from input stream and produces single element to output stream. Type of Single input Stream and Output stream can differ.

Java 8 Stream Map function

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

Map function returns a stream consisting of the results of applying the given function to the elements of this stream.
Function is a functional interface available in Java 8 java.util.function.Function accepts one input and produce a result.

Few important points about Map

  • Map is intermediate operation and returns stream as a result.
  • Map operation takes Function as parameter and this function is called on each element of the stream.
  • Map() method is used to convert Stream to Stream
  • You can also use map method to convert it from Stream to Stream.
    For example: Calling toUppercase() method in Map method which will again return Stream.
  • Let’s understand with the help of a simple example.

    Java 8 Stream Map example

    Let’s say you have a list of employees, now you want to convert it to list of employee names, so you will map each employee object to employee name.

    Java 8 Stream map

    You will give input as Stream of employee objects and get an output as Stream of String.

    1. Create a class named Employee.java

    package org.arpit.java2blog.map;
    
    public class Employee {
    
        String name;
        int age;
    
        public Employee(String name, int age) {
            super();
            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;
        }
    }

    2. Create main class named Java8StreamMapMain.java

    package org.arpit.java2blog.map;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class Java8StreamMapMain {
    
        public static void main(String args[])
        {
            List<Employee> listOfEmployees = createListOfEmployees();
    
            // Using map function to convert Stream<Employee> to Stream<Stream>
            List<String> listOfEmployeeNames=listOfEmployees.stream()
                                            .map(e -> e.getName()) 
                                            .collect(Collectors.toList());
            listOfEmployeeNames.forEach(System.out::println);
        }       
    
        public static List<Employee> createListOfEmployees()
        {
            List<Employee> listOfEmployees=new ArrayList<>();
            Employee emp1= new Employee("John",20);
            Employee emp2= new Employee("Martin",20);
            Employee emp3= new Employee("Mary",20);
            Employee emp4= new Employee("Steve",20);
            listOfEmployees.add(emp1);
            listOfEmployees.add(emp2);
            listOfEmployees.add(emp3);
            listOfEmployees.add(emp4);
            return listOfEmployees;
        }
    }

    When you run above program, you will get below output:

    John
    Martin
    Mary
    Steve

    Here is logical representation of above program.
    MapEmployee
    You can use method reference to at line no.17 as below

    List<String> listOfEmployeeNames=listOfEmployees.stream()
                                            .map(Employee::getName) 
                                            .collect(Collectors.toList());

    Another example

    Let’s say you have list of integers and you want to find sum of double of even numbers.

    package org.arpit.java2blog.map;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class Java8StreamMapNumber {
    
        public static void main(String[] args)
        {
            List<Integer> listOfNumbers=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    
            int sum= listOfNumbers.stream()
                    .filter(n -> n%2==0)
                    .map(n -> n*2)
                    .reduce(0, Integer::sum);
            System.out.println(sum);
    
        }
    }

    When you run above program, you will get below output:

    60

    If you notice, we have used map function to double of input number in above example.

    That’s all about Java 8 Stream map example.

    ]]> https://java2blog.com/java-8-stream-map/feed/ 0 Java 8 Stream filter examples https://java2blog.com/java-8-stream-filter-examples/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream-filter-examples https://java2blog.com/java-8-stream-filter-examples/#respond Tue, 13 Sep 2016 18:50:00 +0000 http://www.java2blog.com/?p=113
    In this post,  we are going to see about Java 8 Stream filter example.
    You can convert list or array to stream very easily and perform various operations on top of it.Java 8 Stream provides various methods such as map,  filter, reduce etc.
    Let’s see more about Java 8 Stream filter method.

    Java 8 Stream filter

    As name suggests, filter method is used to filter stream on basis of criterion. You can pass lambda expressions to filter method but it should always return a boolean value. We have already seen how to pass Predicate object to filter method to filter a collection.
    Lets understand more with help of example: 
    Lets say you have Student class as below:

    package org.arpit.java2blog;
    
    public class Student {
    
        private int id;
        private String name;
        private String gender;
        private int age;
    
        public Student(int id, String name, String gender, int age) {
            super();
            this.id = id;
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + "]";
        }
    }

    Lets say you have list of student objects in studentList and you need to filter all male students.
    You can do it with the help of Stream with below code:

    // Filter all male students
    List maleStudents=studentList.stream()
    .filter(s-> s.getGender().equalsIgnoreCase("M") )
    .collect(Collectors.toList());
    System.out.println("Male students are :"+maleStudents);

    Here we have used stream‘s filter method to filter list and then collect the result to another list with Collectors.toList().

    Java 8 filter,findAny or orElse method

    You can use stream’s filter method to filter list and use findAny and orElse method based on conditions.
    For example:You want to filter Student with name John, if you do not find it in the list then return null.

    // Filer based on name
    Student student=studentList.stream()
    .filter(s-> s.getName().equalsIgnoreCase("John"))
    .findAny()
    .orElse(null); 
    System.out.println("Student with Name john :"+student);

    Lets create a main class as below:

    package org.arpit.java2blog;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;
    
    public class Java8StreamFilterExamples {
    
        public static void main(String[] args)
        {   
            List studentList=createStudentList();   
    
            // Filter all male students
            List maleStudents=studentList.stream()
                    .filter(s>s.getGender().equalsIgnoreCase("M"))
                    .collect(Collectors.toList());
            System.out.println("Male students are :"+maleStudents);
    
                    // Filter based on name
            Student student=studentList.stream()
                    .filter(s-> s.getName().equalsIgnoreCase("John"))
                    .findAny()
                    .orElse(null); 
            System.out.println("Student with Name john :"+student);
        }
    
        public static List createStudentList()
        {
            List studentList=new ArrayList();
            Student s1=new Student(1, "Arpit", "M", 19);
            Student s2=new Student(2, "John", "M", 17);
            Student s3=new Student(3, "Mary", "F", 14);
            Student s4=new Student(4, "Martin", "M", 21);
            Student s5=new Student(5, "Monica", "F", 16);
            Student s6=new Student(6, "Ally", "F", 20);
    
            studentList.add(s1);
            studentList.add(s2);
            studentList.add(s3);
            studentList.add(s4);
            studentList.add(s5);
            studentList.add(s6);
            return studentList;
        }
    }

    When you run above program, you will get below output:

    Male students are :[Student [id=1, name=Arpit, gender=M, age=19], Student [id=2, name=John, gender=M, age=17], Student [id=4, name=Martin, gender=M, age=21]] Student with Name john :Student [id=2, name=John, gender=M, age=17]

    Let me know if you need more examples for Stream‘s filter method.

]]>
https://java2blog.com/java-8-stream-filter-examples/feed/ 0
Java 8 Collectors examples https://java2blog.com/java-8-collectors-examples/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-collectors-examples https://java2blog.com/java-8-collectors-examples/#respond Wed, 31 Aug 2016 18:31:00 +0000 http://www.java2blog.com/?p=128 In this post,  we are going to see java 8 Collectors examples. You can do various operations such as average, count, groupby, sort the list with the help of Collectors. I am not providing theory here, I think you will learn better with the help of examples.
Examples:

Counting:

Counting is used to count number of elements in the stream.It returns Collector instance which can be accepted by collect method.

package org.arpit.java2blog;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Java8CollectorsExample {

    public static void main(String[] args) {
        List intList=Arrays.asList(10,20,30,40,50);
        // Counting
        long  count = intList.stream().collect(Collectors.counting());
        System.out.println(count);

    }
}

When you run above code, you will get below output:

5

AveragingInt :

AveragingInt is used to find average of stream elements as int datatype. It returns Collector instance which can be accepted by collect method.

package org.arpit.java2blog;

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

public class Java8CollectorsExample {

    public static void main(String[] args) {
        List intList=Arrays.asList(10,20,30,40,50);
        // Averaging int
        Double result1 = intList.stream().collect(Collectors.averagingInt(v->v));
        System.out.println(result1);

        Double result2 = intList.stream().collect(Collectors.averagingInt(v->v*v));
        System.out.println(result2);
    }
}

When you run above code, you will get below output:

30.0
1100.0

Lets understand how did you get 30 for case 1 :
(10+20+30+40+50/5)= 150/5 =30.0 
Now you must wondering how did we get 1100 for 2nd case:
(10*10 + 20*20 + 30*30 + 40*40 + 50*50)/5=5500/5 = 1100.0 
If you want to understand more about v-> v*v , you can go through Java 8 lambda expressions Similarly we have different function for different data types such as AveragingDouble, AveragingLong.

joining

Joining method is used to concatenate with delimiter, you can also pass prefix and suffix.

package org.arpit.java2blog;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Java8CollectorsExample {

    public static void main(String[] args) {
        List NameList=Arrays.asList("Arpit","John","Martin");
        // Counting
        String  stringWithHyphen = NameList.stream().collect(Collectors.joining("-"));
        System.out.println("String with hyphen : "+stringWithHyphen);
        String  stringWithHyphenAndPrefixAndSuffix = NameList.stream().collect(Collectors.joining("-","==","=="));
        System.out.println("String with hyphen , suffix and prefix :  "+stringWithHyphenAndPrefixAndSuffix);        
    }
}

When you run above code, you will get below output:

String with hyphen : Arpit-John-Martin
String with hyphen , suffix and prefix : ==Arpit-John-Martin==

summingint:

summingInt is used to find sum of stream elements as int datatype. It returns Collector instance which can be accepted by collect method.

package org.arpit.java2blog;

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

public class Java8CollectorsExample {

    public static void main(String[] args) {
        List intList=Arrays.asList(10,20,30,40,50);
        // Averaging int
        Double result1 = intList.stream().collect(Collectors.summingInt(v->v));
        System.out.println(result1);

        Double result2 = intList.stream().collect(Collectors.summingInt(v->v*v));
        System.out.println(result2);
    }
}

When you run above code, you will get below output:

150
5500

Similarly we have different function for different data types such as summingDouble, summingLong.

collectingAndThen:

collectingAndThen: is used to get a Collector instance and perform finishing function on top of it.

package org.arpit.java2blog;

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

public class Java8CollectorsExample {

    public static void main(String[] args) {
        List intList=Arrays.asList(10,20,30,40,50);
        // collectingAndThen
        int result1 = intList.stream().collect(Collectors.collectingAndThen(Collectors.summingInt(v->(int)v),result->result/2));
        System.out.println(result1);
    }
}

When you run above code, you will get below output:

75

Reference: 
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html ]]> https://java2blog.com/java-8-collectors-examples/feed/ 0