Showing posts with label Streams. Show all posts
Showing posts with label Streams. Show all posts

Tuesday, December 14, 2021

Java 8 Streams Filter With Multiple Conditions Examples

1. Overview


In this tutorial, We'll learn how to utilise stream filter() with several filter conditions (can be more than one condition).

Normally, we apply a single condition to streams using filter() method with lambda and then store the results in Lists or Sets.

However, we'll learn how to use the filter() method with as many condition filters as we require.

More filters can be applied in a variety of methods, such as using the filter() method twice or supplying another predicate to the Predicate.and() method.

In the next sections, we'll look at examples with single and multiple conditions.

GitHub link is given at the end of the article for the shown examples.

Java 8 Streams Filter With Multiple Conditions Examples



Saturday, December 11, 2021

Java 8 Streams if else logic

1. Overview

In this tutorial, We'll learn how to use if/else statements in java 8 streams.

If you are new to the java 8 stream,  It is recommended to read the in-depth on the basics of java 8 streams.

First, we will see the simple to find the even numbers from the given list of numbers.

Next, we will write the java 8 examples with the forEach() and streams filter() method.

Java 8 Streams if else logic


Friday, December 10, 2021

Java 8 Stream Collect() Examples

1. Overview

In this tutorial, We will learn how to use the Stream.collect() method in Java 8 Stream api.

Many of you know that Stream.collect() method is added as part of the new JDK 8 Streams.

Stream collect() method is used to collect the output of stream operations into the collection such as List, Set or Map. Sometimes we can collect into LinkedList, TreeSet or even into the String.

Additionally, we can perform the group by, partition by operations on the streams with Collect() method.

Let us explore the usages of Stream.collect() method with examples.

Java 8 Stream Collect() Examples



2. Java 8 Stream Collect() to List using Collectors.toList()


The below is the first example using Stream.collect() method on the stream pipe line. First created a stream object using stream() method and converted the each value in the stream to uppercase using word.toUpperCase() method. 

Finally, called the collect() method by passing the Collectors.toList() method which collect the each word from the stream into a List. The returned list is the instance of ArrayList and it is the default collection object created by toList() method.


package com.javaprogramto.java8.collectors.collect;

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

/**
 * Examples to Java 8 Stream collect() method
 * 
 * @author JavaProgramTo.com
 *
 */
public class StreamCollectExample {

	public static void main(String[] args) {

		List<String> words = Arrays.asList("hello", "how", "are", "you", "doing", "mate");
		
		List<String> list = words.stream()
				.map(word -> word.toUpperCase())
				.collect(Collectors.toList());
		
		System.out.println("Collectors.toList() : "+list);

	}

}
 
Output:
Collectors.toList() : [HELLO, HOW, ARE, YOU, DOING, MATE]
 

3. Java 8 Stream Collect() to Set using Collectors.toSet()


Furthermore, The below example is to get the numbers length is 3 and remove the duplicates from stream. Finally, collecting the stream output into Set.

And also collected the same output into the List to observe the difference between the toList() and toSet() methods.

toSet() method returns default HashSet object. If you want to get the LinkedHashSet object then you need to use the Collectors.toCollection() method with specifying the LinkedHashSet class.

In the later section of this tutorial, you will learn how to get the different Set object other than default HashSet.

List<String> numbers = Arrays.asList("one", "two", "one", "two", "three", "four");

// using toSet()
Set<String> set = numbers.stream()
 	.filter(number -> number.length() == 3)
	.collect(Collectors.toSet());

// without duplicates
System.out.println("Set removes the duplicates : ");
set.forEach(System.out::println);

// using toList()
List<String> list2 = numbers.stream()
	.filter(number -> number.length() == 3)
	.collect(Collectors.toList());

// without duplicates
System.out.println("List with duplicates: ");
list2.forEach(System.out::println);
 
Output:
Set removes the duplicates : 
one
two
List with duplicates: 
one
two
one
two
 

4. Java 8 Stream Collect() to Map using Collectors.toMap()


Next, In the below example program, we will learn how to convert the stream intermediate output to the Map using Collectors.toMap() method.
List<String> words = Arrays.asList("hello", "how", "are", "you", "doing", "mate");
		
Map<String, Integer> wordsLength = words.stream()
		.collect(Collectors.toMap(Function.identity(), String::length));

System.out.println("toMap() output: ");
wordsLength.forEach((key, value) -> System.out.println(key + " = "+value));
 
Output:
toMap() output: 
how = 3
doing = 5
are = 3
mate = 4
hello = 5
you = 3
Function.identity() is used to get the same object as a key and remember that always identity() method returns the map key when using toMap() method in java 8.

By default, toMap() method returns the HashMap object and if you want TreeMap you can use the overloaded toMap() method as shown in the next section.

If you observe that input list has unique values and Map does not allow the duplicates keys. So what happens if the input has duplicate values as below?
List<String> numbers = Arrays.asList("one", "two", "one", "two", "three", "four");
 
If you run the toMap() logic with the above numbers list with duplicate values then it will through the runtime exception.
Exception in thread "main" java.lang.IllegalStateException: Duplicate key one (attempted merging values 3 and 3)
	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.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	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.javaprogramto.java8.collectors.collect.StreamCollectExample.main(StreamCollectExample.java:45)
 
To work with the duplicate values, we need to use another toMap() overloaded method which takes another 3rd argument that takes care for duplicate keys.

We need to define the logic for duplicate key. If the key is duplicate then add "repeated" string to the value to know that key is repeated,

This the way to handle the duplicate keys with Collectors.toMap() method.
Map<String, String> wordsCount = numbers.stream()
	.collect(Collectors.toMap(Function.identity(), Function.identity(), (oldValue, newValue) -> oldValue+" repeated"));
		
System.out.println("toMap() with dupolicates: ");
wordsCount.forEach((key, value) -> System.out.println(key + " = "+value));
 
Output:
toMap() with duplicates: 
four = four
one = one repeated
three = three
two = two repeated 

5. Java 8 Stream Collect() to Collection such as LinkedList or TreeSet using Collectors.toCollection()


As of now, we have seen toList(), toSet(), toMap() methods and which returns default ArrayList, HashSet, HashMap object as default.

If you want to get the return objects as other collection objects such as LinkedList, LinkedHashSet then use Collectors.toCollection() method.

To cast to TreeMap, you need to use the toMap() method with the Supplier as 4th argument.
// toCollection() examples
// to linkedlist
List<String> linkedList = words.stream()
	.collect(Collectors.toCollection(LinkedList::new));

System.out.println("linkedList is instance of LinkedList = "+(linkedList instanceof LinkedList));

// to linkedhashset
Set<String> linkedhHashSet = words.stream().
	collect(Collectors.toCollection(LinkedHashSet::new));
System.out.println("linkedhHashSet is instance of LinkedHashSet = "+(linkedhHashSet instanceof LinkedHashSet));

// to linkedhashset
Map<String, Integer> treeMap = words.stream()
	.collect(Collectors.toMap(Function.identity(), String::length, (oldValue, newValue) -> newValue, TreeMap::new));
