Showing posts with label Java Collection. Show all posts
Showing posts with label Java Collection. Show all posts

Friday, July 5, 2024

Check if a Number Is Power of 2 in Java

Check if a Number Is Power of 2 in Java

In this article, we will explore different approaches to check if a given number is a power of 2 in Java. We will cover the following methods:

  • Loop Division
  • Using Bitwise & Operations
  • Counting Set Bits
  • Using Integer.highestOneBit()
  • Using Logarithm

1. Loop Division


This approach involves continuously dividing the number by 2 and checking if the remainder is ever not zero.

public class PowerOf2 {
    public static boolean isPowerOfTwo(int n) {
        if (n <= 0) {
            return false;
        }
        while (n % 2 == 0) {
            n /= 2;
        }
        return n == 1;
    }
 
    public static void main(String[] args) {
        System.out.println(isPowerOfTwo(16)); // true
        System.out.println(isPowerOfTwo(18)); // false
    }
}

In the above code:

  • We check if the number is less than or equal to zero. If it is, we return false.
  • We repeatedly divide the number by 2 as long as it is even.
  • Finally, we check if the resulting number is 1.

2. Using Bitwise & Operations


This method utilizes the property that powers of 2 have exactly one bit set in their binary representation.

public class PowerOf2 {
    public static boolean isPowerOfTwo(int n) {
        return n > 0 && (n & (n - 1)) == 0;
    }
 
    public static void main(String[] args) {
        System.out.println(isPowerOfTwo(16)); // true
        System.out.println(isPowerOfTwo(18)); // false
    }
}

In the above code:

◉ We check if the number is greater than zero.
◉ We use the bitwise AND operation to check if the number has only one bit set.

3. Counting Set Bits


This approach counts the number of set bits (1s) in the binary representation of the number.

public class PowerOf2 {
    public static boolean isPowerOfTwo(int n) {
        if (n > 0) {
            count += (n & 1);
            n >>= 1;
        }
        return count == 1;
    }
 
    public static void main(String[] args) {
        System.out.println(isPowerOfTwo(16)); // true
        System.out.println(isPowerOfTwo(18)); // false
    }
}

In the above code:

  • We check if the number is less than or equal to zero.
  • We count the number of set bits by checking the least significant bit and right-shifting the number.
  • We return true if the count of set bits is 1.

4. Using Integer.highestOneBit()


This method uses the Integer.highestOneBit() function to check if the number is a power of 2.

public class PowerOf2 {
    public static boolean isPowerOfTwo(int n) {
        return n > 0 && Integer.highestOneBit(n) == n;
    }
 
    public static void main(String[] args) {
        System.out.println(isPowerOfTwo(16)); // true
        System.out.println(isPowerOfTwo(18)); // false
    }
}

In the above code:

  • We check if the number is greater than zero.
  • We use the Integer.highestOneBit() method to get the highest bit of the number.
  • We check if this highest one-bit is equal to the number itself.

5. Using Logarithm


This approach uses the mathematical property that if a number is a power of 2, its logarithm base 2 should be an integer.

public class PowerOf2 {
    public static boolean isPowerOfTwo(int n) {
        if (n <= 0) {
            return false;
        }
        double log2 = Math.log(n) / Math.log(2);
        return log2 == Math.floor(log2);
    }
 
    public static void main(String[] args) {
        System.out.println(isPowerOfTwo(16)); // true
        System.out.println(isPowerOfTwo(18)); // false
    }
}

In the above code:

  • We check if the number is less than or equal to zero.
  • We calculate the logarithm base 2 of the number.
  • We check if the result is an integer.

6. Summary


Method Advantages  Disadvantages 
Loop Division
  • Simple to understand and implement.
  • Directly checks divisibility by 2.
  • Less efficient for large numbers due to multiple divisions.
Using Bitwise & Operations 
  • Very efficient with constant time complexity O(1).
  • Utilizes fast bitwise operations. 
  • Requires understanding of bitwise operations. 
Counting Set Bits 
  • Conceptually simple and easy to understand. 
  • Less efficient due to the need to count all set bits.
  • Time complexity is O(log n). 
Using Integer.highestOneBit() 
  • Efficient and uses a single built-in method.
  • Constant time complexity O(1). 
  • 5Depends on an understanding of the Integer.highestOneBit() method. 
Using Logarithm
  • 3Uses mathematical properties and is easy to understand. 
  • Less efficient due to the use of floating-point operations.
  • Potential issues with floating-point precision. 

Source: javacodegeeks.com

Friday, January 12, 2024

Unraveling the Power of Collectors, Comparators, and Type Inferencing in Java

Unraveling the Power of Collectors, Comparators, and Type Inferencing in Java

Introduction


Welcome to a comprehensive exploration of the powerful trio in Java programming: Collectors, Comparators, and Type Inferencing. In the ever-evolving landscape of Java development, mastering these essential components is paramount. This article delves into the nuances, applications, and optimization strategies associated with each, aiming to provide a resource that not only educates but empowers developers to harness the full potential of these features.

Collectors in Java: Transforming Data with Precision


Java Collectors are pivotal tools for data manipulation and transformation. Whether you're aggregating elements into a collection or computing statistical information, understanding the intricacies of Collectors is fundamental.

Streamlining Data Aggregation

Collectors.collectingAndThen: This powerful collector enables developers to perform a secondary transformation on the result, adding an extra layer of flexibility to data processing.

Collectors.groupingBy: Ideal for categorizing elements based on specific criteria, this collector simplifies the process of creating grouped representations of data.

Collectors.partitioningBy: When dealing with binary decisions, such as true or false conditions, this collector efficiently partitions data into distinct groups.

Comparators: Fine-Tuning Java's Sorting Mechanism


Sorting lies at the heart of many algorithms, and Java's Comparators play a crucial role in achieving efficient and customizable sorting mechanisms.

Natural Ordering with Comparable Interface

Java's Comparable interface provides a foundation for natural ordering within classes. Implementing this interface allows objects to define their own sorting logic.

Custom Sorting with Comparators

Comparator.comparing: This method facilitates sorting based on a specified key, offering a versatile approach to custom sorting.

Comparator.thenComparing: For scenarios where a single sorting criterion is insufficient, this method enables developers to chain multiple comparators, refining the sorting process.

Type Inferencing: Enhancing Code Readability and Flexibility


Java's type inferencing, introduced in Java 10, has revolutionized the way developers write code, bringing a balance between verbosity and precision.

Var Keyword: Concise Variable Declarations

The introduction of the var keyword allows developers to declare variables without explicitly stating the type. While maintaining strong typing, this feature enhances code readability and reduces redundancy.

Local Variable Type Inference: Embracing the "var" Paradigm

Java's commitment to enhancing developer experience is evident in the embrace of local variable type inference. By inferring types from the context, developers can write code more efficiently without sacrificing clarity.

Optimizing Java Development with the Power Trio


Now that we've unraveled the distinct capabilities of Collectors, Comparators, and Type Inferencing, let's explore how combining these features can lead to optimized Java development.

Efficient Data Processing Pipelines

By employing Collectors judiciously in conjunction with effective Comparators, developers can create streamlined data processing pipelines. This not only enhances the readability of code but also contributes to improved performance.

Enhanced Code Maintainability

Type inferencing, when integrated seamlessly with Collectors and Comparators, contributes to enhanced code maintainability. The reduction of boilerplate code allows developers to focus on the core logic, resulting in more robust and manageable codebases.

Conclusion: Empowering Java Developers to New Heights

In conclusion, mastering the art of Collectors, Comparators, and Type Inferencing in Java is pivotal for any developer aspiring to excel in the ever-evolving world of software development. The synergy of these features opens doors to unparalleled efficiency, readability, and maintainability.

Friday, September 4, 2020

Java 8 Collectors API Tutorial With Real Time Examples

Java 8 Collectors API, Oracle Java Exam Prep, Oracle Java Tutorial and Materials, Oracle Certification

A quick practical guide to Java 8’s Collectors api. Example programs on various useful reduction operations and accumulating elements into collections

1. Overview


In this tutorial, We’ll be learning to Java 8 Collectors API in-depth with all methods and example programs. Collectors is a public final class that extends Object class.

Collectors class provides various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc

This has many methods that are very useful when working with Stream api.

Few methods: toList(), toMap(), toCollection(), joining(), summingInt(), groupingBy() and partitioningBy(), etc.

We will see the example programs on the below Collectors methods and how to use them.

