文章目录
一,stream概述
stream流操作是jdk8的新增特性,配合lambda表达式,能够极大的简化对于集合的操作(每次都要循环遍历,创建新集合)。
stream流特性:
1,stream不会存储数据,而是按照特定规则对数据处理
2,stream不会改变数据源,通常会产生一个新的集合或值
3,stream流具有延迟执行特性,只有调用终端操作才会执行
二,stream的创建
1,使用java.util.stream.Stream()方法
List<String> list=new ArrayList();
Stream<String> stream = list.stream();
Set<String> set=new HashSet<>();
Stream<String> stream1 = set.stream();
// map不是集合,可以通过获取其keySet或者value来创建流
Map<String,String> map=new HashMap<>();
Stream<String> stream2 = map.keySet().stream();
Stream<String> stream3 = map.values().stream();
2,使用Stream中的静态方法of()
Stream<String> aa = Stream.of("aa", "bb", "cc");
aa.forEach(a-> System.out.println(a));
3,使用java.util.Arrays.stream(T[] array)方法用数组创建流
int[] array={1,2,3,4};
IntStream stream4 = Arrays.stream(array);
三,stream常见方法
1,stream方法的分类
终结方法:返回类型不是stream类型的方法,不支持链式调用,每个流只能调用一次终结方法,调用后产生新的集合或值。只有调用终结方法stream的中间操作才会执行
非终结方法:返回类型为stream类型的方法,支持链式调用
2,注意事项
2.1,一个stream只能操作一次
Stream<String> stream5 = Stream.of("aa", "bb", "cc");
stream5.count();
stream5.count();
// 会报错 Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
2.2,stream流返回的是新的流
2.3,只有调用终结方法stream的中间操作才会执行
3,stream常见方法
forEach()方法:终结方法,用于遍历集合中的元素
List<String> list=new ArrayList<>();
Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
//list.stream().forEach(s-> System.out.println(s));
list.stream().forEach(System.out::println);
count()方法:终结方法,统计集合元素的个数
List<String> list=new ArrayList<>();
Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
list.stream().count();
filter()方法:非终结方法,返回符合过滤条件的数据
List<String> list=new ArrayList<>();
Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
//获取名字长度为3的元素
//宋远桥,苏星河
list.stream().filter(a->
a.length()==3
).forEach(System.out::println);
limit()方法,非终结方法,获取流中的前n个元素
List<String> list=new ArrayList<>();
Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
//迪丽热,巴宋远桥,苏星河
list.stream().limit(3).forEach(System.out::println);
skip()方法,非终结方法,跳过流中前n个元素,截取之后的元素。若n大于集合的长度,则会获取长度为0的空流
List<String> list=new ArrayList<>();
Collections.addAll(list,"迪丽热巴","宋远桥","苏星河","老子","庄子","孙子");
//老子,庄子,孙子
list.stream().skip(3).forEach(System.out::println);
map(),非终结方法,将流中的元素映射到另一个流中
//将流中的字符串转为Integer
Stream<String> stringStream = Stream.of("1", "2", "3");
stringStream.map(s -> Integer.valueOf(s)).forEach(System.out::println);
sorted()方法非终结方法,对流中的数据进行排序
// 1,sorted()根据元素的自然顺序排序
// 升序
Stream.of(3, 7, 1, 8, 0, 9).sorted().forEach(System.out::println);
// 2,sorted(Comparator<? super T> comparator)根据比较器定义的规则排序
// 降序
Stream.of(3, 7, 1, 8, 0, 9).sorted((i1,Ii2)->i2 - i1).forEach(System.out::println);
distinct()非终极方法,去除流中的重复元素
Stream.of(3, 1, 1, 3, 0, 2).distinct().forEach(System.out::println);
//自定义对象的去重,要重写equals方法和hashCode方法
Stream<Person> personStream = Stream.of(new Person("小明", "11"), new Person("小明", "11"), new Person("小红", "12"));
personStream.distinct().forEach(System.out::println);
match()终结方法,
allMatch()匹配所有,所有元素都满足条件返回true,否则返回false
anyMatch()匹配某个元素,只要有一个元素满足条件返回true
noneMatch()匹配所有,所有元素都不满足条件返回ture
// false,true,true
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
// System.out.println(integerStream.allMatch(i->i>3));
// System.out.println(integerStream.anyMatch(i->i>3));
System.out.println(integerStream.noneMatch(i->i>6));
find()方法
findFirst()找第一个元素
findAny()找第一个元素
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
System.out.println(integerStream.findAny().get());
max(),min()获取最大值,最小值
Optional<Integer> max = integerStream.max((i1, i2) -> i1 - i2);
System.out.println(max.get());
reduce()将所有的数据归纳得到一个数据
// T reduce(T identity, BinaryOperator<T> accumulator);
// identity:默认值
// BinaryOperator<T>:对数据处理的方式
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
Integer reduce = integerStream.reduce(0, (a, b) -> a + b);
System.out.println(reduce);
concat()将两个流合并成一个流,合并后不能在操作合并前的流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> integerStream1 = Stream.of(5, 6, 7);
Stream.concat(integerStream,integerStream1).forEach(System.out::println);
四,收集stream流中的结果
对流进行操作后,将结果保存到数组或集合中
stream提供方法collect()
Stream<String> stream = Stream.of("a", "b");
//将流中的结果收集到list中
List<String> collect = stream.collect(Collectors.toList());
//将流中的结果收集到set中
Set<String> collect1 = stream.collect(Collectors.toSet());
//收集到指定的集合中
Stream<String> stream = Stream.of("a", "b");
ArrayList<String> collect = stream.collect(Collectors.toCollection(ArrayList::new));
//将流中的数据收集到数组中
Stream<String> stream = Stream.of("a", "b");
//Object[] objects = stream.toArray();
String[] strings = stream.toArray(String[]::new);
对流中的数据进行聚合计算(相当于数据库中的聚合函数)
Stream<Student> studentStream = Stream.of(
new Student("小赵", 56, 11),
new Student("小李", 33, 56),
new Student("小王", 27, 7),
new Student("小周", 87, 98)
);
// 获取最大值
Optional<Student> max = studentStream.collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));
System.out.println(max.get());
//求和
IntSummaryStatistics sum = studentStream.collect(Collectors.summarizingInt(s -> s.getAge()));
System.out.println(sum);
//求平均值
Double score = studentStream.collect(Collectors.averagingInt(s -> s.getScore()));
System.out.println(score);
studentStream.collect(Collectors.counting());
对流中的数据进行分组
Stream<Student> studentStream = Stream.of(
new Student("小赵", 56, 11),
new Student("小李", 56, 56),
new Student("小王", 53, 7),
new Student("小周", 53, 98)
);
//按照age分组
Map<Integer, List<Student>> collect = studentStream.collect(Collectors.groupingBy(s -> s.getAge()));
collect.forEach((k,v)-> System.out.println(k+":"+v));
//成绩大于60合格,否则不合格
Map<String, List<Student>> collect = studentStream.collect(Collectors.groupingBy(s -> {
if (s.getScore() > 60) {
return "合格";
} else {
return "不合格";
}
}));
collect.forEach((k,v)-> System.out.println(k+":"+v));
分区,将流按照指定条件划分为不同区
Stream<Student> studentStream = Stream.of(
new Student("小赵", 56, 11),
new Student("小李", 56, 56),
new Student("小王", 53, 7),
new Student("小周", 53, 98)
);
Map<Boolean, List<Student>> collect = studentStream.collect(Collectors.partitioningBy(s -> s.getScore() > 60));
collect.forEach((k,v)->{
System.out.println(k+"::"+v);
});
拼接,将流中的字符串按照指定条件拼接成一个字符串
String collect = studentStream.map(Student::getName).collect(Collectors.joining("-"));
System.out.println(collect);
//小赵-小李-小王-小周
五,并行stream流
并行stream流的速度较快
获取并行stream流的方法
1,将串行流改为并行流
Stream<Integer> integerStream = Stream.of(2, 7, 45, 3, 19, 87, 12, 5);
integerStream.parallel().forEach(s->{
System.out.println(Thread.currentThread()+"---s:"+s);
});
2,直接获取并行流
List<Integer> list=new ArrayList<>();
Collections.addAll(list,2, 7, 45, 3, 19, 87, 12, 5);
list.parallelStream().forEach(s->{
System.out.println(Thread.currentThread()+"---s:"+s);
});
线程安全问题
List<Integer> list = new ArrayList<>();
IntStream.rangeClosed(1,1000).parallel().forEach(s-> {
list.add(s);
});
System.out.println(list.size());
//list.size!=1000,因为list是线程不安全的
解决方式
1,使用同步代码块
List<Integer> list = new ArrayList<>();
Object obj=new Object();
IntStream.rangeClosed(1,1000).parallel().forEach(s-> {
synchronized (obj){
list.add(s);
}
});
System.out.println(list.size());
2,使用线程安全的集合,例如Vector
3,使用结合工具类将不安全的list转为安全的
List<Integer> list = new ArrayList<>();
List<Integer> list1 = Collections.synchronizedList(list);
IntStream.rangeClosed(1,1000).parallel().forEach(s-> {
list1.add(s);
});
System.out.println(list.size());
4,调用stream流的collect/toArray