java8 新特性 stream
java8 stream
创建流
集合对象.stream()、Arrays.stream(数组对象)【这个返回的是intStream】、Stream.of()【不推荐】
我理解中Stream.of()更像是直接把参数作为一个个的对象去创建流(看解释符合我的猜想),不过参数是字符串数组的时候又会拿数组里面的数据去创建流,真是疑惑。
Stream.of(数组对象)创建流,如果数组数据类型是基本类型,那么创建的流内部是数组对象(int[ ]),会有问题。如果传入的是list,创建的流是一个list流,也有问题。
基本数据类型的数组创建流,最好用Arrays.stream创建基本(int)流,再调用boxed转包装(integer)流。
顺便提醒一下Arrays.asList()创建的list是不可变的
数组转list(前两个本质上都是一样的流操作)
方法1、先利用Arrays.stream转成int流,然后调用boxed转成integer流,再转list。
方法2、可以先用Arrays.asList转成不可变的list,然后转成流再获取集合,这样集合就是可变集合了。
方法3、可以显式创建list,传入Arrays.asList生成的不可变数组对象,然后得到一个可变的list。
int流转Integer流.boxed
int[ ] a={1,2};
String[ ] a1={"1","2"};
IntStream stream = Arrays.stream(a);//返回intStream
Stream<String> stream1 = Arrays.stream(a1);//正常返回字符串流
Stream<int[]> b1 = Stream.of(a);//基本类型数组创建的流有问题
Stream<String> b2 = Stream.of(a1);//正常返回字符串流
Stream<Integer> boxed = Arrays.stream(a).boxed();//int流转integer流
List<Integer> id = Arrays.asList(20, 10, 38, 49);
Stream<List<Integer>> id1 = Stream.of(id);//这样创建也有问题,要用对象.stream创建
流转数组toArray
需要传入构造数据的方法
Integer[] integers1 = Arrays.asList(1, 2, 3).stream()
.toArray(Integer[]::new);
Integer[] integers2 = Arrays.asList(1, 2, 3).stream()
.toArray(size -> new Integer[size]);
操作流
转换流map(一对一)
参数部分可以利用lambda表达式,拼接出新的对象流。参数左侧代表原来列表内的单个对象,右侧代表新的流里面的单个对象。(列表对象数量上面一一对应)
常用:对象流到对象流,对象流转基本数据流。
例子:
class User{
private long id;
private int gender;
private int age;
User(){};
User(long id,int gender,int age){
this.id=id;
this.gender=gender;
this.age=age;
}
}
class Student{
private long id;
private int age;
Student(){};
Student(long id,int age){
this.id=id;
this.age=age;
}
}
List<User> userList=new ArrayList<>();
userList.add(new User(1,0,18));
userList.add(new User(2,0,18));
userList.add(new User(3,1,20));
//对象流转基本数据流
List<Long> userIdList= userList.stream().map(x->x.getId()).collect(Collectors.toList());
//对象流转对象流
List<Student> studentList=userList.stream().map(x->{
Student stu= new Student();
stu.setId(x.getId());
stu.setAge(x.getAge);
return stu;
}).collect(Collectors.toList());
转换流flatMap(一对多)
在括号内,是一对多的关系,左边是原理的对象,右边是一个新的流。也就是将一个对象转成一个流(流里面可能包含多个对象),最后再将全部流合在一起,形成一个新的流。
例子:
//将一个英文句子数组拆成一个单词数组
List<String> sentences = Arrays.asList("hello world","Jia Gou Wu Dao");
List<String> results = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" "))) .collect(Collectors.toList()); System.out.println(results);
.collect(Collectors.toList());
过滤流filter
根据括号内的条件,符合条件的加入返回的流,不符合的就被过滤掉。
例子:
//过滤用户id为空的对象,可以像上面的对象流转对象流一样进行较多逻辑判断
List<User> userIdList= userList.stream()
.filter(x->!Objects.nonNull(x.getVoiceId()))
.collect(Collectors.toList());
排序流sorted
//过滤用户id为空的对象,
List<User> userIdList= userList.stream().sorted((x,y)->x-y).collect(Collectors.toList());
//可以像上面的对象流转对象流一样进行较多逻辑判断,从小到大顺序排序
List<User> userIdList= userList.stream().sorted((x,y)->{
if(x.getId()>y.getId()){
return 1;
}else if(x.getId()<y.getId()){
return -1;
}else{
if(x.getAge()>y.getAge()){
return 1;
}else{
return -1;
}
}
}).collect(Collectors.toList());
去重流distinct
//对象的去重流是调用类的hashcode和toString方法来判断是否重复(可以自定义是否重复)
List<User> userIdList= userList.stream()
.distinct().collect(Collectors.toList());
合并流Stream.concat
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
Stream<Integer> arr1 = Stream.of(1,2,3);
List<Integer> collect2 = Stream.concat(integerStream, arr1)
.collect(Collectors.toList());
System.out.println(collect2);
查找符合条件的第一个元素findFirst
一般配合filter以及ifPresent使用,下面语句的意思是查找符合条件的第一个元素,如果存在则输出
userList.stream().findFirst().ifPresent(s -> System.out.println(s));
遍历(peek&foreach)
中间遍历peek
该方法会遍历一遍流里面的元素,必须配合终止流才会进行里面遍历的操作。如果没有调用终止流的操作,那么中间操作并不会执行。
终止流foreach
调用终止流foreach会遍历流里面的元素,并且立刻执行。
public void testPeekAndforeach() {
List<String> sentences = Arrays.asList("hello world","Jia Gou Wu Dao");
// 演示点1: 仅peek操作,最终不会执行
System.out.println("----before peek----");
sentences.stream().peek(sentence -> System.out.println(sentence));
System.out.println("----after peek----");
// 演示点2: 仅foreach操作,最终会执行
System.out.println("----before foreach----");
sentences.stream().forEach(sentence -> System.out.println(sentence));
System.out.println("----after foreach----");
// 演示点3: peek操作后面增加终止操作,peek会执行
System.out.println("----before peek and count----");
sentences.stream().peek(sentence -> System.out.println(sentence)).count();
System.out.println("----after peek and count----");
}
取前几个元素limit
通过limit,可以限制获取流里面元素的个数,比如先排序,然后限制数量,就可以获取排序前几的元素。
public void testGetTargetUsers() {
List<Integer> ids = Arrays.asList(10,20,50,5,6);
// 使用流操作
List<Integer> results = ids.stream()
.sorted((x,y)->(x-y))
.limit(3)
.collect(Collectors.toList());
System.out.println(results);
}
跳过前几个元素skip
int[] arr={1,2,3};
Arrays.stream(arr).skip(2).forEach(System.out::println);
终止流
一个流调用了终止流的方法之后,流就不可用了。
比如一些常用的,
计算流内元素数量count
获取流里面元素最大值max
获取流里面元素最小值min
流内是否存在元素anyMatch
流内是否全部元素都匹配allMatch
流内没有匹配的元素noneMatch
收集流collect
将流里面的元素返回一个集合
public void testCollectStopOptions() {
List<Dept> ids = Arrays.asList(new Dept(17), new Dept(22), new Dept(23));
// collect成list
List<Dept> collectList = ids.stream().filter(dept -> dept.getId() > 20)
.collect(Collectors.toList());
System.out.println("collectList:" + collectList);
// collect成Set
Set<Dept> collectSet = ids.stream().filter(dept -> dept.getId() > 20)
.collect(Collectors.toSet());
System.out.println("collectSet:" + collectSet);
// collect成HashMap,key为id,value为Dept对象
Map<Integer, Dept> collectMap = ids.stream().filter(dept -> dept.getId() > 20)
.collect(Collectors.toMap(Dept::getId, dept -> dept));
System.out.println("collectMap:" + collectMap);
}
利用collect拼接元素
List<String> id = Arrays.asList("205", "10", "308", "49");
String joinResult = id.stream().collect(Collectors.joining(","));
System.out.println(joinResult);
统计相关
List<Integer> id = Arrays.asList(205, 10, 308, 49);
IntSummaryStatistics collect = id.stream()
.collect(Collectors.summarizingInt(x -> x));
System.out.println(collect);
IntSummaryStatistics 对象还可以中途加数据,加数据之后其他数据会重新计算。
还可以调用combine方法加其他IntSummaryStatistics 对象。
双冒号
lambda表达式的一种写法,接口的方法已经有了实现的时候