System.out.println("treeMap is instance of TreeMap = "+(treeMap instanceof TreeMap));
	
 
Output:
linkedList is instance of LinkedList = true
linkedhHashSet is instance of LinkedHashSet = true
treeMap is instance of TreeMap = true	
 

6. Java 8 Stream API Collect Full Examples

package com.javaprogramto.java8.collectors.collect;

import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Examples to Java 8 Stream collect() method
 * 
 * @author JavaProgramTo.com
 *
 */
public class StreamCollectExample {

	public static void main(String[] args) {

		// toList() examples
		List<String> words = Arrays.asList("hello", "how", "are", "you", "doing", "mate");
		
		List<String> list = words.stream()
		.map(word -> word.toUpperCase())
		.collect(Collectors.toList());
		
		System.out.println("Collectors.toList() : "+list);

		
		List<String> numbers = Arrays.asList("one", "two", "one", "two", "three", "four");

		// using toSet()
		Set<String> set = numbers.stream().filter(number -> number.length() == 3).collect(Collectors.toSet());
		
		// without duplicates
		System.out.println("Set removes the duplicates : ");
		set.forEach(System.out::println);

		// using toList()
		List<String> list2 = numbers.stream().filter(number -> number.length() == 3).collect(Collectors.toList());
		
		// without duplicates
		System.out.println("List with duplicates: ");
		list2.forEach(System.out::println);
		
		// tomap() examples
		Map<String, Integer> wordsLength = words.stream().collect(Collectors.toMap(Function.identity(), String::length));
		
		System.out.println("toMap() output: ");
		wordsLength.forEach((key, value) -> System.out.println(key + " = "+value));
		
		Map<String, String> wordsCount = numbers.stream().collect(Collectors.toMap(Function.identity(), Function.identity(), (oldValue, newValue) -> oldValue+" repeated"));
		
		System.out.println("toMap() with duplicates: ");
		wordsCount.forEach((key, value) -> System.out.println(key + " = "+value));
		
		// toCollection() examples
		// to linkedlist
		List<String> linkedList = words.stream().collect(Collectors.toCollection(LinkedList::new));
		
		System.out.println("linkedList is instance of LinkedList = "+(linkedList instanceof LinkedList));
		
		// to linkedhashset
		Set<String> linkedhHashSet = words.stream().collect(Collectors.toCollection(LinkedHashSet::new));
		System.out.println("linkedhHashSet is instance of LinkedHashSet = "+(linkedhHashSet instanceof LinkedHashSet));
		
		// to linkedhashset
		Map<String, Integer> treeMap = words.stream().collect(Collectors.toMap(Function.identity(), String::length, (oldValue, newValue) -> newValue, TreeMap::new));
		System.out.println("treeMap is instance of TreeMap = "+(treeMap instanceof TreeMap));
	

	}

}

 

7. Conclusion


In this article, we've seen how to use the Collect() of java 8 Stream api with examples.

collect() method can be used to convert the stream into the List or Set or Map or LinkedList or TreeMap based on the need.

And also we can use collect() with the joining, groupingby(), partitionby(), counting().




Wednesday, December 1, 2021

Java 8 IllegalStateException “Stream has already been operated upon or closed” Exception (Stream reuse)

1. Overview

In this short tutorial, We'll see the most common exception "java.lang.IllegalStateException: stream has already been operated upon or closed". We may encounter this exception when working with the Stream interface in Java 8.

Can we collect stream twice after closing?
Java Stream reuse – traverse stream multiple times?




stream has already been operated upon or closed

Exception

java.lang.IllegalStateException: stream has already been operated upon or closed

Sunday, November 28, 2021

Java 8 Stream map() examples - Stream Conversions

1. Overview


In this article, we'll be learning about a new map() function in Java 8 that is introduced in Stream API. map() method converts a Stream from one form to another Stream. This takes input X type Stream and converts into Y type output Stream.

This is widely used as part of new JDK 8 api.

Java 8 Stream map() examples - Stream Conversions


Friday, November 26, 2021

Java 8 Streams - Join or Append Stream of Strings using Collectors.joining()

1. Overview

In this tutorial, We'll learn how to append or join a list of strings or stream of strings in java 8.

This joining is done with a specific delimiter or separator with the Collectors api method.

Use Collectors.joining() method joins the values of the stream with a delimiter specified. If the delimiter is not specified then it takes nothing as a separator. So, that final returned string will be having just all values concatenated from the stream.

Along with the joining, this method does the conversion from java 8 stream to string object with the default delimiter.

Java 8 Stream Join String


2. Collectors.joining() Method


Collectors.joining() method does concatenate the list of values or list of strings or stream of values or strings into a new string. 

For this method, we can pass the our own delimiter and and also we can supply the prefix, suffix to the output string.

joining() is an overloaded method and available in 3 versions.

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(): Input elements are concatenated into a new String as encounter order in the stream.

joining(CharSequence delimiter): Input elements are concatenated into a new String with the given delimiter value as encounter order in the stream.

joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix): Input elements are concatenated into a new String with the given delimiter, suffix and prefix values as encounter order in the stream.


3. Java 8 Stream Join String Examples


Next, let us write the example programs using all these 3 methods of Collectors.joining().

Below example program does the stream joining as string and converting stream to string.

package com.javaprogramto.java8.streams.join;

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

/**
 * Java Join Stream Of Strings and stream to string examples.
 * 
 * @author JavaProgramTo.com
 *
 */
public class StreamOfStringJoiningExample {

	public static void main(String[] args) {

		// Creating the List with string values using Arrays.asList() method
		List<String> stringsList = Arrays.asList("1", "2", "3", "4", "5");

		// java 8 join stream of strings or stream to string

		// Example - 1: with default delimiter
		String joinWithDefaultDelimiter = stringsList.stream().collect(Collectors.joining());

		// Example - 2: with delimiter
		String joinWithDelimiter = stringsList.stream().collect(Collectors.joining(":"));

		// Example - 3: with given delimiter, suffix and prefix
		String joinWithDelimiterSuffixPrefix = stringsList.stream().collect(Collectors.joining("|", "[", "]"));

		// printing the values
		System.out.println("Input List of strings : " + stringsList);
		System.out.println("joining() string : " + joinWithDefaultDelimiter);
		System.out.println("joining(delimiter) string : " + joinWithDelimiter);
		System.out.println("joining(delimiter, suffix, prefix) string : " + joinWithDelimiterSuffixPrefix);
	}
}

Output:
Input List of strings : [1, 2, 3, 4, 5]
joining() string : 12345
joining(delimiter) string : 1:2:3:4:5
joining(delimiter, suffix, prefix) string : [1|2|3|4|5]

From the output, we can observe the output from 3 methods with default delimiter, custom delimiter and with a prefix and suffix values.


4. Stream IllegalStateException: stream has already been operated upon or closed


In the above program, we have created the new stream every time we call collect() or joining() method. You may think, can we reuse the stream object for the next two calls. Thats mean first create the Stream object once using stream() method and use the same stream object for all joining() calls.