Collectors API Methods:
  1. collect()
  2. toList()
  3. toSet()
  4. toUnmodifiableSet()
  5. toUnmodifiableList(()
  6. toCollection()
  7. toMap()
  8. toUnmodifiableMap()
  9. summingInt()
  10. averagingInt() / averagingLong() / averagingDouble()s
  11. counting()
  12. joining()
  13. groupingBy()
  14. partitioningBy()
  15. toConcurrentMap()
  16. filtering()
  17. flatMapping()
  18. maxBy()
  19. minBy()
  20. reducing()
  21. summarizingDouble() / summarizingInt() / summarizingLong()
  22. teeing()
Note: All methods in the Collectors class are static. So it is good to use static import.

If you are using many methods then use static import.

import static java.util.stream.Collectors.*;

If you are using only a few then use like this.

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.joining;

We will be using the below Employee class in this article.

class Employee {
private int id;
private String name;
private int age;
private String region;
private double sal;

public Employee(int id, String name, int age, String region, double sal) {
this.id = id;
this.name = name;
this.age = age;
this.region = region;
this.sal = sal;
}

// Standard setters and getters
}

Creating an Employee List.

List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(100, "Sundar", 47, "North America", 450000));
employeeList.add(new Employee(200, "Pichai", 25, "North America", 50000));
employeeList.add(new Employee(300, "Larry", 30, "Asia", 450000));
employeeList.add(new Employee(400, "Page", 59, "Africa", 450000));

2. Java 8 Stream.collect() Example


Java 8’s most powerful stream method is collect() method. Which is also called a Terminal method.

It allows us to perform mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in a Stream instance.

The strategy for this operation is provided via Collector interface implementation.

3. Collectors.toList() Example


toList() collector can be used for collecting all Stream elements into a List instance.

Example to collect all employee names into List using toList() method.

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

Output:

[Sundar, Pichai, Larry, Page]

But, there are no guarantees on the type, mutability, serializability, or thread-safety of the List returned.

If you need more control over what type of List should be returned then should use toCollection(Supplier) method.

4. Collectors.toSet() Example


toSet() collector is used for collecting all Stream elements into a Set instance.

Example to collect all the regions into Set.

Set<String> regionSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toSet());
System.out.println(regionSet);

Output:

[Asia, Africa, North America]

But, there are no guarantees on the type, mutability, serializability, or thread-safety of the Set returned.

If you need more control over what type of Set should be returned then should use the toCollection(Supplier) method.

5. Collectors.toUnmodifiableSet() Example


This collects the elements into an unmodifiable set.

The set is created using the toSet() method can be modified.

regionSet.add("hello");
System.out.println(regionSet);

Output:

[Asia, Africa, hello, North America]

toUnmodifiableSet() method works similar to the toSet() but this set can not be modified.

Set<Double> unmodifiableSet = employeeList.stream().map(e -> e.getSal()).collect(Collectors.toUnmodifiableSet());
System.out.println(unmodifiableSet);

Output:

[450000.0, 50000.0]

If we try to modify set then will throw UnsupportedOperationException.

unmodifiableSet.add(10983d);

Exception:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:72)

The returned collector does not allow null values. This will throw NullPointerException if it is presented with a null value.

employeeList.add(null);
Set<Employee> empSet = employeeList.stream().collect(Collectors.toUnmodifiableSet());

The above code will cause NullPointerException. The same will be in the case of the toSet() method.

6. Collectors.toUnmodifiableList(() Example


This is similar to the toList() but toUnmodifiableList will collect elements into an unmodifiable List.

List<Double> unmodifiableList = employeeList.stream().map(e -> e.getSal()).collect(Collectors.toUnmodifiableList());
System.out.println(unmodifiableList);

Output:

[450000.0, 50000.0, 450000.0, 450000.0]

This list holds duplicates, unlike Set.

If List has null value then it will throw java.lang.NullPointerException like toUnmodifiableSet.

7. Collectors.toCollection() Example


As you probably already noticed, when using toSet() and toList() collectors, you can’t make any assumptions of their implementations.

If you want to use a custom implementation or LinkedList or TreeSet, you will need to use the toCollection collector with a provided collection of your choice.

Example to collect the names into LinkedList as opposed to default List implementation.

List<String> namesLinkedList = employeeList.stream().map(e -> e.getName()).collect(Collectors.toCollection(LinkedList::new));
System.out.println(namesLinkedList);

Output:

[Sundar, Pichai, Larry, Page]

Another example to collect regions into TreeSet.

Set<String> regionTreeSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toCollection(TreeSet::new));
System.out.println(regionTreeSet);

Output:

[Africa, Asia, North America]

See the output is sorted because TreeSet sorts the values in it.

Note: This method does not work with immutable objects. In such type of cases, We must write custom Collector implementation or Use collectingAndThen().

8. Collectors.toMap() Example


toMap() Syntax:

public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
Using toMap() method, A stream can be converted into a Map. But, this method needs two parameters.

keyMapper

valueMapper

These two are implementations of Function Functional Interface.

Functional Interface Function has a functional method R apply(T t) that accepts one argument and produces a result.

keyMapper will be used for extracting a Map key from a Stream element, and valueMapper will be used for extracting a value associated with a given key.

Now, We will create a map from a stream such that the map key is emp id and value is corresponding employee object.

keyMapper = (e) -> e.getId()

e refers to the Employee object and getting its id by calling getId() method.

valueMapper =  Function.identity()

This method returns a function that always returns its input argument.

Function.identity() method does take one object as an argument and returns the same object with no change.

Map<Integer, Employee> empMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity()));
System.out.println(empMap);

Output:

{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}

What happens if employeeList has duplicate employees with the same employee id.

Now adding a duplicate emp object with the same emp id but the different name “Larry Page”.

employeeList.add(new Employee(400, "Larry Page", 59, "Africa", 450000));

Added a new emp object with emp id = 400.

Map<Integer, Employee> empDupMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity()));

Will throw the Runtime Exception as follow.

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 400 (attempted merging values Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0] and Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0])
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at com.java.w3schools.blog.java8.streams.Java8CollectorExamples.main(Java8CollectorExamples.java:76)

Note: Map does not check the duplicate objects but does not allow duplicate keys.

toMap() function takes 3rd argument as BinaryOperator Functional Interface which has a functional method R apply(T t, U u). This functional method takes two arguments. In our case, the first argument takes the original employee, Second argument takes the duplicate employee and returns the employee object.

Map<Integer, Employee> empDupMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp));
System.out.println(empDupMap);

Output:

Here BinaryOperator will be invoked when there the same key appears. And returning duplicate objects from BinaryOperator apply() method. That replaces the old employee with a new duplicate employee. See the below output.

{400=Employee [id=400, name=Larry Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}

Observe the employee with id 400 has a new name “Larry Page”. If we want to keep existing emp in the map and ignore the duplicate emp then we should return emp instead of sameEmp.

9. Collectors.toUnmodifiableMap() Example


Syntax:

public static <T,K,U> Collector<T,?,Map<K,U>> toUnmodifiableMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
public static <T,K,U> Collector<T,?,Map<K,U>> toUnmodifiableMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)

Returns a Collector that accumulates the input elements into an unmodifiable Map, whose keys and values are the result of applying the provided mapping functions to the input elements.

Map<Integer, Employee> empUnmodifiedMap = employeeList.stream().collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp));
System.out.println(empUnmodifiedMap);

This function will throw NullPointerException if the keyMapper, valueMapper, or mergeFunction is null.

10. Collectors.summingInt() Example


summingInt() Method does the summation of all extracted elements from the stream and returns Integer.

Syntax:

public static <T> Collector<T,?,Integer> summingInt(ToIntFunction<? super T> mapper)

Example:

Finding the sum of all emp id’s using summingInt() method.

int sumOfEmpIds = employeeList.stream().collect(Collectors.summingInt((Employee e) -> e.getId()));
System.out.println("Collectors.summingInt : " + sumOfEmpIds);

Output:

Collectors.summingInt : 1000

This method is to sum of int values.

Similar to this, Collector api has methods for summingLong(), summingDouble().

public static <T> Collector<T,?,Long> summingLong(ToLongFunction<? super T> mapper)
public static <T> Collector<T,?,Double> summingDouble(ToDoubleFunction<? super T> mapper)

summingDouble() Example:

Now, let us see the code to get the sum of salaries of all employees.

double sumOfEmpSalss = employeeList.stream().collect(Collectors.summingDouble((Employee e) -> e.getSal()));
System.out.println("Collectors.summingDouble : " + sumOfEmpSalss);

Output:

Collectors.summingDouble : 1400000.0

11. Collectors.averagingInt() / averagingLong() / averagingDouble() Examples


