一.简介特性
1.Java8开始引入,支持链式书写;
2.存在惰性计算,短路操作,可消费性,所以性能上要优于传统编程;
(1).惰性计算:流的元素只在需要时才进行计算,不会提前计算整个流;
(2).短路操作:类似于 && ,|| 前面满足条件,后面的计算直接略过;
(3).可消费性:流只能被消费一次,即每个元素只能被处理一次;
3.流在管道中流通,在节点被处理;
4.流【无存储】,流不是一种数据结构,流存储的只是一种数据视图;
5.对于无限序列,如果直接调用 forEach() 或者 count() 求最终值,会直接进入死循环,因为无限序列永远不可能被计算完。所以我们需要先将起转变为有序序列,例如 limit(100) ;
6.并行计算: Stream 为单线程,当我们要使用多线程时,直接使用 parallel() ,自动转化多线程。
二.使用
1.常用操作关键字:
中间操作 | 最终操作 | ||
map | 映射,转换 | forEach | 遍历 |
filter | 从头截取到指定索引位置 | collect | count:返回元素个数 |
skip | 从指定的索引后一位截取到最后 | 数 学 (聚合) 计 算 | count:返回元素个数 |
sorted | 排序 | max:找出最大元素 | |
distinct | 去重 | min:找出最小元素 | |
concat | 合并流 | sum:求总和 | |
flatMap | 平面化处理 | sverage:求平均 | |
limit | 从头截取到指定索引位置 | ||
mapToInt mapToDoube mapToLong | 转成整型流 转成小数流 转成长整型流 |
2.创建使用:
(1)of()创建:
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
intStream.forEach(System.out::println);
(2)使用集合:
//1.创建list集合 转成流
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
//转成流
list.stream().forEach(System.out::println);
//2.直接创建
Stream<String> stream = Arrays.stream(new String[]{"1","2"});
(3)采用 Stream.generate() ,传入Supplier对象。基于Supplier创建的Stream会不断调用 Supplier.get() 方法来生成下一个元素,这种Stream中保留的不是元素,而是算法
//主函数
Stream<Integer> my = Stream.generate(new MySup());
my.limit(10).forEach(System.out::println);
//MySup类:
// 不断生成自然数的Supplier(范围在Integer之内)
static class MySup implements Supplier<Integer> {
int n = 0;
public Integer get() {
n++;
return n;
}
}
3.常规操作:
(1)三种基本类型流
Java泛型不支持基本类型,所以我们无法使用像 Stream<int> 这样的形式来保存int,只能采用形如 Integer 这样的形式。但是频繁装箱、拆箱操作会牺牲编译器的大量性能。
所以为了提高效率,Java标准库提供了三种使用基本类型的 Stream ,它们的使用和标准的Stream没有太大区别,直接使用: IntStream , LongStream, DoubleStream;
// 1. 直接创建int流
IntStream is = Arrays.stream(new int[] { 1, 2, 3 });
// 2. 将Stream<String>转换为LongStream:
LongStream s=List.of("1").stream().mapToLong(Long::parseLong);
(2)map() 映射操作
它将一个 Stream 转换为另一个 Stream
a.每一次映射都会自赋值,形如:a = a + 1 可写成 a+1,所以不再需要编写赋值语句
//自赋值
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
intStream.map(a -> a+1).forEach(System.out::print);//输出:23456
b.可以实现类型转换, map() 方法接收一个 Function 接口对象,负责做类型转换
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
List<String> strings = new ArrayList<>();
strings.add(" AbCde ");
strings.add(" asd ");
//去空格,转小写
strings.stream().map(String::trim).map(String::toLowerCase).forEach(System.out::print);//输出:abcdeasd
(3)sorted() 排序操作
System.out.println("排序");
//1.默认从小到大
list.stream().sorted().forEach(System.out::print);
System.out.println("------");
//2.可自定义过滤器,传入a,b两个参数,b-a为从大到小
list.stream().sorted((a,b)-> b-a).forEach(System.out::print);
(4)filter() 过滤操作
//list=[1,2,3,4,5,6,7,8,9],输出大于3的元素
list.stream().filter(a -> a > 3).forEach(System.out::println);//输出:456789
(5)distinct()去重
Arrays.stream(new int[]{1, 1, 2, 3, 2, 2}).distinct().forEach(System.out::print);//输出:123
(6)limit()截取前面
//从0号索引开始,截取4个
list.stream().limit(4).forEach(System.out::print);//输出:0123
(7)skip() 截取后面
//从第5个开始,到最后
list.stream().skip(4).forEach(System.out::print);//输出:456789
(8)concat() 合并流
System.out.println("合并流");
Stream<String> stream1 = Arrays.stream(new String[]{"qw", "we", "rt"});
Stream<String> stream2 = Arrays.stream(new String[]{"as", "sd", "df"});
Stream.concat(stream1,stream2).forEach(System.out::print);//输出:qwwertassddf
(9)flatMap() 平面化处理,将三维数据转成二维数据(将二维数组转成一维数组)
List<List<Integer>> listList = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(9);
list2.add(7);
list2.add(8);
listList.add(list1);
listList.add(list2);
listList.stream().forEach(System.out::print);//输出:[1, 2, 3][9, 7, 8]
System.out.println();
listList.stream().flatMap(ls -> ls.stream()).forEach(System.out::print);//输出:123978
(10)forEach() 遍历
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5);
intStream.forEach(System.out::println);
(11)collect() 转化成集合
/**list=[0,1,2,3,4,5,6,7,8,9]*/
//1.操作完stream,转化成List
listList<Integer> collect = list.stream().map(a -> a + 3).collect(Collectors.toList());
System.out.println(collect); //输出:[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
//2.操作完stream,转化成Set
Set<Integer> collectSet = list.stream().map(a -> a + 2).collect(Collectors.toSet());
System.out.println(collectSet);//输出:[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
//3.操作我stream,转化成Map
//3-1.list中存放基本类型
List<Character> strList = new ArrayList<>();
strList.add('a');
strList.add('b');
strList.add('c');
strList.add('e');
strList.add('f');
//转map时,用strList的索引当作key,strList中的每一个元素当作value
Map<Integer, Character> collectMap1 = strList.stream().collect(Collectors.toMap(obj->strList.indexOf(obj), obj->obj,(a,b)-> a));
System.out.println(collectMap1);//输出:{0=a, 1=b, 2=c, 3=e, 4=f}
//3-2.list中存放对象
List<Person> people = new ArrayList<>();
people.add(new Person(1,"杨过"));
people.add(new Person(2,"小龙女"));
people.add(new Person(3,"周伯通"));
people.add(new Person(4,"杨康"));
people.add(new Person(5,"小龙男"));
//转map时,先把每个对象的编号+1然后当作key,用每个对象的name当作value
Map<Integer, String> collectMap = people.stream().map(p ->{
p.setNumber(p.getNumber()+1);
return p;
}).collect(Collectors.toMap(Person::getNumber, Person::getName,(a,b)-> a));
System.out.println(collectMap);//输出:{2=杨过, 3=小龙女, 4=周伯通, 5=杨康, 6=小龙男}
//3-3. 把两个不同的集合转成map;
//使用strList中存放[a,b,c,e,f] 当作key,使用people中存放的[2=杨过, 3=小龙女, 4=周伯通, 5=杨康, 6=小龙男]的名称当作value
Map<Character, String> collectMap2 = strList.stream().collect(Collectors.toMap(obj -> obj, p -> {
Person person = people.get(strList.indexOf(p));
return person.getName();
},(key1,key2)->key1));
System.out.println(collectMap2);//输出:{a=杨过, b=小龙女, c=周伯通, e=杨康, f=小龙男}
//3-4. List<Object> 转 Map<String, List<Object>> (分组)
//用名称分组
Map<String, List<Person>> groupMap = people.stream().collect(Collectors.groupingBy(Person::getName));
System.out.println(groupMap);//输出:{小龙男=[Person{number=6, name='小龙男'}], 杨过=[Person{number=2, name='杨过'}], 杨康=[Person{number=5, name='杨康'}], 周伯通=[Person{number=4, name='周伯通'}], 小龙女=[Person{number=3, name='小龙女'}]}
//以姓氏分组
Map<String, List<Person>> groupMap1 = people.stream().collect(Collectors.groupingBy(p->p.getName().substring(0,1)));
System.out.println(groupMap1);//输出:{周=[Person{number=4, name='周伯通'}], 杨=[Person{number=2, name='杨过'}, Person{number=5, name='杨康'}], 小=[Person{number=3, name='小龙女'}, Person{number=6, name='小龙男'}]}
(12)数学(聚合)计算: max 最大, min 最小, count 个数, sum 总和, sverage 平均
/**
* list=[0,1,2,3,4,5,6,7,8,9]
* perple=[Person{number=1, name='杨过'}, Person{number=2, name='小龙女'}, Person{number=3, name='周伯通'}, Person{number=4, name='杨康'}, Person{number=5, name='小龙男'}]
*/
System.out.println("***max找最大***");
//数字类型找最大 list=[0,1,2,3,4,5,6,7,8,9]
Optional<Integer> maxInt = list.stream().max(Integer::compareTo);
//通过get()方法获取最大值
System.out.println(maxInt.get());//输出:9
//字符串类型找最大
Optional<String> maxString = Arrays.stream(new String[]{"a", "b", "c", "d", "b"}).max(String::compareTo);
//通过get()方法获取最大值
System.out.println(maxString.get());//输出d
System.out.println("***min找最小***");
Optional<Integer> min = list.stream().collect(Collectors.minBy(Integer::compareTo));
System.out.println("min::"+min.get());//输出: minInt::0
Optional<Person> min1 = people.stream().collect(Collectors.minBy(Comparator.comparing(Person::getNumber)));
System.out.println("min1::"+min1.get()); //输出:minInt1::Person{number=1, name='杨过'}
Optional<Person> min2 = people.stream().min(Comparator.comparing(Person::getNumber));
System.out.println("min2::"+min2.get()); //输出:min2::Person{number=1, name='杨过'}
System.out.println("***count个数***");
long count = list.stream().count();
System.out.println("count::"+count);
System.out.println("***sum总和***");
//原始写法
Integer sum = list.stream().collect(Collectors.summingInt(s -> s));
System.out.println("sum::"+sum);//输出:sum::45
//使用mapToInt()转成IntStream,然后直接使用sum
int sum1 = list.stream().mapToInt(Integer::intValue).sum();
System.out.println("sum1::"+sum1);//输出:sum1::45
//操作Person对象,获取编号,然后sum
int sum2 = people.stream().mapToInt(Person::getNumber).sum();
System.out.println("sum2::"+sum2);//输出:sum2::15
System.out.println("***sverage平均***");
//直接求平均
Double avg = list.stream().collect(Collectors.averagingDouble(p -> p));
System.out.println(avg);//输出:4.5
//转成double,然后求平均
OptionalDouble average = list.stream().mapToDouble(Integer::intValue).average();
System.out.println(average.getAsDouble());//输出:4.5