Stream
Stream是一组用来处理数组、集合的API
JAVA8 费大力气引入函数式编程,原因:
- 多核友好(并行计算),JAVA函数式编程使得并行程序非常简单,就是需要调用一下
parallel()
方法。 - 代码简洁。函数式编程写出的代码简洁且意图明确,使用Stream接口让你从此告别for循环。
特性:
- 不是数据结构,没有内部存储
集合中进行了非常多操作,中间的迭代过程是不支持数据存储的。分为中间操作和执行操作,只有进行执行算子,整个流才会执行 - 不支持索引访问
- 延迟计算
- 支持并行
- 很容易生成数组或集合
- 支持过滤、查找、转换、汇总、聚合等操作
注:
- Stream分为:源source,中间操作,终止操作
- 流的源可以是一个数组、一个集合、一个生成器方法、一个I/O通道等待
- 一个流可以有0或多个中间操作,每个中间操作返回一个新的流,供下一个操作使用
- 一个流只有一个终止操作。Stream只有遇到终止操作,它的源才会开始执行遍历操作
Stream的创建
- 通过数组生成
- 通过集合生成
- 通过Stream.generate()
- 通过Stream.iterate()
- 其他API创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54public class StreamDemo {
// 通过数组生成
static void gen1() {
String[] strs = {"a","b","c","d"};
// 数组转换为一个Stream
Stream<String> strs1 = Stream.of(strs);
/**
* forEach参数是Consumer<? super T> action
* Consumer<T>代表一个输入的函数式接口
* System.out::println是一个实例方法引用
*/
strs1.forEach(System.out::println);
}
// 通过集合生成
static void gen2() {
List<String> list = Arrays.asList("1","2","3","4");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
}
//通过generate()
static void gen3() {
/**
* generate()返回无限顺序无序流,其中每个元素是由提供的Supplier,无限循环
* Supplier,代表一个输出
*/
Stream<Integer> generate = Stream.generate(() -> 0);
generate.limit(3).forEach(System.out::println); // 限制3次
}
// 使用iterator
static void gen4() {
/**
* iterate()参数是UnaryOperator<T> f,无限循环
* UnaryOperator<T> f,一个输入一个输出,类型相同
*/
Stream<Integer> iterate = Stream.iterate(1, x -> x + 1);
iterate.limit(3).forEach(System.out::println);
}
//其他方式
static void gen5() {
String str = "abcd";
IntStream stream = str.chars();
stream.forEach(System.out::println);
}
public static void main(String[] args) {
gen1();
gen2();
gen3();
gen4();
gen5();
}
}结果:
a b c d 1 2 3 4 0 0 0 1 2 3 97 98 99 100
Stream常用API
中间操作:如果返回值是Stream对象,意味着是中间操作
延迟操作可以省掉很多临时存储的空间
StreamDemo.java
public static void main(String[] args) {
//------中间操作:如果返回值是Stream对象,意味着是中间操作
// 取出偶数
Arrays.asList(1,2,3,4,5).stream()
.filter((x)->x % 2 == 0).forEach(System.out::println);
// 求出结果集中的所有偶数的和
long count = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream()
.filter(x -> x % 2 == 0).mapToInt(x->x).sum();
System.out.println(count);
// 求集合中最大值
List list = Arrays.asList(7,1,2,3,4,5,6);
Optional max = list.stream().max((a, b) -> a - b);
System.out.println(max.get());
// 求集合中最小值
System.out.println(list.stream().min((a,b)->a-b).get());
Optional<Integer> any = list.stream().filter(x -> x % 2 == 0).findAny();
System.out.println(any.get());
// 如果没有这个值会报错:no value present
Optional<Integer> first = list.stream().filter(x -> x % 2 == 0).findFirst();
System.out.println(first.get());
Stream<Integer> integerStream = list.stream().filter(i -> {
System.out.println("运行代码"); // 不会被打印 延迟执行 一直等于stream一直不执行
return i % 2 == 0;
});
System.out.println(integerStream);
System.out.println(integerStream.findAny().get());
System.out.println("---------------");
//获取最大值和最小值,但是不使用min和max方法
Optional<Integer> min = list.stream().sorted().findFirst();
System.out.println(min.get());
Optional<Integer> max2 = list.stream().sorted((a,b)->b-a).findFirst();
System.out.println(max2.get());
//按照自然序排序
Arrays.asList("java","c#","python","scala","jee").stream().sorted().forEach(System.out::println);
//按照长度排序
System.out.println("+++++++++++");
Arrays.asList("java","c#","python","scala","jee").stream().sorted((a,b)->a.length()-b.length()).forEach(System.out::println);
System.out.println("=============");
// 想将集合中的元素进行过滤同时返回一个集合对象
List<Integer> collect = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
collect.forEach(System.out::println);
// 去重操作
Arrays.asList(1,2,2,3,3,3,4,5,2).stream().distinct().forEach(System.out::print);
System.out.println();
Arrays.asList(1,2,2,3,3,3,4,5,2).stream().collect(Collectors.toSet()).forEach(System.out::print);
System.out.println();
// 打印20~30这样的集合数据
Stream.iterate(1,x->x+1).limit(50).skip(20).limit(10).forEach(System.out::print);
System.out.println();
// 字符串值求和
String str = "11,22,33,44,55";
System.out.println(Stream.of(str.split(",")).mapToInt(x -> Integer.valueOf(x)).sum());
System.out.println(Stream.of(str.split(",")).mapToInt(Integer::valueOf).sum());
System.out.println(Stream.of(str.split(",")).map(x -> Integer.valueOf(x)).mapToInt(x -> x).sum());
System.out.println(Stream.of(str.split(",")).map(Integer::valueOf).mapToInt(x -> x).sum());
// 创建一组自定义对象
String str2 = "java,scala,python";
Stream.of(str2.split(",")).map(x->new Person(x)).forEach(System.out::print);
System.out.println();
Stream.of(str2.split(",")).map(Person::new).forEach(System.out::print);
System.out.println();
Stream.of(str2.split(",")).map(x->Person.build(x)).forEach(System.out::print);
System.out.println();
Stream.of(str2.split(",")).map(Person::build).forEach(System.out::print);
// 将str中每个数值都打印出来同时算出最终的求和结果
// peek(IntConsumer action)返回由该流的元素组成的流,另外在从生成的流中消耗元素时对每个元素执行提供的操作
System.out.println(Stream.of(str.split(",")).peek(System.out::println).mapToInt(Integer::valueOf).sum());
// list:{7,1,2,3,4,5,6}
// allMatch(IntPredicate predicate)返回此流的所有元素是否与提供的谓词匹配
System.out.println(list.stream().allMatch(x -> x % 2 == 0));
System.out.println(list.stream().anyMatch(x -> x % 2 == 0)); // 任何一个true
}
Person.java
2
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public Person() {
}
public static Person build(String name) {
Person p = new Person();
p.setName(name);
return p;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
结果
2
4
20
7
1
2
2
java.util.stream.ReferencePipeline$2@312b1dae
运行代码
运行代码
运行代码
2
---------------
1
7
c#
java
jee
python
scala
+++++++++++
c#
jee
java
scala
python
=============
2
4
6
12345
12345
21222324252627282930
165
165
165
165
Person{name='java'}Person{name='scala'}Person{name='python'}
Person{name='java'}Person{name='scala'}Person{name='python'}
Person{name='java'}Person{name='scala'}Person{name='python'}
Person{name='java'}Person{name='scala'}Person{name='python'}
22
33
44
55
165
false
true