Collectors api has methods to get the average for integer, Long and Double values. These methods become now very handy to perform avg operations.

Internally arithmetic logic is applied for stream elements.

Syntax:

public static <T> Collector<T,?,Double> averagingInt(ToIntFunction<? super T> mapper)
public static <T> Collector<T,?,Double> averagingLong(ToLongFunction<? super T> mapper)
public static <T> Collector<T,?,Double> averagingDouble(ToDoubleFunction<? super T> mapper)

Here all these versions of methods return Double rather that its names describe.

Examples:

double avgOfEmpSalss = employeeList.stream().collect(Collectors.averagingDouble((Employee e) -> e.getSal()));
System.out.println("Collectors.averagingDouble avg sal: " + avgOfEmpSalss);

Output:

Collectors.averagingDouble avg sal: 350000.0

12. Collectors.counting() Example


Syntax:

public static <T> Collector<T,?,Long> counting()

This method returns a Long value and just counts the values present in the Stream.

long count = employeeList.stream().collect(Collectors.counting());
System.out.println("Collectors.counting() : Count : " + count);

Output:

Collectors.counting() : Count : 4

13. Collectors.joining() Example


Syntax:

public static Collector<CharSequence,?,String> joining()
public static Collector<CharSequence,?,String> joining(CharSequence delimiter)
public static Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

Joining() method does append the all contents of Stream the order they appear.

This is mainly designed for Strings with Stream<String>.

All versions of joining() methods return String.

joining() Example:

String joinedStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining());
System.out.println("joinedStr by using joining() method : "+joinedStr);

Output:

joinedStr by using joining() method : SundarPichaiLarryPage

This joining() method just concatenates without adding any delimiter.

joining(CharSequence delimiter) Example:

If we want to add some delimiter then we should use this variant of the method.

String joinedDelimiterStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining(" * "));
System.out.println("joinedDelimiterStr by using joining(Delimiter) method : "+joinedDelimiterStr);

Output:

joinedDelimiterStr by using joining(Delimiter) method : Sundar * Pichai * Larry * Page

Now observe the output that added * delimiter for each name.

joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) Example:

Example code to add some value to before and after delimiter is applied.

prefix will be added at the beginning after concatenating the delimiter to all values.

suffix will be added at the end after concatenating the delimiter to all values.

String joinePrePostStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining("*", "@", "|"));
System.out.println("joinePrePostStr by using joining(Delimiter) method : "+joinePrePostStr);

Output:

joinePrePostStr by using joining(Delimiter) method : @Sundar*Pichai*Larry*Page|

14. Collectors.groupingBy() Example


This groupingBy function works similar to the Oracle GROUP BY clause.

GroupingBy collector is used for grouping objects by some property and storing results in a Map instance.

We will see the example of the group by an employee region.

Map<String, List<Employee>> groupByRegion = employeeList.stream().collect(Collectors.groupingBy((Employee e) -> e.getRegion()));
System.out.println("groupByRegion :: "+groupByRegion);

Output:

groupByRegion :: {Asia=[Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]], Africa=[Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]], North America=[Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0]]}

The below two employees are stored under the “North America” region.

Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0]

By default, Map values are stored in the List.

If we want to make value is set then we should specify to the groupingBy() method as below.

Map<String, Set<Employee>> groupByRegionSet = employeeList.stream().collect(Collectors.groupingBy((Employee e) -> e.getRegion(), Collectors.toSet()));

15. Collectors.partitioningBy() Example


Syntax:

public static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(Predicate<? super T> predicate)

First, Take a look at the syntax.

From syntax, This method returns a Map and Boolean is key, List<T> as value. The returned Map always contains mappings for both false and true keys only.

Map<Boolean, List<Employee>> partitionByAge = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30));
System.out.println("partitionByAge :: "+partitionByAge);

partitioningBy() method takes Predicate Functional Interface which returns Boolean. Because of this, Key is always determined as Boolean and value is Employee object.

Output:

partitionByAge :: {false=[Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]], true=[Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]]}

Returned Map value is always a List. If you want to change it to another collection then we must use the below variant of groupingBy() method.

public static <T,D,A> Collector<T,?,Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector< super T,A,D> downstream)

Examples:

// Set as Map value
Map<Boolean, Set<Employee>> partitionByAgeSet = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30, Collectors.toSet()));

// LinkedList as Map value
Map<Boolean, LinkedList<Employee>> partitionByAgeLinedList = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30, Collectors.toCollection(LinkedList::new)));

// TreeSet as Map value
Map<Boolean, TreeSet<Employee>> partitionByAgeTreeSet = employeeList.stream().collect(Collectors.partitioningBy( e -> e.getAge() > 30, Collectors.toCollection(TreeSet::new)));

To make working for TreeSort, the Employee class must implement
Comparable interface. Otherwise, will throw ClassCastException.

Note: If a partition has no elements, its value in the resulting Map will be an empty List.

16. Collectors.toConcurrentMap() Example


We have seen already toMap() in this post. If we want to store the result in Concurrent Map then we should use the toConcurrentMap() method.

Syntax:

public static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
public static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
public static <T,K,U,M extends ConcurrentMap<K,U>> Collector<T,?,M> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)

Examples:

Map<Integer, Employee> empConcurrentMap = employeeList.stream().collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity()));

17. Collectors.filtering() Example


Stream api already has a filter() function. But, this is a very convenient way to do at a single place doing condition and collecting into List or Set.

Based on developer choice, We can choose Collectors or Stream api. Mostly, All use stream api filter() method.

Syntax:

public static <T,A,R> Collector<T,?,R> filtering(Predicate<? super T> predicate, Collector<? super T,A,R> downstream)

Examples:

For all stream elements, the first Predicate will be executed first and next downstream will be applied.

List<Employee> filteredEmpList = employeeList.stream().collect(Collectors.filtering((Employee e) -> e.getAge() > 30, Collectors.toList()));
System.out.println("Collectors.filtering() - filteredEmpList : " + filteredEmpList);

Output:

Collectors.filtering() - filteredEmpList : [Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]]

18. Collectors.flatMapping() Example


This is very useful to convert a Collection of Collections into a flat map. The
flatMapping() collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy or partitioningBy.

Syntax:

public static <T,U,A,R> Collector<T,?,R> flatMapping(Function<? super T,? extends Stream<? extends U>> mapper, Collector<? super U,A,R> downstream)

Example:

Creating LineItem class.

class LineItem {

private int itemId;
private String itemName;
private Date manfacturedDate;

public LineItem(int itemId, String itemName, Date manfacturedDate) {
super();
this.itemId = itemId;
this.itemName = itemName;
this.manfacturedDate = manfacturedDate;
}

public int getItemId() {
return itemId;
}

public void setItemId(int itemId) {
this.itemId = itemId;
}

public String getItemName() {
return itemName;
}

public void setItemName(String itemName) {
this.itemName = itemName;
}

public Date getManfacturedDate() {
return manfacturedDate;
}

public void setManfacturedDate(Date manfacturedDate) {
this.manfacturedDate = manfacturedDate;
}

@Override
public String toString() {
return "LineItem [itemId=" + itemId + ", itemName=" + itemName + ", manfacturedDate=" + manfacturedDate + "]";
}

}

Creating Customer class which has HAS-A relationship to LineIteam with List.

class Customer {
private int id;
private String name;
private boolean active;
private String gender;
private List<LineItem> lineItems;

public Customer(int id, String name, boolean active, String gender, List<LineItem> lineItems) {
super();
this.id = id;
this.name = name;
this.active = active;
this.gender = gender;
this.lineItems = lineItems;
}

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 boolean isActive() {
return active;
}

public void setActive(boolean active) {
this.active = active;
}

public String getGender() {
return gender;
}

public void setGender(String gender) {
this.gender = gender;
}

public List<LineItem> getLineItems() {
return lineItems;
}

public void setLineItems(List<LineItem> lineItems) {
this.lineItems = lineItems;
}

}

Creating Customer object 1

LineItem lineItem1 = new LineItem(1001, "Item 1", new Date(2010, 07, 01));
LineItem lineItem2 = new LineItem(1002, "Item 2", new Date(2020, 07, 01));
LineItem lineItem3 = new LineItem(1003, "Item 3", new Date(2030, 07, 01));
LineItem lineItem4 = new LineItem(1004, "Item 4", new Date(2040, 07, 01));
LineItem lineItem5 = new LineItem(1005, "Item 5", new Date(2050, 07, 01));

List<LineItem> lineItemsList1 = new ArrayList<>();
lineItemsList1.add(lineItem1);
lineItemsList1.add(lineItem2);
lineItemsList1.add(lineItem3);
lineItemsList1.add(lineItem4);
lineItemsList1.add(lineItem5);

