一 Stream
1 概述
JDK8的特性之一,并不是传统意义上的IO流,而是一个用于数据传输的"管道",他的作用是提供一组高效的操作数据的方法 – 针对集合中的数据
2 应用Stream对象
通常筛选集合中元素的方法
public class Play {
public static void main(String[] args) {
// 定义集合存放元素
List<String> names= Arrays.asList("大黄","大白","小小黑");
findNameLength(names);
findNameByBig(names);
}
// 获取名字长度大于2的且名字中含有小字的动物
private static void findNameLength(List<String> names){
// 创建存放所有名字的集合
List<String> n=new ArrayList<>();
// 遍历筛选
for (String s:names) {
if(s.length()>2){
n.add(s);
}
}
// 筛选名字中有小的
List<String> l=new ArrayList<>();
for (String s:n) {
if(s.contains("小")){
l.add(s);
}
}
System.out.println(l);
}
// 显示以大开头的动物
private static void findNameByBig(List<String> names){
List<String> n=new ArrayList<>();
for (String s:names) {
if(s.startsWith("大")){
n.add(s);
}
}
System.out.println(n);
}
}
当过滤条件过多时,可使用Stream对象提供的方法,简化操作
public class Play {
public static void main(String[] args) {
// 定义集合存放元素
List<String> names= Arrays.asList("大黄","大白","小小黑");
findNameLength(names);
findNameByBig(names);
}
// 获取名字长度大于2的且名字中含有小字的动物
private static void findNameLength(List<String> names){
names.stream()
.filter(s->s.contains("小"))
.filter(s->s.length()>2)
.forEach(System.out::println);
}
// 显示以大开头的动物
private static void findNameByBig(List<String> names){
// 将集合转为Stream 集合类提供
// public Stream<T> stream()
// Stream<String> stream = names.stream();
// 通过Stream对象调用过滤方法,此方法会遍历集合中的元素
// public Stream<T> filter(Predocate<T> pre)
//Stream<String> n = stream.filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// return s.startsWith("大");
// }
// });
// 通过Stream对象调用方法展示数据
// n.forEach(System.out::println);
names.stream()
.filter(s -> s.startsWith("大"))
.forEach(System.out::println);
}
}
3 操作步骤
核心点:将集合对象转换成Stream对象
① 转换成Stream对象
② 根据需求,调用Stream对象中的方法完成操作
③ 展示数据
操作指定元素序列(集合或数组,集合居多)中符合指定要求(根据需求通过Stream对象调用方法完成对元素操作)的元素(集合或者数组中的数据)的一种技术
二 创建Stream对象的方式
1 共有五种
// 有限流
Collection默认的stream()方法和paralleStream()方法
Arrays.stream()
Stream.of()
// 无限流
Stream.iterate()
Stream.generate()
2 例子
public class Play {
public static void main(String[] args) {
// 方式1:单列集合转Stream
// stream() 按集合中的顺序操作
// paralleStream() 随机顺序进行操作
List<String> list= Arrays.asList("大黄","大白","小黑");
list.stream().forEach(System.out::println);
list.parallelStream().forEach(System.out::println);
// 方式2:数组转Stream
Arrays.stream(new int[]{-2,-1,0,8,42}).forEach(System.out::println);
// 方式3:将任意类型的多个数据视为一个整体转换为Stream
Stream.of(false,10L,8,3.14,'@',"dwd").forEach(System.out::println);
// 方式4:无限流 seed从指定数字计步 uo计步规则 配合limit(long size)可限定数据个数
// Stream.iterate(T need,UnaryOperator<T> uo)
/*Stream.iterate(1, new UnaryOperator<Integer>() {
@Override
public Integer apply(Integer integer) {
return integer+3;
}
}).limit(3).forEach(System.out::println);*/
Stream.iterate(1,i -> i+3).limit(3).forEach(System.out::println);
// 方式5:无限连续的无序流 与limit搭配使用
/*Stream.generate(new Supplier<Integer>() {
@Override
public Integer get() {
return (int)(Math.random()*10+1);
}
}).limit(5).forEach(System.out::println);*/
Stream.generate(()->(int)(Math.random()*10+1)).limit(3).forEach(System.out::println);
}
}
三 Stream常用API
1 筛选与切片
public class PlayTest {
// 筛选与切片
@Test
public void playFilter(){
// 对集合中的元素进行过滤
List<Integer> list= Arrays.asList(-2,4,0,4,12,85);
list.stream()
//显示所有偶数 -2 4 0 4 12
.filter(i->i%2==0)
// 去除重复元素 -2 4 0 12
.distinct()
// 保留指定个数 -2 4 0
.limit(3)
// 跳过几个元素 4 0
.skip(1)
.forEach(System.out::print);
}
}
2 映射
public class PlayTest {
@Test
public void playMap(){
// 字符串转小写
List<String> s=Arrays.asList("daw","swfgeWEFA","AG");
/*s.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toLowerCase();
}
}).forEach(System.out::println);*/
// s.stream().map(s1->s1.toLowerCase()).forEach(System.out::println);
s.stream().map(String::toLowerCase).forEach(System.out::println);
}
@Test
public void playFlatMap(){
// 两集合做一个Stream对象(取并集) stream.of
List<Integer> l1=Arrays.asList(1,2,3);
List<Integer> l2=Arrays.asList(3,4,5);
/*Stream.of(l1,l2).flatMap(new Function<List<Integer>, Stream<?>>() {
@Override
public Stream<?> apply(List<Integer> integers) {
return integers.stream();
}
}).forEach(System.out::println);
Stream.of(l1,l2).flatMap(i->i.stream()).forEach(System.out::println);*/
Stream.of(l1,l2).flatMap(List::stream).forEach(System.out::println);
}
}
3 排序
public class PlayTest {
@Test
public void playSort(){
// 对集合中的元素排序 默认升序 泛型为数值
List<Integer> list= Arrays.asList(-2,4,0,4,12,85);
// 升序
list.stream().sorted().forEach(System.out::println);
// 降序
list.stream().sorted(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}).forEach(System.out::println);
list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
}
}
4 查找匹配
public class PlayTest {
@Test
public void playMatch(){
List<Integer> list= Arrays.asList(-2,4,0,4,12,85);
// 查询是否所有元素都大于0
boolean f1=list.stream().allMatch(i->i>0);
System.out.println(f1);
// 查询是否有个别元素小于0
boolean f2=list.stream().anyMatch(i->i<0);
System.out.println(f2);
// 查询是否真的没有匹配到0
boolean f3=list.stream().noneMatch(i->i==0);
System.out.println(f3);
// 返回集合中第一个元素
Optional<Integer> f4=list.stream().findFirst();
if(f4.isPresent()){
System.out.println(f4.get());
}
// 返回集合中热任一元素
Optional<Integer> any = list.stream().findAny();
if(any.isPresent()){
System.out.println(any.get());
}
}
}
5 统计
public class PlayTest {
@Test
public void playCount(){
List<Integer> list= Arrays.asList(-2,4,0,4,12,85);
// 集合数据的元素总个数
long count = list.stream().count();
System.out.println(count);
// 查询集合元素的最大值
Optional<Integer> max=list.stream().max(Comparator.comparingInt(i->i));
if(max.isPresent()){
System.out.println(max.get());
}
// 查询有最小值
Optional<Integer> min=list.stream().min(Comparator.comparingInt(i->i));
if(min.isPresent()){
System.out.println(min.get());
}
}
}
6 汇总
public class PlayTest {
@Test
public void playCollect(){
// Stream转集合
// 转list
List<Object> l1=Stream.of(5,456,-5,3.14).collect(Collectors.toList());
System.out.println(l1);
// 转set
List<Integer> l2=Arrays.asList(-2,4,0,4,12,85);
Set<Integer> set = l2.stream().collect(Collectors.toSet());
System.out.println(set);
// 转TreeSet
TreeSet<Integer> treeSet = l2.stream().collect(Collectors.toCollection(TreeSet::new));
System.out.println(treeSet);
// 转map 目前Stream是单列 map为双列 故转为map后key同时也是value
// key不能重复 转换前先去重 两种方式去重 转set集合 或用Stream中的distinct()方法
/* Map<Integer,Integer> map=l2.stream().distinct()
.collect(Collectors.toMap(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer key) {
return key;
}
}, new Function<Integer, Integer>() {
@Override
public Integer apply(Integer value) {
return value;
}
}));*/
Map<Integer,Integer> map=l2.stream().distinct()
.collect(Collectors.toMap(k->k,v->v));
System.out.println(map);
// 求和 平均值 最大 最小
Integer sum=l2.stream().collect(Collectors.summingInt(i->i));
System.out.println(sum);
Double avg=l2.stream().collect(Collectors.averagingDouble(i->i));
System.out.println(avg);
Optional<Integer> max=l2.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(i->i)));
if(max.isPresent()){
System.out.println(max.get());
}
Optional<Integer> min=l2.stream()
.collect(Collectors.minBy(Comparator.comparingInt(i->i)));
if(min.isPresent()){
System.out.println(min.get());
}
}
}
7 Optional容器
作用:防止集合中元素没有获取到从而出现空指向异常
原理:通过制定方法获取集合中指定的元素,存放到optional容器中,此容器只能存放1个或0个元素,因此只需对容器判断即可
List<String> list=new ArrayList<>();
/*String s=list.stream().findFirst(); // null
System.out.println(s.length()); //NullpointException*/
Optional<String> f=list.stream().findFirst();
if(f.isPresent()){
String s=f.get();
}
四 分区和分组
1 作用
分组:根据指定条件进行组别的划分
分区:根据指定条件,只能将数据分为两个区域(一个是满足条件(true));一个是不满足条件(false)区域
2 例子
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private String name;
private Integer age;
private Long id;
private Integer kg;
}
测试类
public class EmployeeStreamTest {
private static List<Employee> employees=new ArrayList<>();
static {
employees.add(new Employee("大黄",4,0301L,20));
employees.add(new Employee("大白",4,0302L,18));
employees.add(new Employee("小黑",2,0303L,12));
}
// 根据年龄分组
@Test
public void playGroup(){
/*Map<Integer,List<Employee>> map=employees.stream()
.collect(Collectors.groupingBy(new Function<Employee, Integer>() {
@Override
public Integer apply(Employee employee) {
return employee.getAge();
}
}));*/
Map<Integer,List<Employee>> map=employees.stream()
.collect(Collectors.groupingBy(Employee::getAge));
System.out.println(map);
// {2=[Employee(name=小黑, age=2, id=195, kg=12)],
// 4=[Employee(name=大黄, age=4, id=193, kg=20),
// Employee(name=大白, age=4, id=194, kg=18)]}
}
// 通过体重进行分区 true>=18 false<18
@Test
public void playPart(){
/*Map<Boolean,List<Employee>> map=employees.stream()
.collect(Collectors.partitioningBy(new Predicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getKg()>=18;
}
}));*/
Map<Boolean,List<Employee>> map=employees.stream()
.collect(Collectors.partitioningBy(p->p.getKg()>=18));
System.out.println(map);
// {false=[Employee(name=小黑, age=2, id=195, kg=12)],
// true=[Employee(name=大黄, age=4, id=193, kg=20),
// Employee(name=大白, age=4, id=194, kg=18)]}
System.out.println(map.get(true));//体重不小于18kg的
System.out.println(map.get(false));//体重小于18kg的
}
}
五 并行和并发
1 并发
单核操作,按照指定的顺序完成操作,适用于处理数据量较小的操作,效率高 --stream()
2 并行
必须是多核操作,随机执行,适用于处理数据量较大的操作 – parallelStream
3 例子
public class PlayTest {
@Test
public void play(){
List<String> list= Arrays.asList("大黄","大白","小黑");
// 并发
list.stream().forEach(System.out::println);
// 并行
list.parallelStream().forEach(System.out::println);
// 并发转并行
list.stream().parallel().forEach(System.out::println);
}
}