Look the below code and the output.

		// Creating the stream object once and reuse for every collect() call.
		Stream<String> stream = stringsList.stream();

		// java 8 join stream of strings or stream to string
		
		// Example - 1: with default delimiter
		String joinWithDefaultDelimiter = stream.collect(Collectors.joining());

		// Example - 2: with delimiter
		String joinWithDelimiter = stream.collect(Collectors.joining(":"));
		
		// Example - 3: with given delimiter pipe(|), suffix and prefix
		String joinWithDelimiterSuffixPrefix = stream.collect(Collectors.joining("|", "[", "]"));


Output:

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at com.javaprogramto.java8.streams.join.StreamOfStringJoiningExample.main(StreamOfStringJoiningExample.java:29)

We got the runtime exception because once the terminal method collect() is called stream will be closed. In the next step, we are trying to call collect() method on the closed stream.

We have already discussed in detail about the error "stream has already been operated upon or closed" and how can be handled using Supplier.


5. Conclusion


In this article, We've seen how to join the stream of strings and how to convert Stream to String in java 8 with help of the joining() method.




Ref 

Wednesday, November 24, 2021

Stream to Array - How To Convert Stream To Array In Java 8?

1. Overview

In this article, we'll explore the different ways to convert Stream to Array in Java 8.

I have shown in the previous article how to convert ArrayList<String> to String[] array in java 8.

Java 8 Stream api provides a method Stream.toArray() method which converts the string to array in a faster way.

Stream.of(String t) method is used to create Stream of Strings as Stream<String>. 

Learn How To Convert Stream To Array In Java 8?


We will be showing the conversion on the following in this article

1.1 Using Method Reference

1.2 Lambda Expression

1.3 Custom class stream to custom class array

1.4 On primitive types

But, for all the cases, you must use the Stream.toArray() method.

Stream.toArray() Syntax:

<A> A[] toArray(IntFunction<A[]> generator);

Let us explore each of these topics. In this article, We are going to show examples of how to convert Stream of String into a String array. But, you can convert any Stream of objects into any typed array.

Below all are possible with the toArray() method.

Example 1: Convert Stream<String> to String[] array

Example 2: Convert Stream<Employee> to Employee[] array

Example 3: Convert Stream<CustomClass> to CustomClass[] array

Example 4: Convert Stream<Integer> to Integer[] wrapper Integer array

Example 5: Convert Stream<Integer> to int[] primitive array


2. Using Method Reference

Method Reference is a broad topic. You can go through this article for an advanced level.

Method ref is indicated with "::" double colon operator introduced in java 8 and used to create an instance for a class.

Let us write a simple method with Method reference.

    public static String[]  convertStreamToArray(Stream<String> stringStream){
        String[] strArray = stringStream.toArray(String[]::new);
        return strArray;
    }
Next, write the code to test this method working fine or not.

Look at the complete program.
import java.util.Arrays;
import java.util.stream.Stream;

public class MethodRefStreamToArray {

    public static void main(String[] args) {

        Stream<String> stringStream = Stream.of("hello", "reader", "welcome", "to", "javaprogramto.com", "blog");

        String[] array1 = convertStreamToArray(stringStream);

        System.out.println("Array 1 : "+ Arrays.toString(array1));

        Stream<String> stringStream2 = Stream.of("seocond", "example", "stream to array");

        String[] array2 = convertStreamToArray(stringStream2);

        System.out.println("Array 2 : "+ Arrays.toString(array2));

    }

    public static String[] convertStreamToArray(Stream<String> stringStream) {

        String[] strArray = stringStream.toArray(String[]::new);

        return strArray;
    }
}
Output:
Array 1 : [hello, reader, welcome, to, javaprogramto.com, blog]
Array 2 : [seocond, example, stream to array]

3. Using Lambda Expression


Another way is to pass the lambda expression to the toArray() method. toArray() method takes IntFunction as an argument and it takes size as input and returns String[] array with size.
import java.util.Arrays;
import java.util.stream.Stream;

public class LambdaStreamToArray {

    public static void main(String[] args) {

        Stream<String> stringStream = Stream.of("hello", "reader", "welcome", "to", "javaprogramto.com", "blog");

        String[] array1 = convertStreamToArrayWithLambda(stringStream);

        System.out.println("Array 1 : "+ Arrays.toString(array1));

        Stream<String> stringStream2 = Stream.of("seocond", "example", "stream to array");

        String[] array2 = convertStreamToArrayWithLambda(stringStream2);

        System.out.println("Array 2 : "+ Arrays.toString(array2));

    }

    public static String[] convertStreamToArrayWithLambda(Stream<String> stringStream) {

        String[] strArray = stringStream.toArray(size -> {
            return new String[size];
        });

        return strArray;
    }
}
This program produces the output as same as the above section.

4. Using Custom Generator Class


toArray() method takes IntFunction as argument and it is a Functional Interface.

Let us create a custom class that implements the IntFunction and implements apply() method.
import java.util.Arrays;
import java.util.function.IntFunction;
import java.util.stream.Stream;

public class CustomIntFunctionStreamToArray {

    public static void main(String[] args) {

        Stream<String> stringStream = Stream.of("hello", "reader", "welcome", "to", "javaprogramto.com", "blog");

        String[] array1 = stringStream.toArray(new CustomIntFunction());

        System.out.println("Array 1 : "+ Arrays.toString(array1));

        Stream<String> stringStream2 = Stream.of("seocond", "example", "stream to array");

        String[] array2 = stringStream2.toArray(new CustomIntFunction());;

        System.out.println("Array 2 : "+ Arrays.toString(array2));

    }

}

class CustomIntFunction implements IntFunction<String[]>{

    @Override
    public String[] apply(int size) {
        return new String[size];
    }
}
Output:
Array 1 : [hello, reader, welcome, to, javaprogramto.com, blog]
Array 2 : [seocond, example, stream to array]

5. Stream to Primitive Or Wrapper Array conversion

Let us convert Stream of Integers into Integer Array.

Wrapper Stream to Wrapper[] Array Example

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

public class WrapperStreamToArray {

    public static void main(String[] args) {

        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7);

        Integer[] array1 = integerStream.toArray(Integer[]::new);

        System.out.println("Integer Array 1 : " + Arrays.toString(array1));

        Stream<Integer> integerStream2 = Stream.of(11, 22, 33, 44, 55);

        Integer[] array2 = integerStream2.toArray(size -> new Integer[size]);

        System.out.println("Integer Array 2 : " + Arrays.toString(array2));

    }
}
Output:
Integer Array 1 : [1, 2, 3, 4, 5, 6, 7]
Integer Array 2 : [11, 22, 33, 44, 55]
If you pass the Integer array size as 0 as below will get the runtime exception.
Integer[] array2 = integerStream2.toArray(size -> new Integer[0]);
Exception:
Exception in thread "main" java.lang.IllegalStateException: Begin size 5 is not equal to fixed size 0
	at java.base/java.util.stream.Nodes$FixedNodeBuilder.begin(Nodes.java:1222)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:550)
	at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
	at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:517)
	at com.javaprogramto.java8.streams.toarray.WrapperStreamToArray.main(WrapperStreamToArray.java:18)