Customer customer1 = new Customer(100, "Customer 1", true, "M", lineItemsList1);

Creating Customer object 2

LineItem lineItem6 = new LineItem(2001, "Item 6", new Date(2010, 07, 01));
LineItem lineItem7 = new LineItem(2002, "Item 7", new Date(2020, 07, 01));

List<LineItem> lineItemsList2 = new ArrayList<>();
lineItemsList2.add(lineItem6);
lineItemsList2.add(lineItem7);

Customer customer2 = new Customer(200, "Customer 2", true, "F", lineItemsList2);

Creating Customer object 3

LineItem lineItem8 = new LineItem(2003, "Item 8", new Date(2040, 07, 01));
LineItem lineItem9 = new LineItem(3004, "Item 9", new Date(2070, 07, 01));
LineItem lineItem10 = new LineItem(3005, "Item 10", new Date(2200, 07, 01));

List<LineItem> lineItemsList3 = new ArrayList<>();
lineItemsList3.add(lineItem8);
lineItemsList3.add(lineItem9);
lineItemsList3.add(lineItem10);

Customer customer3 = new Customer(300, "Customer 3", true, "M", lineItemsList3);

Creating Customer object 4

Customer customer4 = new Customer(400, "Customer 4", true, "F", new ArrayList<LineItem>());

Adding all 4 countomers to List.

List<Customer> customersList = new ArrayList<>();
customersList.add(customer1);
customersList.add(customer2);
customersList.add(customer3);
customersList.add(customer4);

Using flatMapping() method to find the LineItems by gender.

Map<String, Set<LineItem>> itemsByGender = customersList.stream()
.collect(Collectors.groupingBy((Customer c) -> c.getGender(),
Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.toSet())));

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

Output:

itemsByGender : {F=[LineItem [itemId=2001, itemName=Item 6, manfacturedDate=Mon Aug 01 00:00:00 IST 3910], LineItem [itemId=2002, itemName=Item 7, manfacturedDate=Sun Aug 01 00:00:00 IST 3920]],
 M=[LineItem [itemId=1001, itemName=Item 1, manfacturedDate=Mon Aug 01 00:00:00 IST 3910], LineItem [itemId=1005, itemName=Item 5, manfacturedDate=Tue Aug 01 00:00:00 IST 3950], LineItem [itemId=1004, itemName=Item 4, manfacturedDate=Thu Aug 01 00:00:00 IST 3940], LineItem [itemId=1002, itemName=Item 2, manfacturedDate=Sun Aug 01 00:00:00 IST 3920], LineItem [itemId=1003, itemName=Item 3, manfacturedDate=Fri Aug 01 00:00:00 IST 3930], LineItem [itemId=2003, itemName=Item 8, manfacturedDate=Thu Aug 01 00:00:00 IST 3940], LineItem [itemId=3004, itemName=Item 9, manfacturedDate=Sat Aug 01 00:00:00 IST 3970], LineItem [itemId=3005, itemName=Item 10, manfacturedDate=Sun Aug 01 00:00:00 IST 4100]]}

Finding the count LineItemas count by gender.

Now instead of calling collecting the output of flatMapping() into Set, invoke Collectors.counting() that count the number of Line items by Gender.

Map<String, Long> itemsCountByGender = customersList.stream().collect(Collectors.groupingBy((Customer c) -> c.getGender(),Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.counting())));

Output:

itemsCountByGender {F=2, M=8}

19. Collectors.maxBy() Example


maxBy() method finds the max element from the stream. To find the max element, we must pass the Comparator implementation to this method as argument.

This method does as same as reducing(BinaryOperator.maxBy(comparator)).

Syntax:

public static <T> Collector<T,?,Optional<T>> maxBy(Comparator<? super T> comparator)
This method returns the Optional object. This object avoids NullPointerException by using isPresent() method of Optional class.

Example:

Collectors.maxBy() Example to find highest emp id object.

Comparator<Employee> empComparator = (e1, e2) -> e1.getId() - e2.getId();
Optional<Employee> empMaxOptional = employeeList.stream().collect(Collectors.maxBy(empComparator));
if(empMaxOptional.isPresent()) {
System.out.println("Max Emp : "+empMaxOptional.get());
}

Output:

Max Emp : Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]

20. Collectors.minBy() Example


minBy() is opposite to the maxBy() method. minBy() method is used to find a minimum element from the Stream. We should pass the
Comparator as an argument.

This method does as same as reducing(BinaryOperator.minBy(comparator)).

Syntax:

public static <T> Collector<T,?,Optional<T>> maxBy(Comparator<? super T> comparator)

This method also returns an Optional instance similar to the maxBy() method.

Example:

Collectors.minBy() Example to find min emp id object.

Optional<Employee> empminOptional = employeeList.stream().collect(Collectors.minBy(empComparator));
if (empminOptional.isPresent()) {
System.out.println("Min Emp : " + empminOptional.get());
}

Output:

Min Emp : Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0]

21. Collectors.reducing() Example


Returns a Collector which performs a reduction of its input elements under a specified BinaryOperator. The result is described as an Optional<T>.

Syntax:

public static <T> Collector<T,?,Optional<T>> reducing(BinaryOperator<T> op)
public static <T> Collector<T,?,T> reducing(T identity, BinaryOperator<T> op)
public static <T,U> Collector<T,?,U> reducing(U identity, Function<? super T,? extends U> mapper, BinaryOperator<U> op)

Example:

// Collectors.reducing() Example
Optional<Employee> reducingOptinal = employeeList.stream().collect(Collectors.reducing(BinaryOperator.minBy(empComparator)));
if (reducingOptinal.isPresent()) {
System.out.println("Min Emp using reducing() method : " + reducingOptinal.get());
}

Output:

Min Emp using reducing() method : Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0]

We can find the max emp element using maxBy static method of BinaryOperator.

22. Collectors.summarizingDouble() / summarizingInt() / summarizingLong() Example


summarizingDouble() method does statistics operations on double values in the stream.

This method returns DoubleSummaryStatistics which holds count, min, max, sum, and the average for all double values in the stream. This helps like a utility method.

Syntax:

public static <T> Collector<T,?,DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)

Example:

DoubleSummaryStatistics doubleSummaryStatistics = employeeList.stream().collect(Collectors.summarizingDouble((Employee e) -> e.getSal()));
System.out.println("Statistics summary on employees salary : "+doubleSummaryStatistics);

Output:

DoubleSummaryStatistics{count=4, sum=1400000.000000, min=50000.000000, average=350000.000000, max=450000.000000}

In the same way for Integer and Long values separate methods provided to get the statistics using summarizingInt() and summarizingLong().

public static <T> Collector<T,?,LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
public static <T> Collector<T,?,IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)


23. Collectors.teeing() Example


teeing() method is used to combine two Collectors output using a special merger function. This method is added in Java 12.

Syntax:

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

The above syntax is difficult to understand and simplified as below.

public static Collector teeing(Collector collector1, Collector collector2, BiFunction merger)

Simple words, This method accepts two collectors and one merger function. Merger function takes outputs of two collectors and performs operations. Finally, returns some value or object or maybe collection.

Example:

Collectors teeing() example to find the average of first 100 numbers.

// Converting 1 to 100 numbers into Stream integer.
List<Integer> intList = new ArrayList<>();
IntStream.range(1, 100).forEach(i -> intList.add(i));

// Calling teeing method.
Double average = intList.stream().collect(
Collectors.teeing(Collectors.summingDouble(i -> i), Collectors.counting(), (sum, n) -> sum / n));

System.out.println("Average of first 100 numbers: " + average);

Collector 1: Finds the sum of 100 numbers from the stream.

Collectors.summingDouble(i -> i)

Collector 2: Finds count of numbers in the stream.

Collectors.counting()

Merger: Takes sum and count as input and does the average operation.

(sum, n) -> sum / n)

Output:

Average of first 100 numbers: 50.0


24. Complete Collectors Methods Examples


All Collectors utility class all methods with examples in a single program.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.DoubleSummaryStatistics;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Java 8 Collectors api Examples
 *
 * @author Venkatesh
 *
 */
