January 19, 2024

Java Stream – Convert a Stream to Map

In this tutorial you’ll see how to convert a Stream to Map using collector method and utility methods like toMap() and groupingBy() of Collectors class in Java Stream API.

Syntax of toMap() method is as given below-

toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)

This method returns a Collector that accumulates elements into a Map. Both of the arguments passed to the method are of type Function which is a functional interface. Using these mapping functions keyMapper and valueMapper, keys and values of the resulting Map are calculated.

1. Using Collectors.toMap() method

In the following example a list of students is collected to a Map where key is the student’s roll number and value is Student name.

Student class used is-

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 String getName() {
    return name;
  }

  public String getStream() {
    return stream;
  }

  public int getMarks() {
    return marks;
  }

  @Override
  public String toString() {
    return "Roll Number: " +  getRollNo() 
        + " Name: " + getName() + " Marks: " + getMarks();
  }
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class StreamToMap {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 73),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 76));
    Map<Integer, String> studentMap = studentList.stream()
                          .collect(Collectors.toMap(Student::getRollNo, Student::getName));  
    System.out.println(studentMap);
  }
}
Output
{1=Mercy, 2=Ram, 3=Priscilla, 4=Jacques, 5=Peter}

If you want to collect to a Map where key is the student’s roll number and value is the student object then it can be done as. Here utility method Function.identity() is used which returns a function that always returns its input argument.

public class StreamToMap {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Mercy", "Science", 73),
              new Student(2, "Ram", "Science", 99),
              new Student(3, "Priscilla", "Art", 68),
              new Student(4, "Jacques", "Maths", 97),
              new Student(5, "Peter", "Science", 76));
    Map<Integer, Student> studentMap = studentList.stream()
                          .collect(Collectors.toMap(Student::getRollNo, Function.identity()));  
    System.out.println(studentMap);
  }
}
Output
{1=Roll Number: 1 Name: Mercy Marks: 73, 2=Roll Number: 2 Name: Ram Marks: 99, 3=Roll Number: 3 Name: Priscilla Marks: 68, 4=Roll Number: 4 Name: Jacques Marks: 97, 5=Roll Number: 5 Name: Peter Marks: 76}

2. Using Collectors.groupingBy() method

groupingBy() method also collects elements into a map by dividing elements into two lists of elements as per the passed grouping function. The collector produces a Map<K, List> where key specifies a group and List contains the elements which map to the associated key.

public class StreamToMap {

  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

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


You may also like

January 18, 2024

Java Stream boxed() With Examples

The boxed() method in Java Stream is used to wrap the primitive value (int, long or double) to its respective wrapper class object.

There are primitive specializations of Stream named IntStream, LongStream and DoubleStream each of these interfaces have a boxed() method that returns a Stream consisting of the elements of this stream, each boxed to an Integer, Long or Double respectively. Note that boxed() is an intermediate operation.

boxed stream Java examples

Let’s see few examples how to box a primitive value into its wrapper class using boxed() method.

1. boxed() in IntStream which is used to get a Stream consisting of the elements of this stream, each boxed to an Integer.

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

public class BoxedIntStream {
  public static void main(String[] args) {    
    Stream<Integer> wrappedInts = IntStream.of(1, 2, 3, 4, 5).boxed();
    List<Integer> numList = wrappedInts.collect(Collectors.toList());
    System.out.println(numList);
  }
}
Output
[1, 2, 3, 4, 5]

Here IntStream having int elements first uses boxed() method to wrap these primitive ints into an object of Integer class and then use the Stream consisting of those Integer objects to convert into a List. Doing it directly won’t work, so the following statement results in compile time error.

List<Integer> numList = IntStream.of(1,2,3,4,5).collect(Collectors.toList());

2. boxed() in LongStream which is used to get a Stream consisting of the elements of this stream, each boxed to a Long.

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

public class BoxedLongStream {
  public static void main(String[] args) {
    List<Long> numList = LongStream.of(6, 7, 8, 9, 10)
          .boxed()
          .collect(Collectors.toList());
    System.out.println(numList);
  }
}
Output
[6, 7, 8, 9, 10]

3. boxed() in DoubleStream which is used to get a Stream consisting of the elements of this stream, each boxed to a Double.

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

public class BoxedDoubleStream {
  public static void main(String[] args) {
    List<Double> numList = DoubleStream.of(6, 7, 8, 9, 10)
                               .boxed()
                               .collect(Collectors.toList());
    System.out.println(numList);

  }
}
Output
[6.0, 7.0, 8.0, 9.0, 10.0]

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


You may also like

January 17, 2024

Java Stream concat() With Examples

If you want to merge two streams you can use concat() method in Java Stream API.

Syntax of concat() method

concat(Stream<? extends T> a, Stream<? extends T> b)

Here a represents the first stream and b represents the second stream. Method returns a stream consisting all the elements of the first stream followed by all the elements of the second stream.

The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel.

concat() method Java examples

1. Using concat() method to merge streams of Strings.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<String> stream1 = Stream.of("A", "B", "C");
    Stream<String> stream2 = Stream.of("D", "E", "F");
    Stream<String> mergedStream = Stream.concat(stream1, stream2);
    mergedStream.forEach(System.out::println);
  }
}
Output
A
B
C
D
E
F