Wrapper Stream to int[] primitive Array Example

Stream api has another method mapToInt() method which returns the int primitive values as IntStream. Next, will need to call the toArray() method to get the int[] array.

Similar to this steam api has built-in support for mapToLong() and mapToDouble() methods. All of these methods come under Stream Intermediate Options which returns Stream output.
import java.util.Arrays;
import java.util.stream.Stream;

public class PrimitiveStreamToArray {

    public static void main(String[] args) {

        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7);

        int[] array1 = integerStream.mapToInt(primitiveVlaue -> primitiveVlaue).toArray();

        System.out.println("int[] Array 1 : " + Arrays.toString(array1));

        Stream<Integer> integerStream2 = Stream.of(11, 22, 33, 44, 55);

        int[] array2 = integerStream2.mapToInt( i -> i).toArray();

        System.out.println("int[] Array 2 : " + Arrays.toString(array2));

    }
}

7. Exception

If the stream is already closed then it will throw runtime exception saying IllegarStateException and reason is "stream has already been operated upon or closed".
Array 1 : [hello, reader, welcome, to, javaprogramto.com, blog]Exception in thread "main" 
java.lang.IllegalStateException: stream has already been operated upon or closed
	at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:246)
	at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:517)
	at com.javaprogramto.java8.streams.toarray.CustomIntFunctionStreamToArray.main(CustomIntFunctionStreamToArray.java:19)

8. Conclusion


In this article, You've seen how to convert Any Stream to an Array in java 8 using toArray(), mapToInt(), and of() methods.

All Examples are shown are on GitHub.


Wednesday, November 3, 2021

Java 8 Stream Sum - Adding Numbers With Java Streams

1. Overview

In this article, we'll learn how to add the numbers in java using java 8 streams summing and reduce() methods.

To make the examples simple, we are going to write code based in the integer values.

Java 8 Stream Sum - Adding Numbers With Java Streams


2. Sum using Java Stream.reduce()

First, Stream api has a reduce() method which takes the accumulator as an argument. reduce() method is a terminal operation which means reduce() method produces the result from stream and this should be called at the end of the stream.

reduce() method takes the two numbers such as number 1 and number 2. These two numbers are taken and applied the logic of addition what we write. 

Please refer the following example program.

package com.javaprogramto.java8.streams.sum;

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

public class IntegerSumExample1 {

	public static void main(String[] args) {

		List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
		
		int totalSum = numbers.stream().reduce(0, (number1, number2) -> number1 + number2);
		
		System.out.println("Sum of integers : "+totalSum);
	}
}
 

Output

Sum of integers : 55

 

Instead of passing "(number1, number2) -> number1 + number2)" logic to the reduce method, you can add this logic in the new method and call the new method as below. There will be no change in the output. In this way, we can reuse the add() method from many stream operations.

public class IntegerSumExample1 {

	public static void main(String[] args) {

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

		int totalSum = numbers.stream().reduce(0, ArithmeticUtils::add);

		System.out.println("Sum of integers : " + totalSum);
	}

}

class ArithmeticUtils {

	public static int add(int number1, int number2) {
		return number1 + number2;
	}
}
 

Additionally, you can use the builtin method Integer::sum from the reduce() method.

3. Using Collectors.summingInt()

Another way to add the list of integers is using the summingInt() of Collectors api.

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

int summingIntValue = numbers.stream().collect(Collectors.summingInt(Integer::intValue));

System.out.println("Sum of integers using summingInt : " + summingIntValue);

 

Output: 

Sum of integers using summingInt : 55
 

In the similar to the summingInt(), there are separate methods to deal with the addition of long and double such as summingDouble() and summingLong().

4. Using IntStream.sum()

Next, Using IntStream api sum() method, we can get the addition of numbers from the list or map.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int intStreamSum = numbers.stream().mapToInt(Integer::intValue).sum();
System.out.println("IntStream sum : "+intStreamSum);


Output:

IntStream sum : 55


5. Stream Sum with Map values

Let us see now to get the sum of value of Map object. First we need to get the values list or set from the map and then apply any one of the methods what we have learnt so far.

Map<Double, Integer> map = new HashMap<>();
map.put(1.0, 100);
map.put(2.0, 200);
map.put(3.0, 300);
map.put(4.0, 400);

int mapValuesSum = map.values().stream().reduce(0, Integer::sum);
System.out.println("Map values sum : "+mapValuesSum);

Output: 

Map values sum : 1000


6. Stream sum with custom objects

Next, create the set of objects then add them to the list. Further apply all of these ways on the list.

List<Employee> emps = Arrays.asList(new Employee(100, "A", 25), new Employee(200, "B", 35),
		new Employee(300, "C", 45));

int sum = emps.stream().map(emp -> emp.getAge())
			  .reduce(0, (a, b) -> a + b);

sum = emps.stream().map(emp -> emp.getAge())
		  .mapToInt(Integer::intValue)
		  .sum();

sum = emps.stream().map(emp -> emp.getAge())
		  .collect(Collectors.summingInt(Integer::intValue));


All above ways produces the same output as sum value 105.


7. Full code Stream Sum Example

All the examples are shown are put together in the single program.

package com.javaprogramto.java8.streams.sum;

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

import com.javaprogramto.models.Employee;

public class IntegerSumExample1 {

	public static void main(String[] args) {

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

		// reduce() example
		int totalSum = numbers.stream().reduce(0, ArithmeticUtils::add);
		System.out.println("Sum of integers : " + totalSum);

		// summingInt() example
		int summingIntValue = numbers.stream().collect(Collectors.summingInt(Integer::intValue));
		System.out.println("Sum of integers using summingInt : " + summingIntValue);

		// IntStream sum() example
		int intStreamSum = numbers.stream().mapToInt(Integer::intValue).sum();
		System.out.println("IntStream sum : " + intStreamSum);

		Map<Double, Integer> map = new HashMap<>();
		map.put(1.0, 100);
		map.put(2.0, 200);
		map.put(3.0, 300);
		map.put(4.0, 400);

		int mapValuesSum = map.values().stream().reduce(0, Integer::sum);
		System.out.println("Map values sum : " + mapValuesSum);

		List<Employee> emps = Arrays.asList(new Employee(100, "A", 25), new Employee(200, "B", 35),
				new Employee(300, "C", 45));
		
		int sum = emps.stream().map(emp -> emp.getAge())
					  .reduce(0, (a, b) -> a + b);

		sum = emps.stream().map(emp -> emp.getAge())
				  .mapToInt(Integer::intValue)
				  .sum();
		
		sum = emps.stream().map(emp -> emp.getAge())
				  .collect(Collectors.summingInt(Integer::intValue));
		
		System.out.println("custom objects sum : "+sum);
	}

}

class ArithmeticUtils {

	public static int add(int number1, int number2) {
		return number1 + number2;
	}
}


		

