java 1.8 stream使用总结(个人总结有一些经典文章的集合)(三)

简介: java 1.8 stream使用总结(个人总结有一些经典文章的集合)(三)

收集


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);
            }
        }
    }
}


运行结果

[北京市, 北京市朝阳区, 北京市朝阳区黄渠, 北京市朝阳区来广营, 北京市东城区区, 北京市东城区区东直门, 北京市东城区区东花市, 北京市西城区, 北京市西城区德胜门]
相关文章
|
11天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
21 2
|
11天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
15天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
15天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
15天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
12 0
|
JavaScript 前端开发 Java
|
5天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
13天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
4天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
4天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
下一篇
无影云桌面