2. Using concat method to merge more than 2 streams. You can also layer the concat() method to merge more than two streams, in the following example 4 streams are concatenated.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<Integer> stream1 = Stream.of(1, 2, 3);
    Stream<Integer> stream2 = Stream.of(4, 5, 6);
    Stream<Integer> stream3 = Stream.of(7, 8, 9);
    Stream<Integer> stream4 = Stream.of(10, 11, 12);
    Stream<Integer> mergedStream = Stream.concat(stream1, 
            Stream.concat(Stream.concat(stream2, stream3), stream4));
    mergedStream.forEach(e -> System.out.print(e + " "));
  }
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 

3. Using concat() with other stream operations. A very common scenario is to merge two streams and get only the distinct elements, that can be done by using distinct() in Java stream.

public class ConcatDemo {
  public static void main(String[] args) {
    Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
    Stream<Integer> stream2 = Stream.of(4, 4, 3, 1, 8, 6);

    Stream<Integer> mergedStream = Stream.concat(stream1, stream2).distinct();
    mergedStream.forEach(e -> System.out.print(e + " "));
  }
}
Output
1 2 3 4 5 6 8 

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


You may also like

January 15, 2024

Java Stream count() With Examples

In Java Stream API there is a count() method that returns the count of elements in the stream. In this tutorial you’ll learn about count() method with the help of some examples.

Java Stream count() method

Syntax of the count() method is as follows-

long count()

count method is a special case of a reduction operation as it takes a sequence of input elements and combines them into a single summary result. This method is a terminal operation meaning it produces a result and stream pipeline is considered consumed, and can no longer be used after count operation.

count() method Java examples

1. Using count() to get the number of elements in a List by using list as a Stream source.

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

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 4, 12, 16, 0, 7, 6);
    long result = numList.stream().count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 8

2. You can also use count() method along with other operations to get the count of stream elements after applying other operations. In the following example first filter() method is used to filter out elements as per the given condition (elements should be greater than 10) then count() is used to get the count of elements in the stream after applying filter operation.

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 4, 12, 16, 0, 7, 6);
    long result = numList.stream().filter(e -> e > 10).count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 2

3. In the following example count() is used to get the count of distinct elements.

public class CountDemo {

  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 5, 5, 12, 16, 12, 3, 6);
    long result = numList.stream().distinct().count();
    System.out.println("Number of elements- " + result);
  }
}
Output
Number of elements- 5

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


You may also like

January 14, 2024

AtomicInteger in Java With Examples

java.util.concurrent.atomic package in Java has classes that support lock free atomic operations. That means using classes contained in this package atomicity of operations is guaranteed for integer, long, boolean values along with object references and arrays with out using explicit synchronization or locks. In this post we'll discuss one of such class AtomicInteger in Java which provides an int value that may be updated atomically.

AtomicInteger in Java

AtomicInteger class which is part of java.util.concurrent.atomic package provides methods to get, set, increment, update, compare int value as an atomic operation that too with out using locks or synchronized keyword to regulate access to shared variable by multiple threads.

Atomic classes use CAS (Compare and Swap) to ensure data integrity using non-blocking algorithms. That’s why these classes are considered to be faster than locking where one thread acquires the object lock while other threads are blocked.

Java AtomicInteger Constructors

There are two constructors in AtomicInteger class.

  • AtomicInteger()- Creates a new AtomicInteger with 0 as initial value.
  • AtomicInteger(int initialValue)- Creates a new AtomicInteger initialized with the given initial value.

AtomicInteger Java examples

One of the common use is to provide an atomically incremented counter using an AtomicInteger. For that purpose incrementAndGet() method can be used which atomically increments the current value.

Atomically incremented counter using AtomicInteger
public class AtomicIntExample {
  public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    AtomicInteger atomicInt = new AtomicInteger();
    for(int i = 0; i < 10; i++){
      executor.submit(()->System.out.println("Counter- " + atomicInt.incrementAndGet()));
    }
    executor.shutdown();
  }
}
Output
Counter- 1
Counter- 2
Counter- 3
Counter- 4
Counter- 5
Counter- 6
Counter- 7
Counter- 8
Counter- 9
Counter- 10

