Try various Java Stream API methods (now)

Stream API added in Java 8. I researched and used the minimum as needed, but I didn't understand it well, so I re-examined and tried it.

What is Stream API in the first place?

"A class that supports functional operations on a stream of elements". https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/package-summary.html … The official documentation is hard to read, perhaps because it's automatic translation. You may understand if you read English ...

The "element" here seems to mainly refer to Collection elements such as List. Stream is exactly as it is written in this article. https://qiita.com/castaneai/items/3dbdd8543b020aa903cb

What is StreamAPI useful for?

My interpretation is

--Easy to operate on Collection elements --Because it can process in parallel, you can make use of multi-core CPU

Stream API overview

I felt that JavaDoc for the Stream interface would be the basis for everything, so I'll focus on it here. https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html

Process flow

  1. Create a Stream from one source (such as List)
  2. 0 to n intermediate operations
  3. One termination operation

スクリーンショット 2018-12-05 6.06.52.png

Point (excerpt from JavaDoc)

--Must be non-interfering (do not change the source of the stream) --In most cases, it should be stateless (the result should not depend on any state that may change during the execution of the stream pipeline).

It's an experiment for the time being!

Derived things such as methods that return IntStream are excluded.

Before that

I created one bean and one method for creating test data. I call it from the main method, create a variable called list, and then experiment.

Bean

Bean


public class TestBean {
	String key;
	String value;
	String description;
	public TestBean(String key, String value, String description) {
		this.setKey(key);
		this.setValue(value);
		this.setDescription(description);
	}
	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	@Override
	public String toString() {
		return "key:" + this.key + " value:" + this.value + " description:" + this.description;
	}
}
method

Test data creation method


	private static List<TestBean> editTestData() {
		List<TestBean> list = new ArrayList<>();
		list.add(new TestBean("B", "Butaman", "Contains pork"));
		list.add(new TestBean("A", "Anman", "Contains red bean paste"));
		list.add(new TestBean("C", "Chukaman", "It is a general term for Anmanbutaman etc."));
		return list;
	}

Intermediate operation

filter As the name implies, it filtered!

filter


list.stream()
.filter(x -> x.getValue().equals("Anman"))
.forEach(x -> System.out.println(x.getDescription()));

Execution result


Contains red bean paste

map I interpreted it as creating another Stream based on the Stream. In this example, a Stream composed of TestBean type is replaced with a Stream composed of String.

map


list.stream()
.map(x -> x.getKey() + x.getValue() + x.getDescription())
.forEach(x -> System.out.println(x));

Execution result


B Butaman pork is included
A Anman Anko is included
C Chukaman Anmanbutaman, etc.

flatMap It seems that you can create a Stream inside a Stream. An image like making a table with Stream? Here, each item of the bean that composes one row is separated to create another Stream.

flatMap


list.stream()
.flatMap(x -> Stream.of(Arrays.asList(x.getKey(),x.getValue(),x.getDescription())))
.forEach(x -> x.forEach(y -> System.out.println(y)));

Execution result


B
Butaman
Contains pork
A
Anman
Contains red bean paste
C
Chukaman
It is a general term for Anmanbutaman etc.

distinct Eliminate duplicate elements. In conducting this test, we inflated the above test data.

Test data

Test data (duplicate a)


	private static List<TestBean> editTestData() {
		List<TestBean> list = new ArrayList<>();
		TestBean a = new TestBean("A", "Anman", "Contains red bean paste");
		TestBean b = new TestBean("B", "Butaman", "Contains pork");
		TestBean c = new TestBean("C", "Chukaman", "It is a general term for Anmanbutaman etc.");
		list.add(b);
		list.add(a);
		list.add(a);
		list.add(a);
		list.add(c);
		return list;
	}
No distinct

Source


list.stream()
.forEach(x -> System.out.println(x.getDescription()));

Execution result


Contains pork
Contains red bean paste
Contains red bean paste
Contains red bean paste
It is a general term for Anmanbutaman etc.
with distinct

Source


list.stream()
.distinct()
.forEach(x -> System.out.println(x.getDescription()));

Execution result


Contains pork
Contains red bean paste
It is a general term for Anmanbutaman etc.

sorted Sort as the name implies. In this example, the items named key (ABC) are sorted in order.

sorted