Output

Sum of integers : 55
Sum of integers using summingInt : 55
IntStream sum : 55
Map values sum : 1000
custom objects sum : 105

8. Conclusion

In this post, we've seen what are the different ways to do sum of numbers using java stream api with examples.

GitHub

Stream.reduce()

Collectors api

Friday, February 5, 2021

Java 8 Parallel Streams - Custom Thread Pools Examples

1. Introduction


In this tutorial, You'll learn how to create custom thread pools in Java 8 for bulk data processing with parallel streams powerful API.

Parallel Stream can work well in concurrent environments and these are improved versions of streams performance at the cost of multi-threading overhead.

The main focus in this article is to look at one of the biggest limitations of Stream API and Examples on how can you use the Parallel Streams with the custom thread pools.

Custom Thread Pools In Java 8 Parallel Streams

Thursday, December 10, 2020

Java 8 Stream - Convert List to Map

1. Overview

In this tutorial, We'll learn how to convert List to Map using java 8 stream methods.

Use Collectors.toMap() method which collect List into Map instance but we need to provide the values for key and value for output map object.

Once we see the example programs on how to pass key and value to the toMap() method.

Let us explore the different ways to do this.

Java 8 Stream - Convert List to Map


2. Collect List to Map using Collectors.toMap()


First create a list with string values and convert it into Stream using stream() method. Next, call stream.collect(Collectors.toMap()) method to convert list to map.

In the below example, key is the string and value is the length of string.

package com.javaprogramto.java8.arraylist.tomap;

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

public class ListToMapExample {

	public static void main(String[] args) {
		
		// creating a List
		List<String> list = Arrays.asList("one","two","three","four","five");
		
		// List to Stream
		Stream<String> stream = list.stream();
		
		// Stream to map - key is the string and value is its length
		Map<String, Integer> map = stream.collect(Collectors.toMap(String::new, String::length));
		
		// printing input list and map
		System.out.println("List : "+list);
		System.out.println("Map : "+map);
	}
}

Output:
List : [one, two, three, four, five]
Map : {four=4, one=3, two=3, three=5, five=4}


3. Collect List of Custom objects to Map using Collectors.toMap()


Now, let us see how to extract the values for key, value for Map from List.

Create a simple custom class named Book with constructor, setter, getters and toString() method.

package com.javaprogramto.java8.arraylist.tomap;

public class Book {

	private int id;
	private String author;
	private int yearRealeased;

	public Book(int id, String author, int yearRealeased) {
		this.id = id;
		this.author = author;
		this.yearRealeased = yearRealeased;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public int getYearRealeased() {
		return yearRealeased;
	}

	public void setYearRealeased(int yearRealeased) {
		this.yearRealeased = yearRealeased;
	}

	@Override
	public String toString() {
		return "Book [id=" + id + ", author=" + author + ", yearRealeased=" + yearRealeased + "]";
	}
}

Next, Create List of Books and convert it into Map.

Map1 with key is book id and value is book object
Map2 with key is yearReleased and value is book object
Map3 with key is name and value author name.

Use Function.idendity() method to get the current object from Stream.

package com.javaprogramto.java8.arraylist.tomap;

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

public class ListToMapCustomObjects {

	public static void main(String[] args) {
		List<Book> books = Arrays.asList(new Book(100, "book 1", 2017), new Book(101, "book 2", 2018),
				new Book(102, "book 3", 2019), new Book(103, "book 4", 2020));

		// map1 with key = id and value is book object
		Map<Integer, Book> map1 = books.stream().collect(Collectors.toMap(Book::getId, Function.identity()));

		// map2 with key = yearReleased and value is book object
		Map<Integer, Book> map2 = books.stream().collect(Collectors.toMap(Book::getYearRealeased, Function.identity()));

		// map3 with key = author name and value is year released
		Map<String, Integer> map3 = books.stream().collect(Collectors.toMap(Book::getAuthor, Book::getYearRealeased));

		// printing
		System.out.println("List of books --> " + books);
		System.out.println("Map1 --> " + map1);
		System.out.println("Map2 --> " + map2);
		System.out.println("Map3 --> " + map3);
	}
}

Output:
List of books --> [Book [id=100, author=book 1, yearRealeased=2017], Book [id=101, author=book 2, yearRealeased=2018], Book [id=102, author=book 3, yearRealeased=2019], Book [id=103, author=book 4, yearRealeased=2020]]
Map1 --> {100=Book [id=100, author=book 1, yearRealeased=2017], 101=Book [id=101, author=book 2, yearRealeased=2018], 102=Book [id=102, author=book 3, yearRealeased=2019], 103=Book [id=103, author=book 4, yearRealeased=2020]}
Map2 --> {2017=Book [id=100, author=book 1, yearRealeased=2017], 2018=Book [id=101, author=book 2, yearRealeased=2018], 2019=Book [id=102, author=book 3, yearRealeased=2019], 2020=Book [id=103, author=book 4, yearRealeased=2020]}
Map3 --> {book 2=2018, book 1=2017, book 4=2020, book 3=2019}


4. List to Map with Duplicate key


In the above section, we have added the unique values to the key in map. So, we are seeing the output as expected. 

But, What happens if we are adding the key that have duplicate values.

List<String> list = Arrays.asList("one","two","three","four","five", "five");

Now added "five" value twice in the section 2 program. So, run and see the output now.

It has thrown the runtime error " Duplicate key five (attempted merging values 4 and 4)" but this is not expected. We want to merge or replace with the new value for duplicate key.

Error is clearly saying problem with key value "five".

Exception in thread "main" java.lang.IllegalStateException: Duplicate key five (attempted merging values 4 and 4)
	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.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	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.javaprogramto.java8.arraylist.tomap.DuplicatesListToMapExample.main(DuplicatesListToMapExample.java:20)

To solve this duplicate issue, need to use overloaded toMap() with three parameters.

parameter 1 --> for key
parameter 2 --> for value
parameter 3 --> if the key is duplicate what should be the new value

Look at the below modified code in case of duplicates we are adding 1000 to the new value.
Map<String, Integer> map = stream
				.collect(Collectors.toMap(String::new, String::length, (oldValue, newValue) -> newValue + 1000));

Look at the output.

Map : {four=4, one=3, five=1004, three=5, two=3}

We can see in the output that duplicate key five is added with 1000 value.

The same logic, we can apply to the custom objects.

public class DuplicateListToMapCustomObjects {

