jva8在java.util.stream包下,通过Stream真正的引入函数式编程,可以对数据进行复杂的查找,过滤映射,提供了高效且易于使用的处理数据的方式,例如想要获取集合中的某些特定元素,在以前需要遍历集合,对每个元素进行筛选代码比较多,通过Stream,一行代码就可以搞定
@Test
public void test1(){
//创建Stream的方式
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明",22,2000.00));
persionList.add(new Persion("小红",34,2500.00));
persionList.add(new Persion("AA",18,1800.00));
persionList.add(new Persion("小强",40,3500.00));
persionList.add(new Persion("小黑",22,2200.00));
persionList.add(new Persion("小花",27,2000.00));
persionList.add(new Persion("bb",16,1500.00));
//1.通过集合中的.stream()获取Stream流,注意该方法返回的是一个顺序流(根据向集合中添加的顺序)
Stream<Persion> stream1 = persionList.stream();
//通过集合中的parallelStream()获取一个并行流,有点像通过几个线程同时去取,顺序可能发生改变
Stream<Persion> stream2 = persionList.parallelStream();
//2.通过Arrays工具类中的stream(T[] array)静态方法获取Stream流
//集合转数组
Persion[] perArray = persionList.toArray(new Persion[persionList.size()]);
Stream<Persion> stream = Arrays.stream(perArray);
//注意点,在使用Arrays中的stream()方法获取Stream流时,根据像方法中传递的
//泛型T不同,其返回的Stream不同
int[] iArray = new int[]{1,4,9};
long[] lArray = new long[]{11l,22l,6l};
double[] dArray = new double[]{7.8,14.3,5.1};
IntStream intStream = Arrays.stream(iArray);
LongStream longStream = Arrays.stream(lArray);
DoubleStream doubleStream = Arrays.stream(dArray);
//3.通过Stream的of()方法创建,将数据传入of()方法中
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4);
//4.创建无限Stream流,输出0-10的偶数,
//iterate()中0代表开始位置,后面的Lambda传递的是Function +2返回
//limit为中止操作,10
//forEach()为执行体
Stream.iterate(0,t -> t +2).limit(10).forEach(System.out :: println);
//生成,获取10个随机数
Stream.generate(Math :: random).limit(10).forEach(System.out :: println);
}
使用Stream对数据继续操作,例如过滤筛选,映射,排序等,注意点: Stream被称为"惰性求值",在进行中间操作时,如果最终不调用终止,则中间操作无效,在调用终止操作后,若有后续的操作需要重新获取Stream流,否则无效
@Test
public void test1(){
//persionList是一个List集合
//获取Stream流
Stream<Persion> stream = persionList.stream();
//筛选与切片
//1.filter(Predicate p) 过滤,接收 Lambda ,从流中排除某些元素
//获取集合中age大于20的数据
stream.filter(p -> p.getAge()>20).forEach(System.out :: println);
//2.limit(n) 截断流,使其元素不超过给定的数量n
Stream<Persion> stream2 = persionList.stream();
//获取集合中前三条数据
stream2.limit(3).forEach(System.out :: println);
//3.skip(n) 跳过元素,返回一个不包括n以前个数的元素,若流中不足n个数据则返回就返回一个空流
//去掉集合中前3个元素
persionList.stream().skip(3).forEach(System.out :: println);
//4.distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
//去重
persionList.stream().distinct().forEach(System.out :: println);
}
@Test
public void test2(){
//1.map(Function f) 接收一个函数作为参数,将元素映射成其它形式或获取信息,
//该函数会被应用到每个元素上,并将其映射到新的元素
//map()会依次对Stream中的每个元素执行
//示例1,将集合中所有字符串转换为大写
List<String> stringList = Arrays.asList("aa", "bb", "cc");
stringList.stream().map(str -> str.toUpperCase()).forEach(System.out :: println);
//示例2,获取集合姓名包含"小"的员工的姓名
Stream<String> ageStream = persionList.stream().map(Persion::getName);
ageStream.filter(name -> name.contains("小")).forEach(System.out :: println);
//2.flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流
//然后把所有流连接成一个流,与map()方法的区别有点像集合中的add(),与addAll()
//假设调用add方法向集合中添加另外一个集合是会变成[obj1, obj2, obj3,List[obj1,obj2,obj3]]
//如果调用addAll(),则会重新组合为一个集合,而不是集合作为集合类型元素存在
//假设通过map()获取的数据是Stream>,此时如果想要继续过滤就有点麻烦,可以通过flatMap()
//例如调用下面自定义的fromStringToStream(String str)方法,返回多个Stream流,
Stream<Stream<Character>> streamStream = stringList.stream().map(ArrayTest::fromStringToStream);
//输出stringList中的所有char字符,由于调用ArrayTest类中中的fromStringToStream()方法
//返回的是Stream>,需要两层farEach()
streamStream.forEach(s -> {
s.forEach(System.out :: println);
});
//使用flamtMap,则会将多个Stream流重新组合为一个
Stream<Character> characterStream = stringList.stream().flatMap(ArrayTest::fromStringToStream);
characterStream.forEach(System.out :: println);
}
//将String字符串,转换为char集合,并将char集合转换为Stream流返回
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
//1.使用map转换为其它类型
List<ResponseDataDTO> responseDataDTOS = result.stream().map(a -> {
ResponseDataDTO responseDataDTO = new ResponseDataDTO();
responseDataDTO.setC00("");
responseDataDTO.setC01(a.getRmtype());
responseDataDTO.setC02(a.getRate1().toString());
responseDataDTO.setC03("");
responseDataDTO.setC04("");
responseDataDTO.setC05("");
responseDataDTO.setC06(a.getRatecode());
responseDataDTO.setC07("");
responseDataDTO.setC08(a.getRate1().toString());
responseDataDTO.setC09(a.getPackages());
return responseDataDTO;
}).collect(Collectors.toList());
//2.使用map+flatMap多list合并
List<String> accntList = searchcheckin.getData().getList()
.stream()
.filter(o -> !CollectionUtils.isEmpty(o.getList()))
.map(OrderRespDTO::getList)
.flatMap(Collection::stream)
.filter(occ -> !CollectionUtils.isEmpty(occ.getGuests()))
.map(OccupationDTO::getGuests)
.flatMap(Collection::stream)
.filter(g -> StringUtils.isNotBlank(g.getAccNt()))
.map(GuestDTO::getAccNt)
.distinct()
.collect(Collectors.toList());
2)代码示例
@Test
public void test3(){
//排序
//1.sorted() 自然排序
List<Integer> integers = Arrays.asList(12, 34, 20, 70, 60);
integers.stream().sorted().forEach(System.out::println);
//如果想要自定义类对象实现自然排序,该类需要实现Comparator接口,制定排序规则否则报错
//否则使用sorted定制排序
//2.sorted(Comparator com) 定制排序(如果年龄相等则使用工资排序)
persionList.stream().sorted((p1, p2) ->{
int ageVal = Integer.compare(p1.getAge(),p2.getAge());
if(ageVal != 0){
return ageVal;
}else {
return Double.compare(p1.getSalary(), p2.getSalary());
}
}).forEach(System.out :: println);
}
@Test
public void test4() {
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()......
//一下的操作中都可以在加入中间操作实现过滤后再进行终止
//1.allMatch(Predicate p) 检查元素是否匹配,所有都是true,才是true
//判断是否集合中的所有年龄都大于18岁
Boolean b1 = persionList.stream().allMatch(p -> p.getAge() > 18);
//2.anyMatch(Predicate p) 检查是否有一个元素匹配,有一个为true则为true
//判断集合中是否有工资大于5000
Boolean b2 = persionList.stream().anyMatch(p -> p.getSalary() > 5000);
//3.noneMatch(Predicate p) 检查是否没有匹配的
//判断集合中是否有叫小明的,如果有则返回false
boolean b3 = persionList.stream().noneMatch(p -> p.getName().contains("小明"));
//4.findFirst 返回第一个元素,Option<>
Optional<Persion> persionOptional = persionList.stream().findFirst();
//5.findAny 返回当前流中任意元素
Optional<Persion> anyPersion = persionList.stream().findFirst();
//6.count 返回当前流中元素个数
//获取工资超过2000的个数
long count = persionList.stream().filter(p -> p.getSalary()>2000.00).count();
//7.max(Comparator c) 返回当前流中最大的元素
//返回最大工资的
Optional<Persion> max = persionList.stream().max((p1, p2) -> Double.compare(p1.getSalary(), p2.getSalary()));
//min(Comparator c) 返回最小的元素
//返回年龄最小的
Optional<Persion> min = persionList.stream().min((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
//返回最小年龄
persionList.stream().map(p -> p.getAge()).min(Integer :: compare);
//8.forEach(Consumer c) 内部迭代
persionList.stream().forEach(System.out :: println);
}
@Test
public void test5(){
//1.reduce(T identity, BinaryOperator) 将六种的元素结合起来得到一个值并返回
//查看BinaryOperator源码进行分析
//BinaryOperator继承BiFunction接口,该接口传递两个T类型参数,返回一个T类型参数
//刚好符合Integer与Dubbo中的sum方法
//计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list.stream().reduce(0, Integer::sum);
//普通方式
Integer reduce2 = list.stream().reduce(0, (i1, i2) -> i1 + i2);
//2.reduce(BinaryOperator)
//获取集合中工资总和
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()...
Optional<Double> reduce1 = persionList.stream().map(Persion::getSalary).reduce(Double::sum);
//普通方式
persionList.stream().map(Persion::getSalary).reduce((d1, d2) -> d1+d2);
}
1)方法概述
StreamAPI 收集 Collectors,将过滤终止的Stream结果数据收集为其他类型,与Stream收集终止操作配合使用
2)代码示例
@Test
public void test6(){
//1.collection(Collector c); 配合Collector中的静态方法,将Stream过滤终止后的数据
//收集为其他类型,例如List, set等
List<Persion> persionList = new ArrayList<>();
persionList.add(new Persion("小明", 22, 2000.00));
//add()......
//查找工资大于2000的员工返回List,或set
List<Persion> pList = persionList.stream().filter(p -> p.getSalary()>2000).collect(Collectors.toList());
pList.forEach(System.out :: println);
//返回set集合
Set<Persion> collect = persionList.stream().filter(p -> p.getSalary() > 2000).collect(Collectors.toSet());
//返回Collection,根据toCollection中的类型来决定返回值的类型
ArrayList<Persion> collect1 = persionList.stream().filter(p -> p.getSalary() > 2000)
.collect(Collectors.toCollection(ArrayList::new));
}
Map<String, List<NewRoomStatusDataRespDTO>> map = respList.stream().collect(Collectors.groupingBy(NewRoomStatusDataRespDTO::getBldCd));
//返回集合中userName等于"aaa"的数据,如果不存在返回null;
User user = userList.stream().filter(u -> u.getUserName().equals("aaa")).findAny().orElse(null);
//获取集合中对象元素指定属性
List<String> orderNoList=list.stream().map(Order::getOrderNo).collect(Collectors.toList());
private List<RoomStatusAllDataRespDTO> generateRoomsAllStateResult(List<DayRoomsStateDTO> roomStateList) {
//1.value为原数据,重复key覆盖
Map<String, DayRoomsStateDTO> map1 = roomStateList.stream().collect(Collectors.toMap(DayRoomsStateDTO::getDate, Function.identity(), (oldKey, newKey) -> newKey));
//2.value为通过Stream数据封装出的类型(Map中的value为 RoomStateDTO是DayRoomsStateDTO::getRoom返回的数据类型),重复key覆盖
Map<String, RoomStateDTO> map2 = roomStateList.stream().collect(Collectors.toMap(DayRoomsStateDTO::getDate, DayRoomsStateDTO::getRoom, (oldKey, newKey) -> newKey));
//3.value为通过Stream数据封装出的类型,重复key放入list中
Map<String, List<RoomStateDTO>> map = roomStateList.stream().collect(Collectors.toMap(DayRoomsStateDTO::getDate,
dayRoomsStateDTO -> {
ArrayList<RoomStateDTO> list = new ArrayList<>();
list.add(dayRoomsStateDTO.getRoom());
return list;
},
(oldList, newList) -> {
oldList.addAll(newList);
return oldList;
}));
//4.转map并排序
TreeMap<String, List<Working>> collect =
workings.stream().collect(Collectors.toMap(Working::getInvoicePage,
e -> {
ArrayList<Working> list = new ArrayList<>();
list.add(e);
return list;
},
(oldList, newList) -> {
oldList.addAll(newList);
return oldList;
},
() -> new TreeMap<>(Comparator.comparing(Integer::valueOf))));
return null;
}
private List<OccupationDTO> getOccupationDTO(PmsOrderBean order, List<PmsOccupationGuest> occGuestList) {
if (CollectionUtils.isEmpty(occGuestList)) {
return null;
}
//1.由于三方返回订单信息以入住人为维度,先通过房间号进行分组
Map<String, List<PmsOccupationGuest>> guestMap = occGuestList.stream().collect(Collectors.groupingBy(PmsOccupationGuest::getRoomNo));
//2.转换为对应占房类型,并根据房间号去重
List<OccupationDTO> occupateionList = occGuestList.stream().map(occ -> {
return occ.convertOccupationDTO(order.getOrderState());
}).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<OccupationDTO>(Comparator.comparing(OccupationDTO::getRoomNo))), ArrayList::new));
//3.拿到占房结构信息后遍历,通过房间号获取分组中对应信息,填充入住人信息
occupateionList.forEach(occ -> {
List<GuestDTO> gList = guestMap.get(occ.getRoomNo()).stream().map(PmsOccupationGuest::convertGuestDTO).collect(Collectors.toList());
occ.setGuests(gList);
});
return occupateionList;
}