list.stream()
.sorted((o1, o2) -> o1.getKey().compareTo(o2.getKey()))
.forEach(x -> System.out.println(x.getKey() + x.getValue() + x.getDescription()));

Execution result


A Anman Anko is included
B Butaman pork is included
C Chukaman Anmanbutaman, etc.

peek This does not specifically manipulate the contents of the stream, It looks like a method for debugging. peek = A glimpse (literally translated)

peek


list.stream()
.peek(x -> System.out.println(x))
.forEach(x -> System.out.println("Output with forEach"));

Execution result


key:B value:Butaman description:Contains pork
Output with forEach
key:A value:Anman description:Contains red bean paste
Output with forEach
key:C value:Chukaman description:It is a general term for Anmanbutaman etc.
Output with forEach

I was wondering if forEach would be done after all the peeks were done first, but it seems that intermediate processing → termination processing is done for each element.

limit Truncate the number of Streams to the specified number.

limit


list.stream()
.limit(2)
.forEach(x -> System.out.println(x));

Execution result


key:B value:Butaman description:Contains pork
key:A value:Anman description:Contains red bean paste

skip Contrary to limit, it skips the beginning of Stream.

skip


list.stream()
.skip(1)
.forEach(x -> System.out.println(x));

Execution result


key:A value:Anman description:Contains red bean paste
key:C value:Chukaman description:It is a general term for Anmanbutaman etc.

Termination operation

forEach I casually used it every time so far. Processes all elements of Stream. … But it seems that the order is not guaranteed. Only for parallel streams?

forEachOrdered It's the same as forEach, but it seems that the order is guaranteed by using this.

toArray Simply make the stream an array.

toArray


Object[] testBeans = list.stream().toArray();
System.out.println(testBeans[0].toString());
System.out.println(testBeans[1].toString());

Execution result


key:B value:Butaman description:Contains pork
key:A value:Anman description:Contains red bean paste

reduce reduce = reduce, reduce (literally) It seems to be useful when aggregating the contents of Stream. In this example, the item named value is attached. Only one Optional is returned from Stream. In addition, there is also reduce that can set the initial value. Signature difference.

reduce


Optional<TestBean> opt = list.stream()
.reduce((t, u) -> {
  t.setValue(t.getValue() + u.getValue());
  return t;
});
System.out.println(opt.orElse(new TestBean("x", "x", "x")));

Execution result


key:B value:Butaman Anman Chukaman description:Contains pork

collect It seems to be used when you want to return it as a Collection instead of a single element like Optional. Collection → Edit as Stream → Output as Collection I think I use it quite often.

If you want to seriously implement the various interfaces that are the arguments of collect by yourself, you have to write about 5 abstract methods, so it is easy to use the static method provided in the Collectors class.

collect


List<TestBean> newlist = list.stream()
  .filter(x -> x.getKey().equals("C"))
  .collect(Collectors.toList());
System.out.println(newlist.get(0).toString());

Execution result


key:C value:Chukaman description:It is a general term for Anmanbutaman etc.

min As the name implies, it returns the smallest one as Optional. What is the minimum is the same as for sort, and the Comparator is implemented and defined. In this example, specify the item called key.

min


Optional<TestBean> op = list.stream()
  .min((x, y) -> x.getKey().compareTo(y.getKey()));
System.out.println(op.orElse(new TestBean("x", "x", "x")).toString());

Execution result


key:A value:Anman description:Contains red bean paste

max The opposite of min!

max


Optional<TestBean> op = list.stream()
  .max((x, y) -> x.getKey().compareTo(y.getKey()));
System.out.println(op.orElse(new TestBean("x", "x", "x")).toString());

Execution result


key:C value:Chukaman description:It is a general term for Anmanbutaman etc.

count As the name implies, it returns the number of Stream elements.

count


System.out.println(list.stream().count());

Execution result


3

anyMatch As I read, it returns true if any of the conditions in Stream are met. In this example, we are looking for an item with the key "A".

anyMatch


boolean matched = list.stream().anyMatch(x -> x.getKey().equals("A"));
if (matched) {
  System.out.println("There was an anman!");
}

Execution result


There was an anman!

allMatch Until I read this as well, it returns true if all the elements in the Stream meet the specified conditions.

allMatch


boolean matched = list.stream().allMatch(x -> !x.getKey().equals("Z"));
if (matched) {
  System.out.println("Not everyone is Z!");
}