In the above example Runnable is implemented as a lambda expression. If you prefer Runnable implemented the old way here is the same example.

public class AtomicIntExample {
  public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    AtomicInteger atomicInt = new AtomicInteger();
    CounterRunnable runnableTask = new  CounterRunnable(atomicInt);
    for(int i = 0; i < 10; i++){
      executor.submit(runnableTask);
    }
    executor.shutdown();
  }
}

class CounterRunnable implements Runnable{
  AtomicInteger atomicInt;
  CounterRunnable(AtomicInteger atomicInt){
    this.atomicInt = atomicInt;
  }
  @Override
  public void run() {
    System.out.println("Counter- " + atomicInt.incrementAndGet());		
  }
}

Methods in AtomicInteger class

Some of the atomic methods in the Java AtomicInteger class are as follows-

  • addAndGet(int delta)- Atomically adds the given value to the current value.
  • compareAndSet(int expect, int update)- Atomically sets the value to the given updated value if the current value == the expected value.
  • getAndDecrement()- Atomically decrements by one the current value.
  • getAndIncrement()- Atomically increments by one the current value.
  • getAndSet(int newValue)- Atomically sets to the given value and returns the old value.
  • getAndUpdate(IntUnaryOperator updateFunction)- Atomically updates the current value with the results of applying the given function, returning the previous value.
  • incrementAndGet()- Atomically increments by one the current value.

Comparing and setting value using AtomicInteger

You can compare and set value using compareAndSet() method which takes two arguments expected value and update. If expected value is equal to the current value of the AtomicInteger instance then the value is updated. Returns true if successful. False return indicates that the actual value was not equal to the expected value.

public class AtomicIntExample {
  public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    AtomicInteger atomicInt = new AtomicInteger(0);
    
    for(int i = 1; i <= 10; i++){
      // delay between each update submission
      try {
        TimeUnit.MILLISECONDS.sleep(20);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      executor.submit(new RunnableTask(atomicInt, atomicInt.get(), i));
    }
    System.out.println("Updated value- " + atomicInt.get());
    executor.shutdown();
  }
}

class RunnableTask implements Runnable{
  AtomicInteger atomicInt;
  int expectedVal;
  int newVal;
  RunnableTask(AtomicInteger atomicInt, int expectedVal, int newVal){
    this.atomicInt = atomicInt;
    this.expectedVal = expectedVal;
    this.newVal = newVal;
  }
  @Override
  public void run() {
    System.out.println("Value updated- " + atomicInt.compareAndSet(expectedVal, newVal));		
  }
}
Output
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Value updated- true
Updated value- 10

That's all for the topic AtomicInteger 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

Generate Random Numbers Java Stream

If you are writing a Java program to generate random numbers, two tried and tested ways are to either use Math.random() method or methods of Random class to get a random number but the limitation with these methods is that they generate a single random number and you would need to use them in a loop in case you need a list of random numbers. With the introduction of Java Stream API in Java 8, Random class has also been expanded to include methods that can return a stream of ints, longs or doubles which means a return type of IntStream, LongStream or DoubleStream.

Random class methods for generating streams

In Random class there are following methods for generating infinite streams-

1. ints()- Returns an effectively unlimited stream of int values.

2. ints(int randomNumberOrigin, int randomNumberBound)- Returns an effectively unlimited stream of int values within the given bounds.

Following methods restrict the generated random numbers.

1. ints(long streamSize)- Returns a stream producing the given streamSize number of int values.

2. ints(long streamSize, int randomNumberOrigin, int randomNumberBound)- Returns a stream producing the given streamSize number of int values within the given bounds.

Same set of methods also exist for producing long and double random numbers-

  • longs()
  • longs(long streamSize)
  • longs(long randomNumberOrigin, long randomNumberBound)
  • longs(long streamSize, long randomNumberOrigin, long randomNumberBound)
and
  • doubles()
  • doubles(double randomNumberOrigin, double randomNumberBound)
  • doubles(long streamSize), doubles(long streamSize, double randomNumberOrigin
  • double randomNumberBound)

Generating stream of random number examples

1. An infinite stream of integers using ints() method of the Random class. Here limit() method of Java Stream is used to limit the stream.

import java.util.Random;

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.ints().limit(10).forEach(System.out::println);
  }
}
Output
164843204
-1469424678
1335628408
29431696
267957743
-944667359
228878324
672262783
1504662080
-262691321