	public static void main(String[] args) {
		List<Book> books = Arrays.asList(new Book(100, "book 1", 2017), new Book(101, "book 2", 2018),
				new Book(102, "book 3", 2019), new Book(103, "book 4", 2020), new Book(103, "book 3", 2021),
				new Book(102, "book 4", 2019));

		// map1 with key = id and value is book object
		Map<Integer, Book> map1 = books.stream()
				.collect(Collectors.toMap(Book::getId, Function.identity(), (oldValue, newValue) -> newValue));

		// map2 with key = yearReleased and value is book object
		Map<Integer, Book> map2 = books.stream().collect(
				Collectors.toMap(Book::getYearRealeased, Function.identity(), (oldValue, newValue) -> newValue));

		// map3 with key = author name and value is year released
		Map<String, Integer> map3 = books.stream()
				.collect(Collectors.toMap(Book::getAuthor, Book::getYearRealeased, (oldValue, newValue) -> newValue));

		// printing
		System.out.println("List of books --> " + books);
		System.out.println("Map1 --> " + map1);
		System.out.println("Map2 --> " + map2);
		System.out.println("Map3 --> " + map3);
	}
}

Output:
List of books --> [Book [id=100, author=book 1, yearRealeased=2017], Book [id=101, author=book 2, yearRealeased=2018], Book [id=102, author=book 3, yearRealeased=2019], Book [id=103, author=book 4, yearRealeased=2020], Book [id=103, author=book 3, yearRealeased=2021], Book [id=102, author=book 4, yearRealeased=2019]]
Map1 --> {100=Book [id=100, author=book 1, yearRealeased=2017], 101=Book [id=101, author=book 2, yearRealeased=2018], 102=Book [id=102, author=book 4, yearRealeased=2019], 103=Book [id=103, author=book 3, yearRealeased=2021]}
Map2 --> {2017=Book [id=100, author=book 1, yearRealeased=2017], 2018=Book [id=101, author=book 2, yearRealeased=2018], 2019=Book [id=102, author=book 4, yearRealeased=2019], 2020=Book [id=103, author=book 4, yearRealeased=2020], 2021=Book [id=103, author=book 3, yearRealeased=2021]}
Map3 --> {book 2=2018, book 1=2017, book 4=2019, book 3=2021}

5. Conclusion


In this article, We've seen how to collect the List to Map using java 8 Streams method Collectors.toMap() method.

And alos seen how to handle the duplicate keys with toMap() method and its solution.

More over, we can use filter(), map() and sort() method on the stream and finally we can collect the stream into Map.




Java 8 - How To Convert Any Stream to List in Java? toList()?

1. Overview

In this tutorial, We'll learn how to convert any type of Stream to List in java 8

Use Collectors.toList() method to convert the lambda Stream Collect to List or ArrayList. When you call toList() method, it creates an ArrayList object and returns to the caller.

But, if you want to get the List as LinkedList then need to use Collectors.toCollection() method.

Let us see the example programs using these two methods for better understanding.

Java 8 - How To Convert Stream to List in Java? Collectors.toList()


2. Java 8 - Convert Stream to List


Below example program to convert a stream to list using Collectors.toList() method with the help of collect() method.

package com.javaprogramto.java8.collectors.streamtolist;

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

/**
 * Example Stream to List
 * 
 * @author javaprogramto.com
 *
 */
public class StreamToListExample {

	public static void main(String[] args) {
		// creating an list
		List<String> names = Arrays.asList("Nick", "Boran", "Tison", "Sunshine");

		// converting list to stream
		Stream<String> stream = names.stream();

		// finally collecting the stream values into a list with any filtering the
		// objects.
		List<String> finalList = stream.collect(Collectors.toList());

		// printing
		System.out.println("List values : " + finalList);
	}
}

Output:

List values : [Nick, Boran, Tison, Sunshine]

3. Java 8 - Numbers Stream to List With filter() - Stream.of()


In this approach, first we will create the Stream of integers as Stream<Integer> using Stream.of() method and pass the numbers to of() method. We can pass any number of int values comma separated to this method. Because this method takes the input var-args.

package com.javaprogramto.java8.collectors.streamtolist;

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

/**
 * Example on numbers Stream to List
 * 
 * @author javaprogramto.com
 *
 */
public class NumbersStreamToListExample {

	public static void main(String[] args) {

		// Creating a stream using of() method.
		Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

		// Filtering the stream values to get only even numbers and next collect into ArrayList.
		List<Integer> finalList = stream.filter(e -> e % 2 == 0).collect(Collectors.toList());

		// printing
		System.out.println("Final ArrayList values : " + finalList);
	}
}

Output:
Final ArrayList values : [2, 4]

In the above program, after adding the first 5 integers to stream and adding filter() to get only the even numbers. Finally, Invoked the collect(Collectors.toList()) method which returns ArrayList instance default and stored the values into the List<Integer> variable.

4. Java 8 Stream to List as LinkedList


In the above sections, we've used Collectors.toList() method to get ArrayList object from stream values. But, if we want to get it as LinkedList then use another Collectors method toCollection() method which takes the LinkedList object as LinkedList::new.

LinkedList::new will create a new LinkedList object using Method Reference concept.

package com.javaprogramto.java8.collectors.streamtolist;

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

/**
 * Example Stream to LinkedList
 * 
 * @author javaprogramto.com
 *
 */
public class StreamToLinkedListExample {

	public static void main(String[] args) {
		// creating an list
		List<String> values = Arrays.asList("1", "2", "3", "4", "5");

		// converting list to stream
		Stream<String> stream = values.stream();

		// Collecting the stream values into a LinkedList using stream collectors.
		LinkedList<String> linkedList = stream.collect(Collectors.toCollection(LinkedList::new));

		// printing
		System.out.println("LinkedList values : " + linkedList);
	}
}

Output:
LinkedList values : [1, 2, 3, 4, 5]

5. Java 8 - Convert Infinite Stream to List


Java 8 api allows to create infinite streams of number using IntStream.iterate() method.

Let us now convert Infinite stream into List with limiting the number values from unlimited stream using limit() method.

Look at the below example.

limit(): taking first 10 values from infinite stream
boxed(): convert primitive to Wrapper integer object.
toList(): collecting stream values into List.

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

/**
 * Example on Infinite Stream to List
 * 
 * @author javaprogramto.com
 *
 */
public class StreamToListExample {

	public static void main(String[] args) {

		// Creating the infinite even numbers stream using iterate() starts from value
		// 10.
		IntStream infiniteStream = IntStream.iterate(10, i -> i + 2);

		// limit() + boxed() + toList() example
		List<Integer> finalList = infiniteStream.limit(10).boxed().collect(Collectors.toList());

		// printing
		System.out.println("List values : " + finalList);
	}
}

Output:
List values : [10, 12, 14, 16, 18, 20, 22, 24, 26, 28]

6. Conclusion


In this article, we've seen how to convert stream to list in java 8. Use Collectors.toList() to get the output in ArrayList object and Collectors.toCollection() method to get the output for other collections as LinkedList.



Wednesday, December 9, 2020

Java 8 Stream foreach Collect - Can not be done?

1. Overview

In this tutorial, We'll see whether can we use the forEach() method in the middle of stream operations such as stream().foreach().collect().

Another one can not we use the stream().forEach() and stream.collect() in one stream?

This is a common doubt for beginners when they start writing the programs in java 8 stream concepts.

First understand that forEach() and collect() methods are the terminal operations. That means theses are designed to produce the output of the stream and next end the stream. And also these two do not produce the stream result. So, we can not call further any stream methods.

We must be clear on Lambda Rules for usage.

But, we are trying to do with the calling forEach() in the middle of stream methods.

Let us see the simple examples.

Java 8 Stream foreach Collect - Can not be done?


2. Java 8 Stream forEach collect Example


Take a list with strings and try to do some filtering and then call forEach(). Finally, call collect method to store the final strings into a ArrayList.

package com.javaprogramto.java8.foreach;

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

public class Java8StreamForEachCollect {