Execution result


Not everyone is Z!

noneMatch Returns true if there is no such thing in the Stream.

noneMatch


boolean noMatched = list.stream().noneMatch(x -> x.getKey().equals("Z"));
if (noMatched) {
  System.out.println("There was no Z warrior");
}

Execution result


There was no Z warrior

findFirst As the name implies, it returns the first one!

findFirst


Optional<TestBean> op = list.stream().findFirst();
System.out.println(op.orElse(new TestBean("x", "x", "x")).toString());

Execution result


key:B value:Butaman description:Contains pork

findAny It goes through its name and returns something. I'm talking about something ... I don't really know what will be returned. Arguments cannot be specified. When I tried it with a sequential stream, the first element was returned, but it seems that there is no guarantee. (2018/12/08 I received a comment and corrected it)

findAny


Optional<TestBean> op = list.stream().findAny();
System.out.println(op.orElse(new TestBean("x", "x", "x")).toString());

Execution result


key:B value:Butaman description:Contains pork

Experiments other than trying the method

Confirm that the original source has not changed even if you operate Stream

I overwrote the bean value item in Stream with a fixed string. Certainly the source (List) hasn't changed.

source

python


System.out.println("【Change before】");
for (TestBean bean : list) {
  System.out.println(bean);
}

list.stream().map(x -> {
  x.setValue("I changed it!");
  return x;
});

System.out.println("[After change]");
for (TestBean bean : list) {
  System.out.println(bean);
}
Execution result

Execution result


【Change before】
key:B value:Butaman description:Contains pork
key:A value:Anman description:Contains red bean paste
key:C value:Chukaman description:It is a general term for Anmanbutaman etc.
[After change]
key:B value:Butaman description:Contains pork
key:A value:Anman description:Contains red bean paste
key:C value:Chukaman description:It is a general term for Anmanbutaman etc.

Measure speed difference

Create a List of 150 million Store random numbers from 0 to 99 in it Create another List by extracting only the element that stores 99 I did a wasteful process and measured it.

As a result, there is no big difference between List and stream, paralellStream was obviously fast.

source

python


    final int loopsize = 150000000;
    final int randomrange = 100;
    final int findnum = 99;

    // create many data
    System.out.println("During test data generation...");
    List<Integer> list = IntStream.range(0, loopsize)
        .mapToObj(x -> new Random().nextInt(randomrange))
        .collect(Collectors.toList());

    // byList
    LocalDateTime starttime = start("--- byList ---");
    List<Integer> newlist = new ArrayList<>();
    for (Integer i : list) {
      if (i.intValue() == findnum) {
        newlist.add(i);
      }
    }
    end(starttime, findnum, newlist);

    // byStream
    starttime = start("--- byStream ---");
    List<Integer> streamlist = list.stream()
        .filter(x -> x.intValue() == findnum).collect(Collectors.toList());
    end(starttime, findnum, streamlist);

    // byParalellStream
    starttime = start("--- byParalellStream ---");
    List<Integer> paralellStreamlist = list.parallelStream()
        .filter(x -> x.intValue() == findnum).collect(Collectors.toList());
    end(starttime, findnum, paralellStreamlist);
  }

  private static LocalDateTime start(String msg) {
    System.out.println("");
    System.out.println(msg);
    LocalDateTime ldt = LocalDateTime.now();
    System.out.println("start: " + ldt);
    return ldt;
  }

  private static void end(LocalDateTime starttime, int findnum,
      List<Integer> newlist) {
    LocalDateTime elapsed = LocalDateTime.now();
    System.out.println("end  : " + elapsed);
    elapsed = elapsed.minusHours(starttime.getHour());
    elapsed = elapsed.minusMinutes(starttime.getMinute());
    elapsed = elapsed.minusSeconds(starttime.getSecond());
    elapsed = elapsed.minusNanos(starttime.getNano());
    System.out
        .println("elapsed: " + elapsed.format(DateTimeFormatter.ISO_TIME));
    System.out.println(findnum + "Is" + newlist.size() + "There were one!");
  }
Execution result

Execution result


During test data generation...

--- byList ---
start: 2018-12-08T15:35:51.584
end  : 2018-12-08T15:35:52.039
elapsed: 00:00:00.455
There were 1500072 99!