2. In this example we’ll generate 10 random numbers in between the lower and upper bounds of 10 and 50.

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.ints(10, 10, 51).forEach(System.out::println);
  }
}
Output
39
29
14
49
26
29
37
50
31
48

Note that with in the passed bounds lower bound is inclusive where as upper bound is exclusive that’s why to make upper bound till 50, 51 is passed as the argument.

3. If you want 10 random doubles with in the range 0 and 1.

public class RandomNumberGeneration {
  public static void main(String[] args) {
    Random random = new Random();
    random.doubles(10, 0, 1).forEach(System.out::println);
  }
}
Output
0.6099718485028252
0.3440097793096719
0.31985736196344106
0.6028702735888255
0.8780031623608885
0.09055972507136933
0.8280686637964826
0.7917602864784455
0.7277181639918716
0.8424139111003316

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


You may also like

January 13, 2024

Summarizing Collectors in Java Stream

In this tutorial you’ll learn about the different summarizing collectors in Java Stream API that returns a summary statistics Collectors.

Summarizing collectors in Collectors class

There are three summarizing collector methods in Collectors class which are as following-

  • summarizingInt(ToIntFunction<? super T> mapper)- Returns a Collector which applies an int-producing mapping function to each input element.
  • summarizingLong(ToLongFunction<? super T> mapper)- Returns a Collector which applies an long-producing mapping function to each input element.
  • summarizingDouble(ToDoubleFunction<? super T> mapper)- Returns a Collector which applies an double-producing mapping function to each input element.

Argument to these methods is a corresponding functional interface ToIntFunction, ToLongFunction and ToDoubleFunction that represents a function that produces respectively a int, long or double valued result.

Return type of the method used is also as per type and the Collectors returned are of type IntSummaryStatistics, LongSummaryStatistics and DoubleSummaryStatistics.

Summary statistics object that you can get by using these methods encapsulates attributes like-

  • count
  • min
  • max
  • sum
  • average

These summarizing collectors are great utility methods to compute all the above values with in a single pass.

Collectors.summarizingInt() Java example

For the examples we’ll use the Person class objects.

public class Person {
  private String name;
  private int dependents;
  private long age;
  private double weight;
  Person(String name, int dependents, long age, double weight){
    this.name = name;
    this.dependents = dependents;
    this.age = age;
    this.weight = weight;
  }
  public String getName() {
    return name;
  }
  public int getDependents() {
    return dependents;
  }

  public long getAge() {
    return age;
  }
  public double getWeight() {
    return weight;
  }
}

1. To get the summary statistics for the weight field which is of type int.

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

public class SummarizingCollectorDemo {
  public static void main(String[] args) {
    List<Person> personList = Arrays.asList(new Person("Peter", 2, 45, 75.6),
              new Person("Ram", 3, 34, 80),
              new Person("Priscilla", 1, 26, 68),
              new Person("Ajay", 4, 35, 71.5),
              new Person("Dan", 0, 58, 77.8));
    IntSummaryStatistics stats = personList.stream()
                    .collect(Collectors.summarizingInt(Person::getDependents));
    System.out.println("Total count of person- " + stats.getCount());
    System.out.println("Max dependents- " + stats.getMax());
    System.out.println("Min dependents- " + stats.getMin());
    System.out.println("Total number of dependents- " + stats.getSum());
    System.out.println("Average number of dependents- " + stats.getAverage());
  }
}
Output
Total count of person- 5
Max dependents- 4
Min dependents- 0
Total number of dependents- 10
Average number of dependents- 2.0

Collectors.summarizingLong() and Collectors.summarizingDouble() Java example

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

public class SummarizingCollectorDemo {
  public static void main(String[] args) {
    List<Person> personList = Arrays.asList(new Person("Peter", 2, 45, 75.6),
              new Person("Ram", 3, 34, 80),
              new Person("Priscilla", 1, 26, 68),
              new Person("Ajay", 4, 35, 71.5),
              new Person("Dan", 0, 58, 77.8));

    LongSummaryStatistics longSummaryStats = personList.stream()
        .collect(Collectors.summarizingLong(Person::getAge));
    
    DoubleSummaryStatistics doubleSummaryStats = personList.stream()
        .collect(Collectors.summarizingDouble(Person::getWeight));
    System.out.println("Summary statistics for age- " + longSummaryStats);
    System.out.println("Summary statistics for weight- " + doubleSummaryStats);
  }
}
Output
Summary statistics for age- LongSummaryStatistics{count=5, sum=198, min=26, average=39.600000, max=58}
Summary statistics for weight- DoubleSummaryStatistics{count=5, sum=372.900000, min=68.000000, average=74.580000, max=80.000000}

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


You may also like