【Java基础】JDK8新特性最佳实践3

简介: 【Java基础】JDK8新特性最佳实践3

8.Collector收集器和集合统计

8.1.collector收集器

  • collect()方法的作用
  • 一个终端操作,用于对流中的数据进行归集操作,collect方法接收的参数是一个Collector
  • 有两个方法重载,在Stream接口里面
//重载方法一 
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R>combiner);  
//重载方法二
<R, A> R collect(Collector<? super T, A, R> collector)
  • Collector的作用
  • 就是收集器,也是一个接口,它的工具类Collectors提供了很多工厂方法
  • Collectors的作用
  • 提供了很多常见的集合的收集
  • Collectors.toList()
public static <T> Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>(
        (Supplier<List<T>>) ArrayList::new,
        List::add,
        (left, right) -> { 
            left.addAll(right); 
            return left; },
        CH_ID
    );
}
  • ArrayList::new,创建一个ArrayList作为累加器
  • List::add,对流中的元素直接加到累加器中
  • reduce,对子任务归集结果直接全部添加到前一个子任务结果中
  • CH_ID是一个unmodifableSet集合

常见的收集器

  • Collector.toMaps():创建一个map收集器
  • Collector.toSet():创建一个set收集器
  • Collector.toCollection():自定义收集器
  •              Collector.toCollection(LinkedList::new)
  •              Collector.toCollection(TreeSet::new)

8.2.joining函数

  • 拼接函数,将集合内的元素按照一定规则拼接起来,Collectors.joining()
//三种重载方法
Collectors.joining() //无参数默认按照空字符拼接
Collectors.joining("-") //一个参数,按照“-”进行分割
Collectors.joining("-","{","}") //三个参数,第一个为分隔符,后两个为前缀后缀
  • 源码

baefce4b36d74d30bd71266ad09e052d.jpeg

38641759913942099f90e2c27584dc07.jpeg

319d759ec4f64e4983b8ae8f6cdc21f5.jpeg

  • 测试
List<String> list = Arrays.asList("SpringBoot","Docker","Java","SpringCloud","Netty");
String collect1 = list.stream().collect(Collectors.joining());
System.out.println(collect1);
String collect2 = list.stream().collect(Collectors.joining("-"));
System.out.println(collect2);
String collect3 = list.stream().collect(Collectors.joining("-", "{", "}"));
System.out.println(collect3);

f06592ff01bd4551a2af247a7a7a7583.jpeg

8.3.partitioningBy分组

  • Collectors.partitioningBy()会根据筛选条件进行分组,返回一个Map<Boolean,List>类型,boolean为true的表示符合条件的,false的为不符合筛选条件的。
  • 源码

 b5e617ce444e4955933cc39c7de82be3.jpeg  

  • 测试
List<String> list = Arrays.asList("Java","SpringBoot","HTML5","CSS3");
Map<Boolean, List<String>> collect = list.stream().collect(Collectors.partitioningBy(obj -> obj.length() > 4));
System.out.println(collect);

3bbf4f38f7954a25ad865e3d8d7ed5e6.jpeg

8.4.groupingBy分组

  • Collectors.groupingBy(),会根据实体Bean的某个属性进行分组,更实用,返回的是Map<String,List>,key为要分组的实体Bean的属性值
  • 源码

dbebeb6b6c1d4bd7bb5323c8fa25e705.jpeg

d79fe376a7664616898599f8ea3a2bdd.jpeg

  • 测试
List<Student> students = Arrays.asList(
      new Student("lx", 23, "北京"),
      new Student("ls", 24, "天津"),
      new Student("zs", 23, "⼴东"),
      new Student("ww", 22, "⼴东"),
      new Student("ld", 20, "北京"),
      new Student("xs", 20, "⼴东"),
      new Student("ok", 25, "北京"));
Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
//第二种方式
//Map<String, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(Student::getProvince));
        collect.forEach((key,value) -> {
            System.out.println("----"+key);
            value.forEach(obj-> System.out.println(obj));
        });

