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.
"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
My interpretation is
--Easy to operate on Collection elements --Because it can process in parallel, you can make use of multi-core CPU
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
--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).
Derived things such as methods that return IntStream are excluded.
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
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;
}
}
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;
}
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 (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;
}
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.
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.
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
I overwrote the bean value item in Stream with a fixed string. Certainly the source (List) hasn't changed.
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
【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.
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.
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
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!
It was certainly not guaranteed with parallelStream. In sequential Stream, it was accessed in the order of the original source (List).
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
--- 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
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.
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