[Must-see for apprentice java engineer] How to use Stream API

Article summary


This article focuses on how to use the Stream API. Many source code examples and explanations are provided so that even those who are new to the Stream API can understand it. It also introduces applied usage such as Strategy pattern using Stream API.

Benefits of learning the Stream API


――Because the processing is done like words, readability is improved. --Clear input and output make it easier to write test code --Bugs are hard to hide because it does not cause state changes --Combining functions does not affect each other --Supports parallel processing

When can I use the Stream API?


It can be used in places where loop processing such as for statements is performed most often.

How to use Stream API


The basic flow is to create a Stream instance, perform as many processes as you want (intermediate operation), and finally bring it to the desired state (end point operation).

Let's compare ** if you did not use the Stream API ** and ** if you did use ** to imagine this process.

The code written below shows the source code that converts the character string stored in the List to uppercase and extracts and displays only the 4-character character string.

//Code written without using Stream API
List<String> list2 = Arrays.asList("hoge", "foo", "bar","hoga");
		List<String> stream2 = new ArrayList<String>();
		for(String s :list2){
			String sUpperCase = s.toUpperCase();
			if(sUpperCase.length() == 4){
				stream2.add(sUpperCase);
			}
		}
		for(int i = 0; i < stream2.size(); i++){
			System.out.println(stream2.get(i));
		}

/*
The result is as follows
HOGE
HOGA
*/
//When using Stream API
		List<String> list1 = Arrays.asList("hoge", "foo", "bar","hoga");
		List<String> stream1 = list1.stream()
								.map(String::toUpperCase)
								.filter(s -> s.length() == 4)
								.collect(Collectors.toList());
		stream1.forEach(System.out::println);

/*
The result is as follows
HOGE
HOGA
*/

Using the Stream API like this is better readability because you only have to write what you want to do declaratively. (There is an advantage because there is no other state change and unnecessary processing does not run due to processing delay)

Now that you have an image of how to use the Stream API, I will explain in detail how to use it.

I will explain the flow of Stream separately as follows. ** 1. Stream instance creation ** ** 2. Intermediate operation ** ** 3. End point operation **

1. Create Stream instance


There are many ways to create a Stream instance, but here are four that you might use most often.

Class / interface Method Overview
Collection stream() Stream instance generation from a class that inherits the Collection interface
Arrays stream (T[] array) Create a Stream instance from an array
Stream of(T… values) Create a Stream instance based on the direct value
Stream iterate(T seed, UnaryOperator f) Create an ordered infinite Stream instance

How to write source code

// Collection#stream()
List<String> list = Arrays.asList("hoge", "foo", "bar");
Stream<String> stream = list.stream();

// Arrays#stream (T[] array)
String[] array = {"hoge", "foo", "bar"};
Stream<String> stream2 = Arrays.stream(array);

// Stream#of (T[] array)
Stream<String> stream3 = Stream.of("hoge", "foo", "bar");

// Stream#iterate (T seed, UnaryOperator f)
Stream<Integer> stream4 = Stream.iterate(2, x -> x * 2);

2. Intermediate operation


Intermediate operations are roughly divided into three processing methods.

--Narrow down the elements --Processing of elements --Sort elements

** 1. I think you understand how to create a Stream instance **, so I will narrow down the intermediate operations for the generated Stream instance.

Narrow down the elements

Since it is narrowed down, the number of inputs and outputs will change.

Method Overview
filter(Predicate<? super T> predicate) Stream that narrows down only the elements whose boolean judgment defined in Predicate is truereturn it
limit(long maxSize) Returns a Stream of elements from the beginning of the element to maxSize
skip(long maxSize) Returns a Stream that skips elements from the beginning of the element to maxSize
distinct() Compare elements with equals method and return Stream excluding duplicates

How to write source code

List<String> list = Arrays.asList("hoge", "foo", "bar","hoga","hoga");
//I used filter to extract only a 4-character string
System.out.println("****↓ filter****");
list.stream()
	.filter(s -> s.length() == 4)
	.forEach(System.out::println);

/*
Output result
hoge
hoga
hoga
*/

List<String> list = Arrays.asList("hoge", "foo", "bar","hoga","hoga");
//Extracted up to 3 strings from the first character using limit
list.stream()
	.limit(3)
	.forEach(System.out::println);

/*
Output result
hoge
foo
bar
*/
List<String> list = Arrays.asList("hoge", "foo", "bar","hoga","hoga");
//I used skip to skip the element string from the first character
list.stream()
	.skip(1)
	.limit(2)
	.forEach(System.out::println);

/*
Output result
foo
bar
*/