8a4680ddcaaf40848476f82be41014cb.jpeg

8.5.counting函数

  • 用于统计groupingBy于分组之后,每组元素的个数
  • 源码

7ab02017a45645eab9d7b28ba8885a3f.jpeg

  • 测试
List<Student> students = Arrays.asList(
       new Student("lx", 23, "北京"),
       new Student("ls", 24, "天津"),
       new Student("zs", 23, "⼴东"),
       new Student("ww", 22, "⼴东"),
       new Student("ld", 20, "北京"),
       new Student("xs", 20, "⼴东"),
       new Student("ok", 25, "北京"));
Map<String, Long> collect1 = students.stream().collect(Collectors.groupingBy(Student::getProvince, Collectors.counting()));
collect1.forEach((key,value) -> {
     System.out.println("---"+key);
     System.out.println("---"+value);
});

55944b8c2806440bbd3f5c0cde14b641.jpeg

8.6.summarizing集合统计

  • 集合相关的统计都能实现,根据实体Bean的某个属性进行统计,求最大值,最小值,总和等等
  • 分类
  • summarizingInt
  • summarizingLong
  • summarizingDouble
  • 测试,统计各个学生的年龄信息
IntSummaryStatistics collect = students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println("平均值:"+collect.getAverage());
System.out.println("总人数:"+collect.getCount());
System.out.println("年龄总和:"+collect.getSum());
System.out.println("最大值:"+collect.getMax());
System.out.println("最小值:"+collect.getMin());

cf3cb39e42a54fc689bba85786f3a31a.jpeg

9.Collection和Lambda实战

(1)需求:求两个集合的交集、差集、去重并集,两集合的各自平均值,总和

(2)创建两个集合

//总价 35
List<VideoOrder> videoOrders1 = Arrays.asList( new VideoOrder("20190242812", "springboot教程", 3), new VideoOrder("20194350812", "微服务SpringCloud", 5), new VideoOrder("20190814232", "Redis教程", 9), new VideoOrder("20190523812", "⽹⻚开发教程", 9), new VideoOrder("201932324", "百万并发实战Netty", 9));
//总价 54
List<VideoOrder> videoOrders2 = Arrays.asList( new VideoOrder("2019024285312", "springboot教程", 3), new VideoOrder("2019081453232", "Redis教程", 9), new VideoOrder("20190522338312", "⽹⻚开发教程", 9), new VideoOrder("2019435230812", "Jmeter压⼒测试", 5), new VideoOrder("2019323542411", "Git+Jenkins持续集成", 7), new VideoOrder("2019323542424", "Idea全套教程", 21));

(3)注意一点要重写equals和hashcode方法

@Override
public boolean equals(Object o) {
    if(o instanceof VideoOrder){
        VideoOrder o1 = (VideoOrder)o;
        return this.title.equals(o1.title);
    }
    return super.equals(o);
}
@Override
public int hashCode() {
    return title.hashCode();
}

(4)计算两个集合的交集

List<VideoOrder> clist = videoOrder1.stream().filter(videoOrder2::contains).collect(Collectors.toList());

(5)计算两个集合的差集

List<VideoOrder> nclist = videoOrder1.stream().filter(obj -> !videoOrder2.contains(obj)).collect(Collectors.toList());

(6)计算两个集合的去重并集

List<VideoOrder> allList = videoOrder1.paralleStream().distinct().collect(Collectors.toList());
allList.addAll(videoOrder2);

(7)计算订单价格的平均值

double avg = videoOrder1.stream().collect(Collectors.averagingInt(VideoOrder::getMoney)).doubleValue();

(8)计算订单价格的总和

Integer sum = videoOrders1.stream().collect(Collectors.summingInt(VideoOrder::getMoney));

c93322dd4d1a4640a5282719775d07fd.jpeg

10.内存空间和异常处理

