流是什么
一个流Stream代表了多个元素的序列,支持不同的操作:计算、求和等。Stream为函数式编程而生。对Stream的修改不会改变其数据源,特点:
- 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
- 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
对stream的操作分为为两类,中间操作(intermediate operations)和结束操作(terminal operations),二者特点是: 中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream,仅此而已。 结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。
引用来自链接:https://www.imooc.com/article/24862
Stream的常见方法使用示例
创建流stream
常见的容器对象、IO对象以及数组均可以转换为Stream,我们以最常使用的列表list来展示Stream的用法。
创建空流Stream
Stream.empty()
of方法创建流
Stream.of(“A”, “B”, “C”)
使用构建器builder创建流
Stream.builder().add(new String[]{“A”, “B”, “B”, “C”}).build()
使用生成器创建流
Stream.generate(Math::random)
使用迭代器创建流
Stream.iterate(1, item -> item 1)
list的stream()创建流
List widgets = Arrays.asList(colors); widgets.stream()
filter方法
filter方法接受一个预处理对象Predicate<T>,过滤出符合Predicate的元素流。 筛选找出数组中为 “B”的元素:使用filter过滤出【ele -> ele.equals(“B”)】的元素,作为新流,然后遍历forEach输出。
String[] arr = {“A”, “B”, “C”, “D”}; Arrays.asList(arr).stream().filter(ele -> ele.equals(“B”)).forEach(System.out::println);
示例全代码单元测试示例
代码语言:javascript复制package org.byron4j.eight;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.byron4j.eight.base.BaseLoggerService;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
/**
* java 8 Stream 常用方法示例
* 集合均可以转换为stream来使用
* @author BYRON.Y.Y
*
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class StreamTestCase extends BaseLoggerService{
static class Color{
String name;
int weight;
int color;
public Color(String name, int weight, int color) {
super();
this.name = name;
this.weight = weight;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
@Override
public String toString() {
return "Color [name=" name ", weight=" weight ", color=" color "]";
}
}
@Test
public void test_001filter过滤测试() {
String[] arr = {"A", "B", "C", "D"};
Arrays.asList(arr).stream().filter(ele -> ele.equals("B")).forEach(System.out::println);;
}
@Test
public void test_002map方法测试() {
//数组
Color[] colors = {new Color("RED", 1, 100), new Color("GREEN", 2, 200), new Color("BLUE", 3, 100), new Color("ORANGE", 4, 300)};
//数组转换为列表
List<Color> widgets = Arrays.asList(colors);
int sum = widgets.stream() //流
.filter(b -> b.getColor() == 100) //条件过滤
.mapToInt(b -> b.getWeight()) //收集行为
.sum(); //求和
System.out.println("sum=" sum);
//将列表中的元素的某个属性汇聚成列表(泛型接受该属性的类型)
List<Integer> collectColors = widgets.stream().sorted(Comparator.comparing(Color::getColor).reversed()).map(Color::getColor).collect(Collectors.toList());
System.out.println("属性汇聚成列表=" collectColors);
}
@Test
public void test_003flatMap方法测试() {
Color[] colors = {new Color("RED", 1, 100), new Color("GREEN", 2, 200), new Color("BLUE", 3, 100), new Color("ORANGE", 4, 300)};
//数组转换为列表
List<Color> widgets = Arrays.asList(colors);
//flatMap 可以同时获取每个遍历到的元素的多个属性
//将给定的函数ele.getName(), ele.getColor() 获取到的结果 来替换该流的每个元素
System.out.println(widgets.stream().flatMap(ele -> Stream.of(ele.getName(), ele.getColor())).collect(Collectors.toList()));
//将ele.getName()函数应用到该流的每个元素
widgets.stream().map(ele -> Stream.of(ele.getName())).collect(Collectors.toList()).forEach(System.out::println);
widgets.stream().map(ele -> ele.getName()).collect(Collectors.toList()).forEach(System.out::println);
}
@Test
public void test_004distinct方法测试() {
System.out.println("distinct方法测试");
Integer[] nums = {2, 2, 3, 1, 1, 4, 5, 5, 6 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//去重顺序输出
numList.stream().distinct().sorted().forEach(System.out::println);
}
@Test
public void test_005sorted方法测试() {
System.out.println("sorted方法测试");
Integer[] nums = {2, 2, 3, 1, 1, 4, 5, 5, 6 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//顺序输出
numList.stream().sorted().forEach(System.out::println);
//也可以传入比较器
numList.stream().sorted((s1, s2) -> s1 - s2).forEach(System.out::println);
}
@Test
public void test_006peek方法测试() {
System.out.println("peek方法测试");
//多次peek操作可以多次获取当前迭代的元素
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " e)) //一次
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " e)) //两次
.collect(Collectors.toList());
}
@Test
public void test_007limit方法测试() {
System.out.println("limit方法测试");
Integer[] nums = {1, 2, 3, 4};
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//使用limit仅仅获取3个元素
numList.stream().limit(3).forEach(System.out::println);
}
@Test
public void test_008skip方法测试() {
System.out.println("skip方法测试");
Integer[] nums = {1, 2, 3, 4, 5 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//使用skip(n)设置步长跳过几个元素,从第 n 1 个元素开始
numList.stream().skip(2).forEach(System.out::println);
}
@Test
public void test_009forEachOrdered方法测试() {
System.out.println("forEachOrdered方法测试");
Integer[] nums = {356,35, 23, 45346 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//按顺序流处理
numList.stream().parallel().forEachOrdered( System.out::println);
//使用并行处理时,顺序是不可知的
numList.stream().parallel().forEach( System.out::println);
}
@Test
public void test_010toArray方法测试() {
System.out.println("toArray方法测试");
Integer[] nums = {356,35, 23, 45346 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
Object[] arr = numList.stream().toArray();
System.out.println(arr);
}
@Test
public void test_011toArray2方法测试() {
System.out.println("toArray2方法测试");
Integer[] nums = {356,35, 23, 45346 };
//数组转换为列表
List<Integer> numList = Arrays.asList(nums);
//指定类型
Integer[] arr = numList.stream().toArray(Integer[]::new);
System.out.println(arr);
}
/**<pre>
* reduce 应该是对流元素累计的做某种操作而使用
* T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
</pre>
*/
@Test
public void test_012reduce方法测试() {
System.out.println("reduce方法测试");
Color[] colors = {new Color("RED", 1, 100), new Color("GREEN", 2, 200), new Color("BLUE", 3, 100), new Color("ORANGE", 4, 300)};
//数组转换为列表
List<Color> widgets = Arrays.asList(colors);
//累计求和
int sum = widgets.stream().map(ele -> ele.getColor()).reduce(0 , (a, b) -> a b);
System.out.println("reduce方法测试 sum = " sum); //700
/*
* acc = 1, item =2; cc = 1 2 = 3;
* acc = 3, itm = 3, acc = 3 3 = 6;
* acc = 6, itm = 4, acc = 6 4 = 10; over
*/
Optional accResult = Stream.of(1, 2, 3, 4).reduce((acc, item) -> {
System.out.println("acc : " acc);
acc = item;
System.out.println("item: " item);
System.out.println("acc : " acc);
System.out.println("--------");
return acc;
});
}
/*
* There are many existing classes in the JDK whose signatures are well-suited for use with method references as arguments to collect().
* For example, the following will accumulate strings into an ArrayList: List<String> asList = stringStream.collect(ArrayList::new,
* ArrayList::add,
ArrayList::addAll);
The following will take a stream of strings and concatenates them into a single string:
String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
StringBuilder::append)
.toString();
*/
@Test
public void test_013collect3参数方法测试() {
System.out.println("collect3个参数方法测试:");
/*
* 第一个参数表示: 供应者 创建一个ArrayList
* 第二个参数表示: 聚集器 使用创建的ArrayList的add方法积聚流的元素
* 第三个参数表示: 连接器(结果的展示) 使用addAll方法
*/
Stream.of("A", "B", "C", "D", "E", "F").collect(ArrayList::new, ArrayList::add, ArrayList::addAll).forEach(System.out::println);
}
/**
* 获取最小的元素(返回对象是一个Optional)
*/
@Test
public void test_014min参数方法测试() {
System.out.println("min参数方法测试:");
System.out.println(Stream.of("A", "B", "C", "D", "E", "F").min( (s1, s2) -> s1.compareTo(s2)).get());
}
/**
* 获取流中最大的的元素
*/
@Test
public void test_015max参数方法测试() {
System.out.println("max参数方法测试:");
System.out.println(Stream.of("A", "B", "C", "D", "E", "F").max( (s1, s2) -> s1.compareTo(s2)).get());
}
/**
* 返回一个long类型的流中的元素个数
*/
@Test
public void test_016count参数方法测试() {
System.out.println("count参数方法测试:");
System.out.println(Stream.of("A", "B", "C", "D", "E", "F").count());
}
/**
* 匹配一个,找到一个就返回true
*/
@Test
public void test_017anyMatch参数方法测试() {
System.out.println("anyMatch参数方法测试:");
System.out.println(Stream.of("A", "B", "C", "D", "E", "F").anyMatch(ele -> ele.equalsIgnoreCase("C")));
}
/**
* 全部匹配才返回true
*/
@Test
public void test_018allMatch方法测试() {
System.out.println("allMatch参数方法测试:");
System.out.println(Stream.of("A", "A", "A").allMatch(ele -> ele.equalsIgnoreCase("A")));
}
/**
* 一个都匹配不到就返回true
*/
@Test
public void test_019noneMatch方法测试() {
System.out.println("noneMatch参数方法测试:");
System.out.println(Stream.of("A", "B", "C").noneMatch(ele -> ele.equalsIgnoreCase("F")));
}
/**
* 获取流的第一个元素
*/
@Test
public void test_020findFirst方法测试() {
System.out.println("findFirst方法测试:");
System.out.println(Stream.of("A", "B", "C").findFirst());
}
/**
* 匹配任意过一个
*/
@Test
public void test_021findAny方法测试() {
System.out.println("findAny方法测试:");
System.out.println(Stream.of("A", "B", "B", "C").filter(ele -> ele.equalsIgnoreCase("B")).findAny());
}
/**
* builder() 返回一个Stream的构建器对象
* builder.accept(Object obj) 接受obj作为流的元素
* builder.build() 创建一个流Stream对象
*/
@Test
public void test_022builder方法测试() {
System.out.println("builder方法测试:");
Stream.builder().add(new String[]{"A", "B", "B", "C"}).build().forEach(System.out::println);
}
/**
* 获取一个空流
*/
@Test
public void test_023empty方法测试() {
System.out.println("empty方法测试:");
Stream.empty().forEach(System.out::println);
}
/**
* 将第一个参数作为第一个元素,
* 第一个参数传入第二个函数参数,作为第二个函数参数的参数,结果作为第二个元素
* 以此类推;
* 与generate的区别是: iterate是递归方式
*/
@Test
public void test_024iterate方法测试() {
System.out.println("iterate方法测试:");
Stream.iterate(1, item -> item 1).limit(10).forEach(System.out::println);
}
/**
* 按给定的方式生成流--generate表示是一个生成器
*/
@Test
public void test_025generate方法测试() {
System.out.println("generate方法测试:");
Stream.generate(Math::random).limit(3).forEach(System.out::println);
}
/**
* concat: 连接多个流; 可以是不同的类型
*/
@Test
public void test_026concat方法测试() {
System.out.println("concat方法测试:");
Stream.concat(Stream.of(1.2, 3.4, 5.6), Stream.of(1, 2, 3)).forEach(ele -> System.out.println(ele));
}
}
运行输出结果:
代码语言:javascript复制==============================================
B
==============================================
==============================================
sum=4
属性汇聚成列表=[300, 200, 100, 100]
==============================================
==============================================
[RED, 100, GREEN, 200, BLUE, 100, ORANGE, 300]
java.util.stream.ReferencePipeline$Head@8807e25
java.util.stream.ReferencePipeline$Head@2a3046da
java.util.stream.ReferencePipeline$Head@2a098129
java.util.stream.ReferencePipeline$Head@198e2867
RED
GREEN
BLUE
ORANGE
==============================================
==============================================
distinct方法测试
1
2
3
4
5
6
==============================================
==============================================
sorted方法测试
1
1
2
2
3
4
5
5
6
1
1
2
2
3
4
5
5
6
==============================================
==============================================
peek方法测试
Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR
==============================================
==============================================
limit方法测试
1
2
3
==============================================
==============================================
skip方法测试
3
4
5
==============================================
==============================================
forEachOrdered方法测试
356
35
23
45346
23
356
45346
35
==============================================
==============================================
toArray方法测试
[Ljava.lang.Object;@768debd
==============================================
==============================================
toArray2方法测试
[Ljava.lang.Integer;@449b2d27
==============================================
==============================================
reduce方法测试
reduce方法测试 sum = 700
acc : 1
item: 2
acc : 3
--------
acc : 3
item: 3
acc : 6
--------
acc : 6
item: 4
acc : 10
--------
==============================================
==============================================
collect3个参数方法测试:
A
B
C
D
E
F
==============================================
==============================================
min参数方法测试:
A
==============================================
==============================================
max参数方法测试:
F
==============================================
==============================================
count参数方法测试:
6
==============================================
==============================================
anyMatch参数方法测试:
true
==============================================
==============================================
allMatch参数方法测试:
true
==============================================
==============================================
noneMatch参数方法测试:
true
==============================================
==============================================
findFirst方法测试:
Optional[A]
==============================================
==============================================
findAny方法测试:
Optional[B]
==============================================
==============================================
builder方法测试:
[Ljava.lang.String;@3ac42916
==============================================
==============================================
empty方法测试:
==============================================
==============================================
iterate方法测试:
1
2
3
4
5
6
7
8
9
10
==============================================
==============================================
generate方法测试:
0.12227481089209669
0.9837223020679042
0.825097455624136
==============================================
==============================================
concat方法测试:
1.2
3.4
5.6
1
2
3
==============================================