public class Java8CollectorExamples {

public static void main(String[] args) {

// Creating a Employee List - Example

List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(100, "Sundar", 47, "North America", 450000));
employeeList.add(new Employee(200, "Pichai", 25, "North America", 50000));
employeeList.add(new Employee(300, "Larry", 30, "Asia", 450000));
employeeList.add(new Employee(400, "Page", 59, "Africa", 450000));

// Collectors.toList() Example

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

// Collectors.toSet() Example
Set<String> regionSet = employeeList.stream().map(e -> e.getRegion()).collect(Collectors.toSet());
System.out.println(regionSet);
regionSet.add("hello");
System.out.println(regionSet);

// Collectors.toUnmodifiableSet() Example

Set<Double> unmodifiableSet = employeeList.stream().map(e -> e.getSal())
.collect(Collectors.toUnmodifiableSet());
System.out.println(unmodifiableSet);
// unmodifiableSet.add(10983d);

// employeeList.add(null);

Set<Employee> empSet = employeeList.stream().collect(Collectors.toUnmodifiableSet());

// Collectors.toUnmodifiableList(() Example
// employeeList.add(null);
List<Double> unmodifiableList = employeeList.stream().map(e -> e.getSal())
.collect(Collectors.toUnmodifiableList());
System.out.println(unmodifiableList);

// Collectors.toCollection() Example

List<String> namesLinkedList = employeeList.stream().map(e -> e.getName())
.collect(Collectors.toCollection(LinkedList::new));
System.out.println(namesLinkedList);

Set<String> regionTreeSet = employeeList.stream().map(e -> e.getRegion())
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(regionTreeSet);

// Collectors.toMap() Example
Map<Integer, Employee> empMap = employeeList.stream()
.collect(Collectors.toMap((e) -> e.getId(), Function.identity()));
System.out.println(empMap);

// with duplicate key. uncomment to work with toMap() for duplicate merger.
// employeeList.add(new Employee(400, "Larry Page", 59, "Africa", 450000));

Map<Integer, Employee> empDupMap = employeeList.stream()
.collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp));
System.out.println(empDupMap);

// Collectors.toUnmodifiableMap() Example
Map<Integer, Employee> empUnmodifiedMap = employeeList.stream()
.collect(Collectors.toMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp));
System.out.println(empUnmodifiedMap);

// Collector.summingInt() Example

int sumOfEmpIds = employeeList.stream().collect(Collectors.summingInt((Employee e) -> e.getId()));
System.out.println("Collectors.summingInt : " + sumOfEmpIds);

// Collector.summingInt() Example

double sumOfEmpSalss = employeeList.stream().collect(Collectors.summingDouble((Employee e) -> e.getSal()));
System.out.println("Collectors.summingDouble : " + sumOfEmpSalss);

// Collectors.averagingInt() / averagingLong() / averagingDouble() Examples

double avgOfEmpSalss = employeeList.stream().collect(Collectors.averagingDouble((Employee e) -> e.getSal()));
System.out.println("Collectors.averagingDouble avg sal: " + avgOfEmpSalss);

// Collectors.counting() Example

long count = employeeList.stream().collect(Collectors.counting());
System.out.println("Collectors.counting() : Count : " + count);

// Collectors.joining() Example
String joinedStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining());
System.out.println("joinedStr by using joining() method : " + joinedStr);

String joinedDelimiterStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining(" * "));
System.out.println("joinedDelimiterStr by using joining(Delimiter) method : " + joinedDelimiterStr);

String joinePrePostStr = employeeList.stream().map(e -> e.getName()).collect(Collectors.joining("*", "@", "|"));
System.out.println("joinePrePostStr by using joining(Delimiter) method : " + joinePrePostStr);

// Collectors.groupingBy() Example
Map<String, List<Employee>> groupByRegion = employeeList.stream()
.collect(Collectors.groupingBy((Employee e) -> e.getRegion()));
System.out.println("groupByRegion :: " + groupByRegion);

// groupingBy for set.
Map<String, Set<Employee>> groupByRegionSet = employeeList.stream()
.collect(Collectors.groupingBy((Employee e) -> e.getRegion(), Collectors.toSet()));
System.out.println("groupByRegionSet :: " + groupByRegionSet);

// Collectors.partitioningBy() Example
Map<Boolean, List<Employee>> partitionByAge = employeeList.stream()
.collect(Collectors.partitioningBy(e -> e.getAge() > 30));
System.out.println("partitionByAge :: " + partitionByAge);

// Set as Map value
Map<Boolean, Set<Employee>> partitionByAgeSet = employeeList.stream()
.collect(Collectors.partitioningBy(e -> e.getAge() > 30, Collectors.toSet()));

// LinkedList as Map value
Map<Boolean, LinkedList<Employee>> partitionByAgeLinedList = employeeList.stream()
.collect(Collectors.partitioningBy(e -> e.getAge() > 30, Collectors.toCollection(LinkedList::new)));

// TreeSet as Map value
/*
* Map<Boolean, TreeSet<Employee>> partitionByAgeTreeSet = employeeList.stream()
* .collect(Collectors.partitioningBy(e -> e.getAge() > 30,
* Collectors.toCollection(TreeSet::new)));
*/

// Collectors.toConcurrentMap() Example
Map<Integer, Employee> empConcurrentMap = employeeList.stream()
.collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity()));
System.out.println(empConcurrentMap);

// with duplicate key. uncomment to work with toMap() for duplicate merger.
// employeeList.add(new Employee(400, "Larry Page", 59, "Africa", 450000));

Map<Integer, Employee> empDupConcurrentMap = employeeList.stream()
.collect(Collectors.toConcurrentMap((e) -> e.getId(), Function.identity(), (emp, sameEmp) -> sameEmp));
System.out.println(empDupMap);

// Collectors.filtering() Example
List<Employee> filteredEmpList = employeeList.stream()
.collect(Collectors.filtering((Employee e) -> e.getAge() > 30, Collectors.toList()));
System.out.println("Collectors.filtering() - filteredEmpList : " + filteredEmpList);

// Collectors.flatMapping() Example

LineItem lineItem1 = new LineItem(1001, "Item 1", new Date(2010, 07, 01));
LineItem lineItem2 = new LineItem(1002, "Item 2", new Date(2020, 07, 01));
LineItem lineItem3 = new LineItem(1003, "Item 3", new Date(2030, 07, 01));
LineItem lineItem4 = new LineItem(1004, "Item 4", new Date(2040, 07, 01));
LineItem lineItem5 = new LineItem(1005, "Item 5", new Date(2050, 07, 01));

List<LineItem> lineItemsList1 = new ArrayList<>();
lineItemsList1.add(lineItem1);
lineItemsList1.add(lineItem2);
lineItemsList1.add(lineItem3);
lineItemsList1.add(lineItem4);
lineItemsList1.add(lineItem5);

Customer customer1 = new Customer(100, "Customer 1", true, "M", lineItemsList1);

LineItem lineItem6 = new LineItem(2001, "Item 6", new Date(2010, 07, 01));
LineItem lineItem7 = new LineItem(2002, "Item 7", new Date(2020, 07, 01));

List<LineItem> lineItemsList2 = new ArrayList<>();
lineItemsList2.add(lineItem6);
lineItemsList2.add(lineItem7);

Customer customer2 = new Customer(200, "Customer 2", true, "F", lineItemsList2);

LineItem lineItem8 = new LineItem(2003, "Item 8", new Date(2040, 07, 01));
LineItem lineItem9 = new LineItem(3004, "Item 9", new Date(2070, 07, 01));
LineItem lineItem10 = new LineItem(3005, "Item 10", new Date(2200, 07, 01));

List<LineItem> lineItemsList3 = new ArrayList<>();
lineItemsList3.add(lineItem8);
lineItemsList3.add(lineItem9);
lineItemsList3.add(lineItem10);

Customer customer3 = new Customer(300, "Customer 3", true, "M", lineItemsList3);
Customer customer4 = new Customer(400, "Customer 4", true, "F", new ArrayList<LineItem>());

List<Customer> customersList = new ArrayList<>();
customersList.add(customer1);
customersList.add(customer2);
customersList.add(customer3);
customersList.add(customer4);

Map<String, Set<LineItem>> itemsByGender = customersList.stream()
.collect(Collectors.groupingBy((Customer c) -> c.getGender(),
Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.toSet())));
System.out.println("itemsByGender : " + itemsByGender);

Map<String, Long> itemsCountByGender = customersList.stream()
.collect(Collectors.groupingBy((Customer c) -> c.getGender(),
Collectors.flatMapping(customer -> customer.getLineItems().stream(), Collectors.counting())));
System.out.println("itemsCountByGender " + itemsCountByGender);

// Collectors.maxBy() Example
Comparator<Employee> empComparator = (e1, e2) -> e1.getId() - e2.getId();
Optional<Employee> empMaxOptional = employeeList.stream().collect(Collectors.maxBy(empComparator));
if (empMaxOptional.isPresent()) {
System.out.println("Max Emp : " + empMaxOptional.get());
}