10.1.新内存空间Matespace

  • JVM 种类有很多,⽐如 Oralce-Sun Hotspot, Oralce JRockit, IBM J9, Taobao JVM,我们讲的是Hotspot才有,JRockit以及J9是没有这个区域
  • JVM内存JDK8之前的HotSpot JVM,有个区域叫做”永久代“(permanent generation),通过在命令行设置参数:-XX:MaxPermSize来设定永久代最大可分配的内存空间
  • 如果JDK8中设置了PermSize和Max PermSize会被忽略并且警告
  • 作用:该块内存主要是被JVM用来存放class和mate信息的,当class被加载loader的时候会被存储到该内存区中,入方法的编译信息及字节码、常量池和符号解析、类的层级信息,字段、名字等
  • java.lang.OutOfMemoryError: PermGen space
  • 异常原因:永久代空间不够,可能类太多导致
  • JDK8使用本地内存存储类元数据信息,叫做元空间(Metaspcae)
  • 在默认情况下Metaspcae的大小至于本地内存大小有关系
  • 常⽤的两个参数
  • -XX:MetaspaceSize=N 指Metaspace扩容时触发FullGC的初始化阈值
  • -XX:MaxMetaspaceSize=N 指⽤于限制Metaspace增⻓的上限,防⽌因为某些情况导致Metaspace⽆限的使⽤本地内存
  • 不管两个参数如何设置,都会从20.8M开始,然后随着类加载越来越多不断扩容调整直到最⼤
  • 查看MetaspaceSize的大小
  • jstat -gc pid

10.2.try-with-resources(JDK7)

  • 自动关流
  • jdk7之前处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        OutputStream outputStream = new FileOutputStream(filePath);
        try {
            outputStream.write((filePath+"学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • jdk7之后处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        //自动关流,当有多个文件时,直接用;分割就可以
        try (OutputStream outputStream = new FileOutputStream(filePath)){
            outputStream.write((filePath + "学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 实现了AutoCloseable接口的类,在try()里面声明该类实例的时候,try结束后自动i盗用的close方法,这个动作会早于finally里面调用的方法。
  • 不管是否出现异常,try()里面的实例都会被调用close方法。
  • try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被关掉。
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        OutputStream outputStream = new FileOutputStream(filePath);
        try {
            outputStream.write((filePath+"学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • jdk7之后处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        //自动关流,当有多个文件时,直接用;分割就可以
        try (OutputStream outputStream = new FileOutputStream(filePath)){
            outputStream.write((filePath + "学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 实现了AutoCloseable接口的类,在try()里面声明该类实例的时候,try结束后自动i盗用的close方法,这个动作会早于finally里面调用的方法。
  • 不管是否出现异常,try()里面的实例都会被调用close方法。
  • try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被关掉。
相关文章
|
1月前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
16天前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
26天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
22天前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
39 7
|
20天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
20天前
|
Java
Java 异常处理:11 个异常处理最佳实践
本文深入探讨了Java异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理异常、不忽略异常、抛出具体异常、正确包装异常、记录或抛出异常但不同时执行、不在finally中抛出异常、避免用异常控制流程、使用模板方法减少重复代码、抛出与方法相关的异常及异常处理后清理资源等内容,旨在提升代码质量和可维护性。
|
25天前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
41 6
|
25天前
|
Java 数据库连接 开发者
Java中的异常处理机制:深入解析与最佳实践####
本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####
|
26天前
|
运维 Java 编译器
Java 异常处理:机制、策略与最佳实践
Java异常处理是确保程序稳定运行的关键。本文介绍Java异常处理的机制,包括异常类层次结构、try-catch-finally语句的使用,并探讨常见策略及最佳实践,帮助开发者有效管理错误和异常情况。
80 4
|
27天前
|
Oracle 安全 Java
深入理解Java生态:JDK与JVM的区分与协作
Java作为一种广泛使用的编程语言,其生态中有两个核心组件:JDK(Java Development Kit)和JVM(Java Virtual Machine)。本文将深入探讨这两个组件的区别、联系以及它们在Java开发和运行中的作用。
69 1