java8Stream
stream
介绍
java8添加了一个抽象流stream,可以让我们像写sql一样操作集合元素。stream将要处理的元素看做是一种流, 在管道中传输,并进行处理,最后由终止操作得到处理的结果。
什么是stream?
stream是一个来自特定元素队列并支持聚合操作
- 元素是具体类型的对象,形成一个队列。
- 数据源是流的来源。
- 聚合操作是类似sql一样的操作,比如filter, map, reduce, find, match, sorted等。
- stream自己不会存储元素。
- stream不会改变源对象。
- stream操作是延迟执行的。
创建流
串行流
stream():即单线程的方式去操作流
并行流
parallelstream():即多线程方式去操作流
@test public void test() { //1通过collection提供的stream()和parallelstream()方法 list<string> list = arrays.aslist("a","b","c"); stream<string> stream1 = list.stream(); stream<string> stream2 = list.parallelstream(); //2通过arrays的静态方法stream() string[] strs= {"a","b","c"}; stream<string> stream3 = arrays.stream(strs); //3通过stream类中的静态方法of() stream<string> stream4 = stream.of("a","b","c"); //4通过stream类的iterate方法生成无限流 stream<integer> stream5 = stream.iterate(0, (x)->x+1); //5通过stream的generate方法生成无限流 stream.generate(()->math.random()); }
中间操作
过滤
使用 filter(predicate<? super t> predicate)来按照一定规则对流中元素进行过滤
@test public void test() { list<integer> list = arrays.aslist(1,2,3,4,5); stream<integer> stream = list.stream(); stream = stream.filter((x)->x.compareto(2)>0); stream.foreach(system.out::println); } 输出: 3 4 5 @test public void test2() { list<integer> list = arrays.aslist(1,2,3,4,5); stream<integer> stream = list.stream(); stream = stream.filter( (x)->{ system.out.println(x); return x.compareto(2)>0;} ); } 结果:没有任何输出,这也就是前面说的stream操作是延迟执行的,只有当终止操作这些中间操作才会依次执行
截断
使元素的个数不超过指定的数目
@test public void test() { list<integer> list = arrays.aslist(1,2,3,4,5); stream<integer> stream = list.stream(); stream=stream.limit(3); stream.foreach(system.out::println); } 输出: 1 2 3 可以看到只输出了给定个元素
跳过元素
跳过流中前几个元素
@test public void test4() { list<integer> list = arrays.aslist(1,2,3,4,5); stream<integer> stream = list.stream(); stream=stream.skip(2); stream.foreach(system.out::println); } 输出: 3 4 5 跳过了前两个元素
唯一筛选
两个元素通过hashcode()判断两个元素是否相同
@test public void test5() { list<integer> list = arrays.aslist(1,2,3,4,5,5); stream<integer> stream = list.stream(); stream.distinct().foreach(system.out::println); } 输出: 1 2 3 4 5
映射
map(method)接受一个方法,把流中的元素按照方法进行转换
@test public void test() { list<string> list = arrays.aslist("a","b","c"); stream<string> stream = list.stream(); stream=stream.map((x)->x.touppercase()); stream.foreach(system.out::println); } 输出: a b c
flatmap(method)也是接受一个函数作为参数,但是与map,不同的是如果这个函数生成的本来就是流,它会把函数生成流中的元素加到流中
//这个函数本身就生成流 public static stream<character> tostream(string s){ list<character> list=new arraylist<character>(); char[] chs = s.tochararray(); for (char c : chs) { list.add(c); } stream<character> stream = list.stream(); return stream; } @test public void test() { list<string> list = arrays.aslist("aaa","bbb","ccc"); stream<stream<character>> stream = //由于函数本身就生成流,所以流中加入的还是流 list.stream().map(streamtest::tostream); //遍历的时候需要先从流中取出流,在遍历 stream.foreach((s)->s.foreach(system.out::println)); } //然而我们可以使用flatmap进行改进 @test public void test() { list<string> list = arrays.aslist("aaa","bbb","ccc"); list.stream().flatmap(streamtest::tostream).foreach(system.out::println); } 输出: a a a b b b c c c
终止操作
所有匹配
当所有元素都匹配时,allmatch(predicate<? super t> predicate)才会返回true
@test public void test() { list<string> list = arrays.aslist("aaa","bbb","ccc"); boolean allmatch = list.stream().allmatch((s)->s.length()>2); system.out.println(allmatch); } 输出: true
任一匹配
当stream中任一一个元素匹配时,anymatch(predicate<? super t> predicate)返回true
@test public void test() { list<string> list = arrays.aslist("aaa","bbb","ccc"); boolean anymatch = list.stream().anymatch((s)->s.equals("bbb")); system.out.println(anymatch); } 输出: true
所有不匹配
当stream中所有的元素都不匹配时,nonematch(predicate<? super t> predicate)返回true
@test public void test() { list<string> list = arrays.aslist("aaa","bbb","ccc"); boolean nonematch = list.stream().nonematch((s)->s.equals("ddd")); system.out.println(nonematch); } 输出: true
第一个元素
返回当前流中的第一个元素
@test public void test() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> findfirst = list.stream().findfirst(); system.out.println(findfirst.get()); } 输出: 1
任一一个元素
返回当前流中的任一一个元素
@test public void test() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> findany = list.stream().findany(); system.out.println(findany.get()); } 输出: 1 //使用并行流试试 @test public void test13() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> findany = list.parallelstream().findany(); system.out.println(findany.get()); } 输出: 3
流中元素个数
返回流中的元素个数
@test public void test14() { list<integer> list = arrays.aslist(1,2,3,4,5); long count = list.stream().count(); system.out.println(count); } 输出: 5
流中的最大值
返回流中元素的最大值
@test public void test15() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> max = list.stream().max(integer::compare); system.out.println(max.get()); } 输出: 5
流中的最小值
返回流中的最小值
@test public void test16() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> min = list.stream().min(integer::compare); system.out.println(min.get()); } 输出: 1
规约
将流中的元素反复结合得到一个最终值
@test public void test() { list<integer> list = arrays.aslist(1,2,3,4,5); optional<integer> reduce = list.stream().reduce(integer::sum); system.out.println(reduce.get()); integer reduce2 = list.stream().reduce(0, (x,y)->{ system.out.println(x+"->"+y); return x+y; }); system.out.println(reduce2); } 输出: 15 0->1 1->2 3->3 6->4 10->5 15
可以看到当使用(t identity, binaryoperator
将流转换成其他形式收集
@test
public void test() {
list<integer> list = arrays.aslist(1,2,3,4,5,5);
set<integer> collect = list.stream().collect(collectors.toset());
system.out.println(collect);
}
输出:
[1, 2, 3, 4, 5]
@test
public void test() {
list<integer> list = arrays.aslist(1,2,3,4,5,5);
optional<integer> collect = list.stream().collect(collectors.maxby(integer::compareto));
system.out.println(collect.get());
}
输出:
5
class stu{
string name;
integer age;
string gender;
public stu(string name, integer age, string gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public string getname() {
return name;
}
public void setname(string name) {
this.name = name;
}
public integer getage() {
return age;
}
public void setage(integer age) {
this.age = age;
}
public string getgender() {
return gender;
}
public void setgender(string gender) {
this.gender = gender;
}
@override
public string tostring() {
return "stu [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
//一级分组
@test
public void test() {
list<stu> list = arrays.aslist(
new stu("张三",20,"男"),
new stu("李四",22,"女"),
new stu("王五",18,"男"),
new stu("赵六",20,"女"),
new stu("田七",22,"女")
);
map<string, list<stu>> collect = list.stream().collect(collectors.groupingby(stu::getgender));
system.out.println(collect);
}
输出:
{女=[stu [name=李四, age=22, gender=女], stu [name=赵六, age=20, gender=女], stu [name=田七, age=22, gender=女]], 男=[stu [name=张三, age=20, gender=男], stu [name=王五, age=18, gender=男]]}
//二级分组
@test
public void test21() {
list<stu> list = arrays.aslist(
new stu("张三",20,"男"),
new stu("李四",22,"女"),
new stu("王五",18,"男"),
new stu("赵六",20,"女"),
new stu("田七",22,"女")
);
map<integer, map<string, list<stu>>> collect = list.stream()
.collect(collectors.groupingby(stu::getage, collectors.groupingby(stu::getgender)));
system.out.println(collect);
}
输出:
{18={男=[stu [name=王五, age=18, gender=男]]}, 20={女=[stu [name=赵六, age=20, gender=女]], 男=[stu [name=张三, age=20, gender=男]]}, 22={女=[stu [name=李四, age=22, gender=女], stu [name=田七, age=22, gender=女]]}}
//分区
@test
public void test22() {
list<stu> list = arrays.aslist(
new stu("张三",20,"男"),
new stu("李四",22,"女"),
new stu("王五",18,"男"),
new stu("赵六",20,"女"),
new stu("田七",22,"女")
);
map<boolean, list<stu>> collect = list.stream()
.collect(collectors.partitioningby((e)->((stu)e).getage()>20));
system.out.println(collect);
}
输出:
{false=[stu [name=张三, age=20, gender=男], stu [name=王五, age=18, gender=男], stu [name=赵六, age=20, gender=女]], true=[stu [name=李四, age=22, gender=女], stu [name=田七, age=22, gender=女]]}