// Collectors.minBy() Example
Optional<Employee> empminOptional = employeeList.stream().collect(Collectors.minBy(empComparator));
if (empminOptional.isPresent()) {
System.out.println("Min Emp : " + empminOptional.get());
}

// Collectors.reducing() Example
Optional<Employee> reducingOptinal = employeeList.stream()
.collect(Collectors.reducing(BinaryOperator.minBy(empComparator)));
if (reducingOptinal.isPresent()) {
System.out.println("Min Emp using reducing() method : " + reducingOptinal.get());
}

// Collectors.summarizingDouble() Example
DoubleSummaryStatistics doubleSummaryStatistics = employeeList.stream()
.collect(Collectors.summarizingDouble((Employee e) -> e.getSal()));
System.out.println("Statistics summary on employees salary : " + doubleSummaryStatistics);

// Converting 1 to 100 numbers into Stream integer.
List<Integer> intList = new ArrayList<>();
IntStream.range(1, 100).forEach(i -> intList.add(i));

// Calling teeing method.
Double average = intList.stream().collect(
Collectors.teeing(Collectors.summingDouble(i -> i), Collectors.counting(), (sum, n) -> sum / n));

System.out.println("Average of first 100 numbers: " + average);

}
}

Output:

[Sundar, Pichai, Larry, Page]
[Asia, Africa, North America]
[Asia, Africa, hello, North America]
[50000.0, 450000.0]
[450000.0, 50000.0, 450000.0, 450000.0]
[Sundar, Pichai, Larry, Page]
[Africa, Asia, North America]
{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}
{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}
{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}
Collectors.summingInt : 1000
Collectors.summingDouble : 1400000.0
Collectors.averagingDouble avg sal: 350000.0
Collectors.counting() : Count : 4
joinedStr by using joining() method : SundarPichaiLarryPage
joinedDelimiterStr by using joining(Delimiter) method : Sundar * Pichai * Larry * Page
joinePrePostStr by using joining(Delimiter) method : @Sundar*Pichai*Larry*Page|
groupByRegion :: {Asia=[Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]], Africa=[Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]], North America=[Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0]]}
groupByRegionSet :: {Asia=[Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]], Africa=[Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]], North America=[Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0]]}
partitionByAge :: {false=[Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]], true=[Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]]}
{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}
{400=Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0], 100=Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], 200=Employee [id=200, name=Pichai, age=25, region=North America, sal=50000.0], 300=Employee [id=300, name=Larry, age=30, region=Asia, sal=450000.0]}
Collectors.filtering() - filteredEmpList : [Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0], Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]]
itemsByGender : {F=[LineItem [itemId=2001, itemName=Item 6, manfacturedDate=Mon Aug 01 00:00:00 IST 3910], LineItem [itemId=2002, itemName=Item 7, manfacturedDate=Sun Aug 01 00:00:00 IST 3920]], M=[LineItem [itemId=1001, itemName=Item 1, manfacturedDate=Mon Aug 01 00:00:00 IST 3910], LineItem [itemId=1005, itemName=Item 5, manfacturedDate=Tue Aug 01 00:00:00 IST 3950], LineItem [itemId=1004, itemName=Item 4, manfacturedDate=Thu Aug 01 00:00:00 IST 3940], LineItem [itemId=1002, itemName=Item 2, manfacturedDate=Sun Aug 01 00:00:00 IST 3920], LineItem [itemId=1003, itemName=Item 3, manfacturedDate=Fri Aug 01 00:00:00 IST 3930], LineItem [itemId=2003, itemName=Item 8, manfacturedDate=Thu Aug 01 00:00:00 IST 3940], LineItem [itemId=3004, itemName=Item 9, manfacturedDate=Sat Aug 01 00:00:00 IST 3970], LineItem [itemId=3005, itemName=Item 10, manfacturedDate=Sun Aug 01 00:00:00 IST 4100]]}
itemsCountByGender {F=2, M=8}
Max Emp : Employee [id=400, name=Page, age=59, region=Africa, sal=450000.0]
Min Emp : Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0]
Min Emp using reducing() method : Employee [id=100, name=Sundar, age=47, region=North America, sal=450000.0]
Statistics summary on employees salary : DoubleSummaryStatistics{count=4, sum=1400000.000000, min=50000.000000, average=350000.000000, max=450000.000000}
Average of first 100 numbers: 50.0

Wednesday, July 15, 2020

The Collection Interface

Oracle Java Tutorial and Material, Oracle Java Exam Prep, Oracle Java Study Materials

A Collection represents a group of objects known as its elements. The Collection interface is used to pass around collections of objects where maximum generality is desired. For example, by convention all general-purpose collection implementations have a constructor that takes a Collection argument. This constructor, known as a conversion constructor, initializes the new collection to contain all of the elements in the specified collection, whatever the given collection's subinterface or implementation type. In other words, it allows you to convert the collection's type.

Suppose, for example, that you have a Collection<String> c, which may be a List, a Set, or another kind of Collection. This idiom creates a new ArrayList (an implementation of the List interface), initially containing all the elements in c.

List<String> list = new ArrayList<String>(c);

Or — if you are using JDK 7 or later — you can use the diamond operator:

List<String> list = new ArrayList<>(c);

The Collection interface contains methods that perform basic operations, such as int size(), boolean isEmpty(), boolean contains(Object element), boolean add(E element), boolean remove(Object element), and Iterator<E> iterator().

It also contains methods that operate on entire collections, such as boolean containsAll(Collection<?> c), boolean addAll(Collection<? extends E> c), boolean removeAll(Collection<?> c), boolean retainAll(Collection<?> c), and void clear().

Additional methods for array operations (such as Object[] toArray() and <T> T[] toArray(T[] a) exist as well.

In JDK 8 and later, the Collection interface also exposes methods Stream<E> stream() and Stream<E> parallelStream(), for obtaining sequential or parallel streams from the underlying collection.

The Collection interface does about what you'd expect given that a Collection represents a group of objects. It has methods that tell you how many elements are in the collection (size, isEmpty), methods that check whether a given object is in the collection (contains), methods that add and remove an element from the collection (add, remove), and methods that provide an iterator over the collection (iterator).

The add method is defined generally enough so that it makes sense for collections that allow duplicates as well as those that don't. It guarantees that the Collection will contain the specified element after the call completes, and returns true if the Collection changes as a result of the call. Similarly, the remove method is designed to remove a single instance of the specified element from the Collection, assuming that it contains the element to start with, and to return true if the Collection was modified as a result.

Traversing Collections


There are three ways to traverse collections: (1) using aggregate operations (2) with the for-each construct and (3) by using Iterators.

Aggregate Operations

In JDK 8 and later, the preferred method of iterating over a collection is to obtain a stream and perform aggregate operations on it. Aggregate operations are often used in conjunction with lambda expressions to make programming more expressive, using less lines of code. The following code sequentially iterates through a collection of shapes and prints out the red objects:

myShapesCollection.stream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));

Likewise, you could easily request a parallel stream, which might make sense if the collection is large enough and your computer has enough cores:

myShapesCollection.parallelStream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));

There are many different ways to collect data with this API. For example, you might want to convert the elements of a Collection to String objects, then join them, separated by commas:

    String joined = elements.stream()
    .map(Object::toString)
    .collect(Collectors.joining(", "));

Or perhaps sum the salaries of all employees:

int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));

These are but a few examples of what you can do with streams and aggregate operations.

The Collections framework has always provided a number of so-called "bulk operations" as part of its API. These include methods that operate on entire collections, such as containsAll, addAll, removeAll, etc. Do not confuse those methods with the aggregate operations that were introduced in JDK 8. The key difference between the new aggregate operations and the existing bulk operations (containsAll, addAll, etc.) is that the old versions are all mutative, meaning that they all modify the underlying collection. In contrast, the new aggregate operations do not modify the underlying collection. When using the new aggregate operations and lambda expressions, you must take care to avoid mutation so as not to introduce problems in the future, should your code be run later from a parallel stream.

for-each Construct

The for-each construct allows you to concisely traverse a collection or array using a for loop — see The for Statement. The following code uses the for-each construct to print out each element of a collection on a separate line.

for (Object o : collection)
    System.out.println(o);

Iterators

An Iterator is an object that enables you to traverse through a collection and to remove elements from the collection selectively, if desired. You get an Iterator for a collection by calling its iterator method. The following is the Iterator interface.

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove(); //optional
}

The hasNext method returns true if the iteration has more elements, and the next method returns the next element in the iteration. The remove method removes the last element that was returned by next from the underlying Collection. The remove method may be called only once per call to next and throws an exception if this rule is violated.

Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.