	public static void main(String[] args) {

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

		list.add("hello");
		list.add("world");
		list.add("welcome");
		list.add("to");
		list.add("javaprogramto.com");

		list.stream().filter(value -> value.contains("c")).forEach(value -> value + "-").collect();
	}
}

Now compile this code and see the error.

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	The method forEach(Consumer<? super String>) in the type Stream<String> is not applicable for the arguments ((<no type> value) -> {})
	Void methods cannot return a value

	at com.javaprogramto.java8.foreach.Java8StreamForEachCollect.main(Java8StreamForEachCollect.java:18)

It is saying forEach() method does not return any value but you are returning string value with "-" and on forEach() method calling collect() method.

Error: Void methods cannot return a value

3. Solve - Stream forEach collect


Actually, If we can see in the forEach method we are trying to do the change the value of string. So, we need to use another method map() rather than forEach() which will do modifying the values and returns a stream of new string values. And further we can collect the result into List and use forEach() method.

And also instead of collecting into list, on map() result we can call forEach() method directly.
package com.javaprogramto.java8.foreach;

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

public class Java8StreamForEachCollect {

	public static void main(String[] args) {

		// creating a list
		List<String> list = new ArrayList<>();

		// adding values to list
		list.add("hello");
		list.add("world");
		list.add("welcome");
		list.add("to");
		list.add("javaprogramto.com");

		// list.stream().filter(value -> value.contains("c")).forEach(value -> value +
		// "-").collect();

		// stream filter() + map() + collect() example
		List<String> newList = list.stream().filter(value -> value.contains("c"))
									.map(value -> value + "-")
									.collect(Collectors.toList());
		
		//printing the list
		System.out.println("Original List : "+list);
		System.out.println("New List Values : ");
		
		// print using forEach on list.
		newList.forEach(value -> System.out.println(value));
		
		// iterating stream using forEach()
		System.out.println("\niterating stream using forEach()");
		list.stream().filter(value -> value.contains("c"))
				.map(value -> value + "-")
				.forEach(str -> System.out.println(str));
	}
}

Output:
Original List : [hello, world, welcome, to, javaprogramto.com]
New List Values : 
welcome-
javaprogramto.com-

iterating stream using forEach()
welcome-
javaprogramto.com-

4. Conclusion


In this article, We've seen how to use the forEach() and collect() methods effectively in java 8 streams.


Saturday, November 21, 2020

Java 8 Stream findFirst() vs findAny() With Examples

1. Overview

In this article, you'll learn what are the differences between findFirst() and findAny() in java 8 Streams.

These methods are quite makes confusion to the some developers.

Let us understand findFirst() vs findAny() first and learn when to use right one.

Read more on :


findAny() and findFirst() are stream terminal operations that means produces the final result.

If any one the stream values is null then it will NullPointerException.
List<String> values = Arrays.asList("A", "B", null, "F", "D");
Optional<String> anyValue = values.stream().findFirst();
Output:
Exception in thread "main" java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:221)
	at java.base/java.util.Optional.<init>(Optional.java:107)
	at java.base/java.util.Optional.of(Optional.java:120)
	at java.base/java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:194)
	at java.base/java.util.stream.FindOps$FindSink$OfRef.get(FindOps.java:191)
	at java.base/java.util.stream.FindOps$FindTask.doLeaf(FindOps.java:319)
	at java.base/java.util.stream.AbstractShortCircuitTask.compute(AbstractShortCircuitTask.java:115)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
	at java.base/java.util.stream.FindOps$FindOp.evaluateParallel(FindOps.java:160)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.findAny(ReferencePipeline.java:548)
	at com.javaprogramto.java8.streams.find.FindAnyParallelStreamIntegersExample.main(FindAnyParallelStreamIntegersExample.java:15)

2. Understand Usage of Stream.findAny()


By seeing the name of the method, you can assume that it is going to return any value from stream. Yes, you are correct till this point.

But, if you are not worried about the order how the values are appearing in the list or stream.

Syntax:
Optional<T> findAny()

This method returns Optional instance with the value found and returns empty Optional if the stream is empty.
package com.javaprogramto.java8.streams.find;

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

public class FindAnyExample {

	public static void main(String[] args) {

		// creating a list with string values
		List<String> values = Arrays.asList("A", "B", "C", "F", "D");

		// getting the any value from stream.
		Optional<String> anyValue = values.stream().findAny();

		// printing the value
		if (anyValue.isPresent()) {
			System.out.println("Any value from stream : " + anyValue.get());
		} else {
			System.out.println("No value presnt in the stream.");
		}
	}
}

Output:
Any value from stream : A
It has obtained the first value from the stream that is value "A". So, it gets the first value from stream.

Now, the tricky part is if the stream is parallel then it will not return the first value but not guaranteed.

For the same list, called findAny() method on parallel stream.
Optional<String> anyValue = values.stream().parallel().findAny();
Now let us see the output. Look at the below output.
Any value from stream : C
So, the value is changed in case stream is parallel and value cannot be predicted.

Next, let us have a look at another example on parallel stream.
package com.javaprogramto.java8.streams.find;

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

public class FindAnyParallelStreamIntegersExample {

	public static void main(String[] args) {

		// creating a list with integer prime values
		List<Integer> values = Arrays.asList(2, 3, 5, 7, 11);

		// Creating prallel stream.
		Optional<Integer> anyValue = values.stream().parallel().findAny();

		// printing the value
		if (anyValue.isPresent()) {
			System.out.println("Value from integer stream : " + anyValue.get());
		} else {
			System.out.println("No value presnt in the stream.");
		}
	}
}
Output:
Value from integer stream : 5

3. Understand Usage of Stream.findFirst()


As this method name describes, findFirst() method returns the first value from stream for any type of stream it may be sequential or parallel.

This method also returns Optional object with the first value. If the stream is empty then empty Optional is returned.

Let see the examples with sequential and parallel streams.

Sequential Stream:
package com.javaprogramto.java8.streams.find;

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

public class FindFirstSequentialExample {

	public static void main(String[] args) {

		// creating a list with string values
		List<String> values = Arrays.asList("A", "B", "C", "F", "D");

		// Getting the first value from sequential stream using findFirst() method
		Optional<String> anyValue = values.stream().findFirst();

		// printing the value
		if (anyValue.isPresent()) {
			System.out.println("First value from stream : " + anyValue.get());
		} else {
			System.out.println("No value presnt in the stream.");
		}
	}
}
Output:
First value from stream : A

Parallel Stream:
package com.javaprogramto.java8.streams.find;

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

public class FindFirstParallelExample {

