收集
collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
Collector<T, A, R> 是一个接口,有以下5个抽象方法:
Supplier < A>supplier():创建一个结果容器A
BiConsumer<A, T> accumulator():消费型接口,第一个参数为容器A,第二个参数为流中元素T。
BinaryOperator< A> combiner():函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各 个子进程的运行结果(accumulator函数操作后的容器A)进行合并。
Function<A, R> finisher():函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R。
Set characteristics():返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征:
CONCURRENT:表示此收集器支持并发。
UNORDERED:表示该收集操作不会保留流中元素原有的顺序。
IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。
public static void main(String[] args) { List<Integer> list=Arrays.asList(1,3,2); // 把list中的值累加起来 Stream<Integer> stream=list.stream(); Stream<Integer> stream1 =stream.filter(t-> t>1); System.out.println(stream1); System.out.println(stream1.collect(Collectors.toList())); //将 stream转换为一个list }
运行结果
java.util.stream.ReferencePipeline$2@254989ff [3, 2]
方法集合
Person p1 = new Person("zhangsan",26); Person p2 = new Person("lisi",22); Person p3 = new Person("wangwu",23); List<Person> list = Arrays.asList(p1,p2,p3); //装成list List<Integer> ageList = list.stream().map(Person::getAge).collect(Collectors.toList());//[26,22,22] //转成set Set<Integer> ageSet = list.stream().map(Person::getAge).collect(Collectors.toSet());//[26,22] //转成map,注:key不能相同,否则报错 Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Person::getName, Person::getAge)); // {zhangsan=26, lisi=22, wangwu=22} //字符串分隔符连接 String joinName = list.stream().map(Person::getName).collect(Collectors.joining(",", "(", ")")); // (zhangsan,lisi,wangwu) //聚合操作 //1.总数 Long count = list.stream().collect(Collectors.counting()); // 3 //2.最大年龄 (最小的minBy同理) Integer maxAge = list.stream().map(Person::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 26 //3.所有人的年龄求和 Integer sumAge = list.stream().collect(Collectors.summingInt(Person::getAge)); // 70 //4.平均年龄 Double averageAge = list.stream().collect(Collectors.averagingDouble(Person::getAge)); // 23.333333333333332 // 带上以上所有方法 DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Person::getAge)); System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage()); //分组 按年龄分组 Map<Integer, List<Person>> ageMap = list.stream().collect(Collectors.groupingBy(Person::getAge)); //分区 //分成两部分,一部分大于10岁,一部分小于等于10岁 Map<Boolean, List<Person>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10)); //规约 Integer allAge = list.stream().map(Person::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40
常见方法
排序操作 将空数据排序到最后 //根据age正序 Collections.sort(list, Comparator.comparing(Student::getAge, Comparator.nullsLast(Intrger::compareTo))); //根据age倒序 Collections.sort(list, Comparator.comparing(BondBsInfoListVo::getCompanyRank, Comparator.nullsLast(Intrger::compareTo)).reversed());
分组操作 //根据name进行分组 Map<String, List<Student>> studentMap = new HashMap<>(); list.stream().collect(Collectors.groupingBy(Student::getName)).forEach( (name, newList) -> { studentMap .put(name, newList); } );
skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream, 如果原Stream中包含的元素个数小于N,那么返回空Stream; list.stream().skip(index).collect(Collectors.toList());
limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素; list.stream().limit(index).collect(Collectors.toList());
分页操作 int pageNo = 1;//当前页数 int pageNo = 20;//每页显示条数 int start = (pageNo - 1) * pageSize; list = list.stream().skip(start).collect(Collectors.toList()); list = list.stream().limit(pageSize).collect(Collectors.toList());
filter:过滤; 过滤出年龄大于19的人: list.stream().filter(person -> (person.getAge() > 19)).collect(Collectors.toList());
map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗; List<Student> students = list.stream().map(person -> new Student(person.getName(), person.getAge())).collect(Collectors.toList()); List<String> names = list.stream().map(Person::getName).collect(Collectors.toList()); int[] ages = list.stream().mapToInt(Person::getAge).toArray();
累加、最大值、最小值、平均值等 //Integer List<Integer> list = new ArrayList<>(); list.add(3); list.add(7); list.add(2); IntSummaryStatistics collect = list.stream().map(Student::getAge).collect(Collectors.summarizingInt(value -> value)); System.out.println(collect); System.out.println("统计集合元素的个数:" + collect.getCount()); System.out.println("集合元素累加之和:" + collect.getSum()); System.out.println("集合中最小值:" + collect.getMax()); System.out.println("集合中最大值:" + collect.getMin()); System.out.println("集合中平均值:" + collect.getAverage()); 打印结果:IntSummaryStatistics{count=3, sum=12, min=2, average=4.000000, max=7} 统计集合元素的个数:3 集合元素累加之和:12 集合中最小值:7 集合中最大值:2 集合中平均值:4.0 //BigDecimal 假设Person中age为BigDecimal类型 Person p1 = new Person("张三", new BigDecimal("11.0")); Person p2 = new Person("王五", new BigDecimal("10.0")); Person p3 = new Person("李四", new BigDecimal("9.0")); Person p4 = new Person("王五", new BigDecimal("10.0")); Person p5 = new Person("赵六", new BigDecimal("10.0")); List<Person> list = new ArrayList<>(); list.add(p1); list.add(p2); list.add(p3); list.add(p4); list.add(p5); BigDecimal sum = list.stream().map(Person::getAge).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal max = list.stream().map(Person::getAge).reduce(BigDecimal.ZERO, BigDecimal::max); BigDecimal min = list.stream().map(Person::getAge).reduce(BigDecimal.ZERO, BigDecimal::min); System.out.println("年龄总计:" + sum); System.out.println("年龄最大:" + max); System.out.println("年龄最小:" + min); 打印结果: 年龄总计:50.0 年龄最大:11.0 年龄最小:9.0
多条件排序: //先根据age排序 在根据name排序 list.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getName));
count:计数; 统计年龄大于19的人的数量: long count = list.stream().filter(person -> (person.getAge() > 19)).count();
字段运算或求值 //int list.stream().mapToInt(Person::getAge).sum(); list.stream().mapToInt(Person::getAge).max(); list.stream().mapToInt(Person::getAge).min(); list.stream().mapToInt(Person::getAge).average(); //double list.stream().mapToDouble(Person::getAge).sum()//和 list.stream().mapToDouble(Person::getAge).max()//最大 list.stream().mapToDouble(Person::getAge).min()//最小 list.stream().mapToDouble(Person::getAge).average()//平均值 map.entrySet().removeIf(entry -> entry.getValue() == null);
本人附2个接触到的面试题;
代码
package com.example.demo; import lombok.Data; @Data public class Alarm { String id; String name; public Alarm(String id,String name){ this.id=id; this.name=name; } }
package com.example.demo; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; public class JavaDemo { public static void main(String[] args) { List<Alarm> listOld = new ArrayList<>(); List<Alarm> listNew = new ArrayList<>(); Alarm a = new Alarm("id1", "姓名1"); Alarm b = new Alarm("id2", "姓名2"); Alarm c = new Alarm("id3", "姓名3"); Alarm d = new Alarm("id4", "姓名4"); Alarm e = new Alarm("id4", "姓名4"); Alarm f = new Alarm("id3", "姓名5"); Alarm g = new Alarm("id2", "姓名3"); Alarm h = new Alarm("id5", "姓名1"); listOld.add(a); listOld.add(b); listOld.add(c); listOld.add(d); System.out.println("listOld==>" + listOld); listNew.add(e); listNew.add(f); listNew.add(g); listNew.add(h); System.out.println("listNew==>" + listNew); //------------------需求1---------------- //获取到 listOld 的中id列表 /*List<String> oldIdList = listOld.stream().map(Alarm::getId).collect(Collectors.toList()); System.out.println("oldIdList==>" + oldIdList); //根据listOld中的id列表筛选出 listNew中不存在的列表 List listNew1 = listNew.stream().filter(alarm -> !oldIdList.contains(alarm.getId())).collect(Collectors.toList()); System.out.println("listOld不存在的id数据为==>" + listNew1);*/ //------------------需求1--------------- //------------------需求2---------------- //创建变量 防止循环创建过多的对象 List<Alarm> listOld1; Alarm alarm1; List<Alarm> listnew1 = new ArrayList<>(); //遍历集合 listNew for (Alarm alarm : listNew) { //首先,获取到listOld的id,包含该次遍历过程中的listNew的id的集合 listOld1 = listOld.stream().filter(old-> old.getId().equals(alarm.getId())).collect(Collectors.toList()); //如果listOld1为空 则表示无id为相同的数据; if(listOld1 == null || listOld1.size() < 1){ //进行下一次的循环 continue; } //获取old中的数据进行name的对比 alarm1 = listOld1.get(0); //如果name不相同则加入集合,否则不做操作; if(!alarm1.getName().equals(alarm.getName())){ listnew1.add(alarm); } } System.out.println("id相同,name不同==>" + listnew1); //------------------需求2---------------- } }
运行结果可自行查看
listOld==>[Alarm(id=id1, name=姓名1), Alarm(id=id2, name=姓名2), Alarm(id=id3, name=姓名3), Alarm(id=id4, name=姓名4)] listNew==>[Alarm(id=id4, name=姓名4), Alarm(id=id3, name=姓名5), Alarm(id=id2, name=姓名3), Alarm(id=id5, name=姓名1)] id相同,name不同==>[Alarm(id=id3, name=姓名5), Alarm(id=id2, name=姓名3)]
代码
package com.example.demo2; import lombok.Data; import java.util.ArrayList; import java.util.List; @Data public class Location { private String name = ""; private List<Location> sublst = new ArrayList<>(); public Location(String str, List<Location> sub) { name = str; sublst = sub; } }
package com.example.demo2; import java.util.ArrayList; import java.util.List; public class DoTest { public static void main(String[] args) { List<Location> temp = new ArrayList<Location>(); temp.add(new Location("黄渠",null)); temp.add(new Location("来广营",null)); Location fj1 = new Location("朝阳区", temp); temp=new ArrayList<>(); temp.add(new Location("东直门",null)); temp.add(new Location("东花市",null)); Location fj2 = new Location("东城区区", temp); temp=new ArrayList<>(); temp.add(new Location("德胜门",null)); Location fj3 = new Location("西城区", temp); temp=new ArrayList<>(); temp.add(fj1); temp.add(fj2); temp.add(fj3); Location sj = new Location("北京市", temp); //你的方法 //最终输出的集合 List<String> list = new ArrayList<>(); //获取首层 也就是北京市的列表和名称 List<Location> sjj = sj.getSublst(); String name = sj.getName(); //把首层名称加入到集合中 list.add(name); //循环首层的子层 for (Location location : sjj) { //将首层名称+子层名称加起来 比如 北京市+朝阳区 String name1 = name + location.getName(); //获取子层的子层 比如朝阳区下有个来广营 List<Location> list1 = location.getSublst(); //开始递归 digui(name1, list1, list); } System.out.println(list); } public static void digui(String name, List<Location> list,List<String> nameList){ //首先将名称加入到集合中 nameList.add(name); //如果该地区没有子层 则表示为最终层 停止递归操作 比如来广营下并没有后续 if(list == null || list.size() < 1){ return; } //对地区进行循环 for (Location location : list) { //如果没有次子层 则添加到集合中 否则进 行递归操作 if(location.getSublst() == null || location.getSublst().size() < 1){ nameList.add(name+location.getName()); }else{ //将名称加起来 比如北京市+朝阳区 name = name+ location.getName(); //继续递归 比如朝阳区下还有来广营 digui(name, location.getSublst(), nameList); } } } }
运行结果
[北京市, 北京市朝阳区, 北京市朝阳区黄渠, 北京市朝阳区来广营, 北京市东城区区, 北京市东城区区东直门, 北京市东城区区东花市, 北京市西城区, 北京市西城区德胜门]