Use Iterator instead of the for-each construct when you need to:

◉ Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.

◉ Iterate over multiple collections in parallel.

The following method shows you how to use an Iterator to filter an arbitrary Collection — that is, traverse the collection removing specific elements.

static void filter(Collection<?> c) {
    for (Iterator<?> it = c.iterator(); it.hasNext(); )
        if (!cond(it.next()))
            it.remove();
}

This simple piece of code is polymorphic, which means that it works for any Collection regardless of implementation. This example demonstrates how easy it is to write a polymorphic algorithm using the Java Collections Framework.

Collection Interface Bulk Operations


Bulk operations perform an operation on an entire Collection. You could implement these shorthand operations using the basic operations, though in most cases such implementations would be less efficient. The following are the bulk operations:

◉ containsAll — returns true if the target Collection contains all of the elements in the specified Collection.

◉ addAll — adds all of the elements in the specified Collection to the target Collection.

◉ removeAll — removes from the target Collection all of its elements that are also contained in the specified Collection.

◉ retainAll — removes from the target Collection all its elements that are not also contained in the specified Collection. That is, it retains only those elements in the target Collection that are also contained in the specified Collection.

◉ clear — removes all elements from the Collection.

The addAll, removeAll, and retainAll methods all return true if the target Collection was modified in the process of executing the operation.

As a simple example of the power of bulk operations, consider the following idiom to remove all instances of a specified element, e, from a Collection, c.

c.removeAll(Collections.singleton(e));

More specifically, suppose you want to remove all of the null elements from a Collection.

c.removeAll(Collections.singleton(null));

This idiom uses Collections.singleton, which is a static factory method that returns an immutable Set containing only the specified element.

Collection Interface Array Operations


The toArray methods are provided as a bridge between collections and older APIs that expect arrays on input. The array operations allow the contents of a Collection to be translated into an array. The simple form with no arguments creates a new array of Object. The more complex form allows the caller to provide an array or to choose the runtime type of the output array.

For example, suppose that c is a Collection. The following snippet dumps the contents of c into a newly allocated array of Object whose length is identical to the number of elements in c.

Object[] a = c.toArray();

Suppose that c is known to contain only strings (perhaps because c is of type Collection<String>). The following snippet dumps the contents of c into a newly allocated array of String whose length is identical to the number of elements in c.

String[] a = c.toArray(new String[0]);

Wednesday, February 19, 2020

How to combine two Map in Java? Example

You can combine two maps in Java by using the putAll() method of java.util.Map interface. This method copies all the mappings from one Map to another, like, if you call it like first.putAll(second), then all mappings from the second Map will be copied into the first Map. Which means if the first map contains 5 elements and the second map contains 10 elements or mapping, then the combined map will contain 15 or fewer mappings. In the case of duplicate keys, the value is overridden or updated from the second map. For example, if the first map has a mapping 1 -> One and second map has mapping 1 -> ONE then after combining the second map into the first one, the value of 1 will be ONE, i.e. the value from the second map.

The putAll() method copies all of the mappings from the specified map to this map. The effect of this call is similar to iterating over the map and calling put(k, v) on this Map once for each mapping from key k to value v in the specified map.

Btw, this is an optional operation for any Map implementation, but HashMap implements this method. You will get the UnsupportedOperationException if the putAll operation is not supported by this map.

The putAll() method also throws NullPointerException if the specified map is null, or if this map does not permit null keys or values, and the specified map contains null keys or values.

It can also throw ClassCastException if the class of a key or value in the specified map prevents it from being stored in this map. Also, the behavior of this operation is undefined if the specified map is modified while the operation is in progress.

Java Program to Copy Values from One Map to Other


Here is a simple program to copy values from one map to other in Java. This way, you can combine mappings, like both keys and values. For example, if you receive two maps of orders from different systems, you can combine them to calculate the total notional value.

In our case, we just have two maps where numbers are mapped to their String values. In one map we have mapped number to equivalent string written in a small case and other maps we have done the same thing, but strings are in capital order.

This has been done to show that in the case of duplicate keys, the values are updated from the second map. This is the basic property of Map and all the Map implementations like HashMap, ConcurrentHashMap, and Hashtable follows it.

Oracle Java Study Material, Oracle Java Prep, Oracle Java Exam Prep, Oracle Java Certification

Java program to combine two maps in Java


import java.util.HashMap;
import java.util.Map;

public class Helloworld {

  public static void main(String[] args) {

    // first map integer to string
    Map<Integer, String> intToString = new HashMap<Integer, String>();
    intToString.put(1, "One");
    intToString.put(2, "Two");
    intToString.put(3, "Three");
    intToString.put(4, "Four");
    intToString.put(5, "Five");

    System.out.println("first map: " + intToString);

    // second map - prime numbers
    Map<Integer, String> primes = new HashMap<>();
    primes.put(2, "TWO");
    primes.put(3, "THREE");
    primes.put(5, "FIVE");
    primes.put(7, "SEVEN");
    primes.put(11, "ELEVEN");

    System.out.println("second map: " + primes);

    // when you combine map, it would contains mapping
    // from the two maps, but for duplicate keys
    // values will be updated from the second map
    // you can choose any map to source and destination
    // for example, in below code, intToString map
    // will contain combined value but primes will
    // not be changed.

    intToString.putAll(primes);

    System.out.println("combined map: " + intToString);
  }

}

Output :

first map: {1=One, 2=Two, 3=Three, 4=Four, 5=Five}
second map: {2=TWO, 3=THREE, 5=FIVE, 7=SEVEN, 11=ELEVEN}
combined map: {1=One, 2=TWO, 3=THREE, 4=Four, 5=FIVE, 7=SEVEN, 11=ELEVEN}

Oracle Java Study Material, Oracle Java Prep, Oracle Java Exam Prep, Oracle Java Certification
You can see from the output that in the combined map the value of 2, 3, and 5 is now capital TWO, THREE, and FIVE. Which means their values are updated from the second map. The combined Map also contains new mappings from the second map, like 7 and 11.

That's all about how to combine two maps in Java. It's actually very easy, you just need to remember about putAll() method of java.util.Map class. Though be careful, as I said, if your map, in which you are copying mappings has duplicate keys, then their values will be overwritten by values form the second map.

The putAll() is also an optional operation which means you cannot rely on every single map supporting this operation, but for most purpose, unless you are using HashMap or other Map implementation from JDK, it doesn't matter.

Tuesday, February 18, 2020

10 Examples of ConcurrentHashMap in Java

Oracle Java Tutorial and Material, Oracle Java Guides, Oracle Java Prep, Oracle Java Exam Prep

Hello Java programmers, you might have heard about the ConcurrentHashMap class of java.util.concurrent package. If you don't let me tell you that ConcurrentHashMap is an important class in Java and you will often find yourself dealing with this class in a multithreaded and concurrent Java application. If you are wondering where to start and how to master this essential Java class then you have come to the right place. In this article, I have shared some of the frequently used examples of ConcurrentHashMap in Java-like how to create a ConcurrentHashMap, how to update a key or value, how to delete a key-value pair, how to check if a key exists in ConcurrentHashMap or not, how to add new key-value pairs, and how to retrieve values from ConcurrentHashMap in Java.

Once you have gone through these examples, you will have a better understanding of ConcurrentHashMap and you will be more confident on using them in your Java program without causing subtle bugs that are hard to find and fix.

10 Examples of ConcurrentHashMap in Java


Without wasting any more of your time, here are 10 useful examples of ConcurrentHashMap in Java.

1. How to create a ConcurrentHashMap with default capacity?

        ConcurrentHashMap programmingLanguages = new ConcurrentHashMap();
        System.out.println("Empty ConcurrentHashMap : " + programmingLanguages);

2. How to add objects into ConcurrentHashMap?

        programmingLanguages.put("Java", Integer.valueOf(18));
        programmingLanguages.put("Scala", Integer.valueOf(10));
        programmingLanguages.put("C++", Integer.valueOf(31));
        programmingLanguages.put("C", Integer.valueOf(41));
        System.out.println("ConcurrentHashMap with four mappings : " + programmingLanguages);

3. How to check if a key exists in ConcurrentHashMap or not?

        boolean isJavaExist = programmingLanguages.containsKey("Java");
        boolean isPythonExist = programmingLanguages.containsKey("Python");
        System.out.printf("Does Programming language Map has %s? %b %n", "Java", isJavaExist);
        System.out.printf("Does Programming language Map contains %s? %b %n", "Python", isPythonExist);