List<String> list = Arrays.asList("hoge", "foo", "bar","hoga","hoga");
//Removed duplicate strings using distinct
list.stream()
	.distinct()
	.forEach(System.out::println);

/*
Output result
hoge
foo
bar
hoga
*/
Processing of elements

The number of inputs and outputs does not change because it is only processed. For example, you can change from lowercase to uppercase, or from a string to the number of characters in a string.

Method Overview
map(Function<? super T, ? extends R> function) Return R from T received by function as an argument, and Stream generated with that R as an elementreturn it

How to write source code

List<String> list = Arrays.asList("hoge", "foo", "bar","hoga");
list.stream()
	.map(String::length)
	.forEach(System.out::println);

/*
Output result
4
3
3
4
*/


Sorting elements
Method Overview
sorted(Comparator<? super T> comparator) Stream compared and sorted by Comparatorreturn it

How to write source code

List<Person> people = Arrays.asList(
		new Person("Suzuki",24),
		new Person("Yamada",53),
		new Person("Henri Fortin",9),
		new Person("Yokouchi",39));

//When sorted by age
people.stream()
		.sorted(comparing(Person::getAge))
		.forEach(s -> System.out.println(s.toString()));
/*
Output result
Henri Fortin:9
Suzuki:24
Yokouchi:39
Yamada:53
*/


//Sort by name.reversed()When using in descending order
people.stream()
		.sorted(comparing(Person::getName).reversed())
		.forEach(s -> System.out.println(s.toString()));
}

/*
Output result
Suzuki:24
Yokouchi:39
Yamada:53
Henri Fortin:9
*/
//Person class used above
public class Person {
	private String name;
	private int age;
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	public String toString(){
		return name + ":" + age;
	}
}

3. End point operation


The end point operation is the last operation that creates a Stream instance and finishes intermediate operations.

Method Return type Contents
forEach(Consumer<? super T> consumer) void Consumer receives each element of Stream as an argument and processes it. When used in parallel processing, the order is not guaranteed even if the original data is an aggregate such as List.
forEachOrdered(Consumer<? super T> consumer) void If each element of Stream guarantees the order, the consumer receives each element as an argument in order and processes it.
toArray() Object[] Returns the elements of Stream as an array of Objects
reduce(T unit, BinaryOperator acc) T reduction(Convolution).. Returns the result of combining elements with the cumulative function acc for the identity element unit.
collect(Supplier factory, BiConsumer acc, BiConsumer combiner) Result container Variable reduction. Variable container generated by factory(For example ArrayList)On the other hand, add an element with acc and combine each container with combiner.
min(Comparator<? super T> comparator) Optional Returns the smallest of the elements. Use the argument comparator to compare the size. Returns an empty Optional if there is no element
max(Comparator<? super T> comparator) Optional Returns the largest of the elements. Use the argument comparator to compare the size. Returns an empty Optional if there is no element
count() long Returns the number of elements that Stream has
anyMatch(Predicate<? super T> predicate) boolean If all the elements of Stream return True in the judgment of predicate, True is returned as the return value.
allMatch(Predicate<? super T> predicate) boolean If all the elements of Stream return True in the judgment of predicate, True is returned as the return value.
noneMatch(Predicate<? super T> predicate) boolean If none of the Stream elements return True on the predicate check, return True as the return value.
findFirst() Optional Returns the first element of the elements. Returns an empty Optional if there is no element
findAny() Optional Returns one element of the elements. Returns an empty Optional if there is no element
sum() int / long /double Returns the sum of the elements that Stream has. The return value will be what the Stream represents. Returns 0 if there are no elements
average() OptionalDouble Returns the average value. If there is no element, Empty OptionalDouble is returned. If it is not divisible, it is rounded to a value that can be represented by a double value.

How to write source code Since the amount is large this time, I wrote an example by extracting about 3 appropriately. There is an optional return value, which will be explained later.


List<Person> people = Arrays.asList(
		new Person("Suzuki",24),
		new Person("Yamada",53),
		new Person("Henri Fortin",9),
		new Person("Yokouchi",39));

//Sort by age and store in List
List<Person> sortedPeople = people.stream()
								.sorted(comparing(Person::getAge))
								.collect(Collectors.toList());
System.out.println(sortedPeople);
/*
Output result
[Henri Fortin:9,Suzuki:24,Yokouchi:39,Yamada:53]
 */
//Sort by age in descending order and get the first Person
Optional<Person> firstPerson = people.stream()
								.sorted(comparing(Person::getAge).reversed())
								.findFirst();