	public static void main(String[] args) {

		// creating a list with string values
		List<String> values = Arrays.asList("A", "B", "C", "F", "D");

		// Getting the first value from sequential stream using findFirst() method
		Optional<String> anyValue = values.stream().parallel().findFirst();

		// printing the value
		if (anyValue.isPresent()) {
			System.out.println("First value from parallel stream : " + anyValue.get());
		} else {
			System.out.println("No value presnt in the stream.");
		}
	}
}
Output:
First value from parallel stream : A

From the above two sequential and parallel streams outputs, findFirst() method returns always the same output.

4. Conclusion


In this tutorial, you've seen the all the differences between the findFirst() and findAny() method in java 8.
 
Main similarity is findFirst() and findAny() method returns the first value from the stream if it is sequential. By default, stream is created with sequential pattern. And always both methods returns the same value. if the any value in the stream is null then it will throw NullPointerException.

But, if you working with parallel streams and your intention is to get the first value from stream then use only findFirst() method. But findAny() method works differently with parallel streams and may get any value from stream (mostly first one but not guaranteed).Because, among the parallel threads, which ever thread is started first and what ever the element is picked from the stream is considered as first value.

GitHub


Read Next

Java 8 Stream - Distinct By Property Example

1. Overview

In this tutorial, you'll learn How to get the distinct values from collection using java 8 stream api distinct() method.

Read more on 

Java 8 Stream API

In other words, how to remove the duplicates from list or collection using java 8 streams. This is a common tasks to avoid duplicates in the list. After java 8 roll out, it has become simple filtering using functional programming language.

Java 8 stream api is added with a unique distinct() method to remove the duplicate objects from stream.

distinct() is an intermediate operation that means it returns Stream<T> as output.

Next, let us jump into examples programs using Strings and Custom objects.

2. Java 8 distinct() example - Strings Values in List

First, create a simple list with duplicate string values. Now, we want to get only the unique values from it.

For this, we need to convert the list into stream using stream() method and next call distinct() method. Here, this distinct() method eliminates the duplicate string values.

Finally, invoke the Collectors.toList() method to take the distinct values into List.

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

public class DistinctStringExample {
	public static void main(String[] args) {
		// create a list with string values
		List<String> strings = new ArrayList<>();
		
		// adding values to list 
		strings.add("ABC");
		strings.add("XYZ");
		strings.add("ABC");
		strings.add("MNO");
		strings.add("ABC");
		strings.add("MNO");
		strings.add("PQR");
		
		// Getting the distinct values from stream using distinct() method
		List<String> uniqueStrings = strings.stream().distinct().collect(Collectors.toList());
		
		//printing the values
		System.out.println("Original list : "+strings);
		System.out.println("Unique values list : "+uniqueStrings);
	}
}

Output:

Original list : [ABC, XYZ, ABC, MNO, ABC, MNO, PQR]
Unique values list : [ABC, XYZ, MNO, PQR]

3. Java 8 distinct() example - By Custom Object Property

In the above program, we've seen with the simple strings. But in the real time, you will be adding the real objects such as Employee, Trade or Customer objects.

Let us create a Customer class with id, name and phone number.  Next, add 5 Customer objects to the List with duplicate id values.

Finally, use our custom logic will  get only the distinct by id field using Function Functional interface.

Customer.java

package com.javaprogramto.java8.streams.distinct;

public class Customer {

	private int id;
	private String name;
	private long phonenumber;
	
	public Customer(int id, String name, long phonenumber) {
		super();
		this.id = id;
		this.name = name;
		this.phonenumber = phonenumber;
	}

	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 long getPhonenumber() {
		return phonenumber;
	}

	public void setPhonenumber(long phonenumber) {
		this.phonenumber = phonenumber;
	}

	@Override
	public String toString() {
		return "Customer [id=" + id + ", name=" + name + ", phonenumber=" + phonenumber + "]";
	}
	
}

Distinct by Property Example:

package com.javaprogramto.java8.streams.distinct;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class DistinctByCustomPropertyExample {

	// predicate to filter the duplicates by the given key extractor.
	public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
		Map<Object, Boolean> uniqueMap = new ConcurrentHashMap<>();
		return t -> uniqueMap.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
	}

	public static void main(String[] args) {

		// creating customer objects with repeated id's 100, 101
		Customer customer1 = new Customer(100, "Jhon", 675000000l);
		Customer customer2 = new Customer(101, "Peter", 675000001l);
		Customer customer3 = new Customer(100, "Paul", 675000002l);
		Customer customer4 = new Customer(102, "Noel", 675000003l);
		Customer customer5 = new Customer(101, "Nup", 675000004l);

		// created a list to store the customer objects
		List<Customer> customers = new ArrayList<>();

		// adding customer objects
		customers.add(customer1);
		customers.add(customer2);
		customers.add(customer3);
		customers.add(customer4);
		customers.add(customer5);

		List<Customer> distinctElements = customers.stream().filter(distinctByKey(cust -> cust.getId()))
				.collect(Collectors.toList());

		System.out.println("customers size : " + customers.size());
		System.out.println("Distinct customers size : " + distinctElements.size());

	}

}

Output:

customers size : 5 Distinct customers size : 3

In the above program, the core is the distinctByKey() method which does the job removing the duplicates.

This is the advantage of core functional programming language.

4. Java 8 distinct toMap() example - Distinct values collecting into Map

In the above example, we have stored the output into List with Customer objects. But, we want to store it into map with id as key and customer object as value.

Use Collectors.toMap() method to remove the duplicates and collect into map.

package com.javaprogramto.java8.streams.distinct;

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

public class DistinctByMapExample {

	public static void main(String[] args) {

		// creating customer objects with repeated id's 100, 101
		Customer customer1 = new Customer(100, "Jhon", 675000000l);
		Customer customer2 = new Customer(101, "Peter", 675000001l);
		Customer customer3 = new Customer(100, "Paul", 675000002l);
		Customer customer4 = new Customer(102, "Noel", 675000003l);
		Customer customer5 = new Customer(101, "Nup", 675000004l);

		// created a list to store the customer objects
		List<Customer> customers = Arrays.asList(customer1, customer2, customer3, customer4, customer5);

		// removing the duplicates and collecting into map id as key, customer as value
		Map<Integer, Customer> mapIdCustomer = customers.stream()
				.collect(Collectors.toMap(Customer::getId, c -> c, (c1, c2) -> c1));

		// printing the map
		System.out.println("Final map after eliminating the duplicates - "+mapIdCustomer);

	}

}

Output:

Final map after eliminating the duplicates - 
{100=Customer [id=100, name=Jhon, phonenumber=675000000],
 101=Customer [id=101, name=Peter, phonenumber=675000001], 
 102=Customer [id=102, name=Noel, phonenumber=675000003]}

5. Conclusion

In this short article, you've seen how to get the distinct values from collection and store them into List and Map.

GitHub

DistinctByCustomPropertyExample.java

DistinctByMapExample.java

DistinctStringExample.java

Ref

How to get the distinct value from Array?

Java 8 forEach Examples