--- byStream ---
start: 2018-12-08T15:35:52.052
end  : 2018-12-08T15:35:52.450
elapsed: 00:00:00.398
There were 1500072 99!

--- byParalellStream ---
start: 2018-12-08T15:35:52.450
end  : 2018-12-08T15:35:52.672
elapsed: 00:00:00.222
There were 1500072 99!

Confirm that the order of forEach and findAny is not guaranteed

It was certainly not guaranteed with parallelStream. In sequential Stream, it was accessed in the order of the original source (List).

source

python


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

    System.out.println("--- byList ---");
    for (int i : list) {
      System.out.println(i);
    }

    System.out.println("--- byStream ---");
    list.stream().forEach(i -> System.out.println(i));

    System.out.println("--- byParallelStream ---");
    list.parallelStream().forEach(i -> System.out.println(i));

    System.out
        .println("findany by stream:" + list.stream().findAny().orElse(null));

    System.out.println("findany by parallelStream:"
        + list.parallelStream().findAny().orElse(null));
Execution result

Execution result


--- byList ---
1
2
3
4
5
6
7
8
9
10
--- byStream ---
1
2
3
4
5
6
7
8
9
10
--- byParallelStream ---
7
9
6
3
5
2
10
1
4
8
findany by stream:1
findany by parallelStream:7

Confused point

Arguments of each method of Stream interface

We are passing a functional interface (behavior) as an argument instead of data. This is called functional programming. I couldn't write it easily because I only wrote it in a procedural way.

I forget it soon and can't write it in one shot, so instead of using a lambda expression, I created an anonymous class with a new interface () {...}, implemented an abstract method, and replaced it with a lambda expression. .. I'm ashamed to say ... Well, you'll get used to it soon.

Articles that I used as a reference

Thank you to all the authors!

Stream API basics https://qiita.com/Takmiy/items/f1d44dfde0d3a906d321

Survey of Java 8 Function, Consumer, Supplier, Predicate https://qiita.com/subaru44k/items/c55d9b9fc419f0d09c64

What is functional programming, what is lambda? https://qiita.com/lrf141/items/98ffbeaee42d30cca4dc

Difference between Stream map and flatMap https://qiita.com/KevinFQ/items/97137efb2159009b60e1

Outside Qiita. It describes from the purpose of Stream API to the experimental results. http://d.hatena.ne.jp/nowokay/20130506

Recommended Posts

Try various Java Stream API methods (now)
Java 8 ~ Stream API ~ to start now
Try Java 8 Stream
Java Stream API
Try using the Stream API in Java
Java8 Stream API practice
Java Stream API cheat sheet
Java Stream API in 5 minutes
[Java] Stream API --Stream termination processing
[Java] Stream API --Stream intermediate processing
[Java] Introduction to Stream API
[Java] Stream API intermediate operation
[swift5] Try to make an API client with various methods
Various methods of Java String class
[java8] To understand the Stream API
[Introduction to Java] About Stream API
I tried using Java8 Stream API
Java methods
Java methods
Data processing using stream API from Java 8
Nowadays Java lambda expressions and Stream API
Try using JSON format API in Java
Java 8 to start now ~ Date time API ~
Stream API memo
[JAVA] Stream type
Try using GCP's Cloud Vision API in Java
Studying Java 8 (Stream)
Try using the COTOHA API parsing in Java
Roughly try Java 9
Java Stream termination
[Java] How to operate List using Stream API
[Java] Stream processing
Stream API basics
Java 9 Optional :: stream
Try calling synchronized methods from multiple threads in Java
[In-house study session] Java basics-Lambda expression and Stream API- (2017/07/13)
[For beginners] How to operate Stream API after Java 8
Use Java lambda expressions outside of the Stream API
[Java] Stream Collectors notes
Pack API response (java)
Try using java.lang.Math methods
[Java] Stream API-Stream generation
Stream API (Collectors class)
Stream API map method
Docker-Client Java API Troubleshooting
Various threads in java
Zabbix API in Java
Java8 Stream reduction operation
Review Java annotations now
Java random, various processing
Try Java return value
Java8 Stream Rough Summary
Handle exceptions coolly with Java 8 lambda expressions and Stream API
I want to use the Java 8 DateTime API slowly (now)
Now is the time to get started with the Stream API
Convert 2D array to csv format with Java 8 Stream API