System.out.println(firstPerson);
/*
Output result
Optional[Yamada:53]
*/
//True if all Persons are 10 or older, false otherwise
boolean ss = people.stream()
					.allMatch(p -> p.getAge() > 10);
System.out.println(ss);
/*
Output result
false
*/

About Optional


What is Optional?

A container object that can be stored with or without non-null values. There is no need to perform nullpo processing such as if (xxx == null). Please read it as it is organized in an easy-to-understand document. https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html

How to use Optional

This is an example using the ifPresent (Consumer <? Super T> consumer) method. This program outputs the first value found when the last name has 3 or more characters.

//If Optional is not used
List<String> people = Arrays.asList("Yamada","Tanaka","Suzuki");
String firsPerson = null;
for(String s : people){
	if(s.length() == 3){
		firsPerson = s;
		break;
	}
}
//null check
if(firsPerson != null){
	System.out.println(firsPerson);
}
//Use Optional and execute only when the value exists
Optional<String> firstPerson = Stream.of("Yamada","Tanaka","Suzuki")
									.filter(s -> s.length() == 3)
									.findFirst();
firstPerson.ifPresent(System.out::println);

If the value exists, it calls the specified consumer with that value, otherwise it does nothing.

Predicate


What is Predicate?

Returns the boolean of the processing result. In addition, processing can be connected, so if there is processing that connects a large number of if statements, It can be used effectively.

How to use Predicate

Implement the process of receiving a T type value as an argument and returning a boolean value. The value of boolean is returned by giving the argument T to the test method.

Predicate<String> predicate = s -> s.length() == 5;
System.out.println(predicate.test("tarou"));

Function


What is Function?

Represents a function that takes a single argument and produces a result.

How to use Function

Implement the process of receiving a T-type argument and returning an R-type value. It can be executed by giving the argument T to the apply method.

Function<String,String> toUpper = s -> s.toUpperCase();
System.out.println(toUpper.apply("tarou"));

Consumer


What is Optional?

How to use Optional

It receives a T type value as an argument and implements processing without a return value. It can be executed by giving the argument T to the accept method.

Consumer<String> consumer = string -> System.out.println("Cunsumer : " + string);
consumer.accept("tarou");

Parallel processing


comming soon

Recursive processing by lazy evaluation


comming soon

Recommended Posts

[Must-see for apprentice java engineer] How to use Stream API
[For beginners] How to operate Stream API after Java 8
How to use Java API with lambda expression
[Java] How to operate List using Stream API
[Java] How to use Map
[Java] How to use Map
How to use java Optional
How to use java class
[Java] How to use Optional ②
[Java] How to use removeAll ()
[Java] How to use string.format
How to use Java Map
How to use Java variables
[Java] Introduction to Stream API
[Java] How to use Optional ①
How to use Truth (assertion library for Java / Android)
Summary of Java communication API (1) How to use Socket
Summary of Java communication API (3) How to use SocketChannel
Summary of Java communication API (2) How to use HttpUrlConnection
How to use Java HttpClient (Get)
How to use SAS tokens for Azure Event hubs (Java)
[java8] To understand the Stream API
[Introduction to Java] About Stream API
How to use Java HttpClient (Post)
[Java] How to use join method
[Processing × Java] How to use variables
[Java] How to use LinkedHashMap class
How to call and use API in Java (Spring Boot)
[JavaFX] [Java8] How to use GridPane
How to use class methods [Java]
[Java] How to use List [ArrayList]
How to use classes in Java?
Java 8 ~ Stream API ~ to start now
[Processing × Java] How to use arrays
How to use Java lambda expressions
[Java] How to use Math class
How to use Java enum type
Multilingual Locale in Java How to use Locale
How to use binding.pry for view files
[Java] How to use the File class
[Java] How to use the hasNext function
How to use submit method (Java Silver)
[Java] How to use the HashMap class
[Easy-to-understand explanation! ] How to use Java instance
[Java] How to use the toString () method
Studying how to use the constructor (java)
[Processing × Java] How to use the loop
How to use Java classes, definitions, import
[Ruby] How to use slice for beginners
[Easy-to-understand explanation! ] How to use Java polymorphism
[Java] [Maven3] Summary of how to use Maven3
[Processing × Java] How to use the class
How to use Java Scanner class (Note)
[Processing × Java] How to use the function
[Easy-to-understand explanation! ] How to use ArrayList [Java]
[Java] How to use the Calendar class
[Java] Learn how to use Optional correctly
[Easy-to-understand explanation! ] How to use Java overload
try-catch-finally exception handling How to use java
[Easy-to-understand explanation! ] How to use Java encapsulation
Java Stream API