4. How to retrieve values from ConcurrentHashMap in Java?

        int howOldIsJava = programmingLanguages.get("Java");
        int howOldIsC = programmingLanguages.get("C");
        System.out.printf("How old is Java programming langugae? %d years %n", howOldIsJava);
        System.out.printf("How old is C langugae? %d years %n", howOldIsC);

5. How to check if a value exists in ConcurrentHashMap?

        boolean is41Present = programmingLanguages.containsValue(Integer.valueOf(41));
        boolean is31Present = programmingLanguages.containsValue(Integer.valueOf(31));
        System.out.printf("Does value 41 is present in ConcurrentHashMap? %b %n", is41Present);
        System.out.printf("Does value 31 is present in ConcurrentHashMap? %b %n", is31Present);

6. How to find Size of ConcurrentHashMap in Java?

        int numberOfMappings = programmingLanguages.size();
        System.out.printf("ConcurrentHashMap %s, contains %d mappings %n",
                programmingLanguages, numberOfMappings);

7. How to loop over ConcurrentHashMap in Java?

There are multiple ways to loop over a ConcurrentHashMap in Java. In fact, you can use all the four ways to iterate over the Map with ConcurrentHashMap as well. Ultimately, it also implements the java.utill.Map interface hence it obeys the contract of Map

        Set&gt; entrySet = programmingLanguages.entrySet();
        for (Map.Entry mapping : entrySet) {
            System.out.printf("Key : %s, Value: %s %n", mapping.getKey(), mapping.getValue());
        }

8. PutIfAbsent Example - Adding keys only if it's not present in ConcurrentHashMap?

        System.out.printf("Before : %s %n", programmingLanguages);
        programmingLanguages.putIfAbsent("Java", 22); // Already exists
        System.out.printf("After : %s %n", programmingLanguages);

        programmingLanguages.put("Python", 23);  // Added
        System.out.printf("After : %s %n", programmingLanguages);

9. How to replace a Mapping in ConcurrentHashMap?

You can use the replace method to update the value of a key in ConcurrentHashMap. This method takes both key and value and updates the old value with the new one as shown below:

        programmingLanguages.replace("Java", 20);
        System.out.println("ConcurrentHashMap After replace : " + programmingLanguages);

10. How to remove key values from ConcurrentHashMap in Java?

You can use the remove() method of ConcurrentHashMap to remove the mapping from the Map. This method will remove both key and values and size of ConcurrentHashMap will decrease by one as shown in the following example:

        programmingLanguages.remove("C++");
        System.out.println("ConcurrentHashMap After remove : " + programmingLanguages);

11. How to remove keys, while Iterating over ConcurrentHashMap?

        Iterator keys = programmingLanguages.keySet().iterator();
        while (keys.hasNext()) {
            System.out.printf("Removing key %s from ConcurrentHashMap %n", keys.next());
            keys.remove();
        }

12. How to check if ConcurrentHashMap is empty in Java?

You can use the isEmpty() method of ConcurrentHashMap to check if the given Map is empty or not. This method will return true if ConcurrentHashMap doesn't have any mapping as shown in following example:

boolean isEmpty = programmingLanguages.isEmpty();
System.out.printf("Is ConcurrentHashMap %s is empty? %b ", programmingLanguages, isEmpty);

Oracle Java Tutorial and Material, Oracle Java Guides, Oracle Java Prep, Oracle Java Exam Prep

ConcurrentHashMap Examples Java


Here is the complete Java Program which you can copy paste in Eclpse or run it from command line to play with:

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
  * Java program to demonstrate how to use Concurrent HashMap in Java by simple examples.
  *
  * @author javin
  */

public class ConcurrentHashMapExamples{

    public static void main(String args[]) {

        // Creates a ConcurrentHashMap with default capacity
        ConcurrentHashMap programmingLanguages = new ConcurrentHashMap();
        System.out.println("Empty ConcurrentHashMap : " + programmingLanguages);


        // Adding objects into ConcurrentHashMap
        programmingLanguages.put("Java", Integer.valueOf(18));
        programmingLanguages.put("Scala", Integer.valueOf(10));
        programmingLanguages.put("C++", Integer.valueOf(31));
        programmingLanguages.put("C", Integer.valueOf(41));
        System.out.println("ConcurrentHashMap with four mappings : " + programmingLanguages);


        // Checking if a key exists in ConcurrentHashMap or not
        boolean isJavaExist = programmingLanguages.containsKey("Java");
        boolean isPythonExist = programmingLanguages.containsKey("Python");
        System.out.printf("Does Programming language Map has %s? %b %n", "Java", isJavaExist);
        System.out.printf("Does Programming language Map contains %s? %b %n", "Python", isPythonExist);


        // Retrieving values from ConcurrentHashMap in Java
        int howOldIsJava = programmingLanguages.get("Java");
        int howOldIsC = programmingLanguages.get("C");
        System.out.printf("How old is Java programming langugae? %d years %n", howOldIsJava);
        System.out.printf("How old is C langugae? %d years %n", howOldIsC);


        // Checking if a value exists in ConcurrentHashMap
        boolean is41Present = programmingLanguages.containsValue(Integer.valueOf(41));
        boolean is31Present = programmingLanguages.containsValue(Integer.valueOf(31));
        System.out.printf("Does value 41 is present in ConcurrentHashMap? %b %n", is41Present);
        System.out.printf("Does value 31 is present in ConcurrentHashMap? %b %n", is31Present);


        // Finding Size of ConcurrentHashMap
        int numberOfMappings = programmingLanguages.size();
        System.out.printf("ConcurrentHashMap %s, contains %d mappings %n",
                programmingLanguages, numberOfMappings);


        // Loop over ConcurrentHashMap in Java
        Set&gt; entrySet = programmingLanguages.entrySet();
        for (Map.Entry mapping : entrySet) {
            System.out.printf("Key : %s, Value: %s %n", mapping.getKey(), mapping.getValue());
        }


        //PutIfAbsent Example - Adding keys only if its not present in ConcurrentHashMap
        System.out.printf("Before : %s %n", programmingLanguages);

        programmingLanguages.putIfAbsent("Java", 22); // Already exists
        System.out.printf("After : %s %n", programmingLanguages);

        programmingLanguages.put("Python", 23);  // Added
        System.out.printf("After : %s %n", programmingLanguages);


        // Replacing a Mapping in ConcurrentHashMap
        programmingLanguages.replace("Java", 20);
        System.out.println("ConcurrentHashMap After replace : " + programmingLanguages);


        // Removing key values from ConcurrentHashMap
        programmingLanguages.remove("C++");
        System.out.println("ConcurrentHashMap After remove : " + programmingLanguages);


        // Removing Keys, while Iterating over ConcurrentHashMap
        Iterator keys = programmingLanguages.keySet().iterator();
        while (keys.hasNext()) {
            System.out.printf("Removing key %s from ConcurrentHashMap %n", keys.next());
            keys.remove();

        }


        // How to check if ConcurrentHashMap is empty
        boolean isEmpty = programmingLanguages.isEmpty();
        System.out.printf("Is ConcurrentHashMap %s is empty? %b ", programmingLanguages, isEmpty);

    }

}

Output:

Empty ConcurrentHashMap : {}
ConcurrentHashMap with four mappings : {C=41, Scala=10, Java=18, C++=31}
Does Programming language Map has Java? true
Does Programming language Map contains Python? false
How old is Java programming langugae? 18 years
How old is C langugae? 41 years
Does value 41 is present in ConcurrentHashMap? true
Does value 31 is present in ConcurrentHashMap? true
ConcurrentHashMap {C=41, Scala=10, Java=18, C++=31}, contains 4 mappings
Key : C, Value: 41
Key : Scala, Value: 10
Key : Java, Value: 18
Key : C++, Value: 31
Before : {C=41, Scala=10, Java=18, C++=31}
After : {C=41, Scala=10, Java=18, C++=31}
After : {C=41, Python=23, Scala=10, Java=18, C++=31}
ConcurrentHashMap After replace : {C=41, Python=23, Scala=10, Java=20, C++=31}
ConcurrentHashMap After remove : {C=41, Python=23, Scala=10, Java=20}
Removing key C from ConcurrentHashMap
Removing key Python from ConcurrentHashMap
Removing key Scala from ConcurrentHashMap
Removing key Java from ConcurrentHashMap
Is ConcurrentHashMap {} is empty? true

That's all about ConcurrentHashMap examples in Java. As I said, after going through these examples, you will have a better understanding of How ConcurrentHashMap works and how to use it properly. Now you have a good idea of how to create, add, update, search, and delete entries on a ConcurrentHashMap in Java.