美文网首页
JDK8新特性(二)

JDK8新特性(二)

作者: 家hao | 来源:发表于2021-06-18 17:53 被阅读0次

一、方法引用与构造函数引用

  • 说明:方法引用是⼀种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已经存在的方法或构造方法
  • 通过方法引用,可以将方法的引⽤赋值给⼀个变量
  • 语法:左边是容器(可以是类名,实例名),中间是" :: ",右边是相应的方法名
    1. 静态方法,则是ClassName::methodName。如 Object ::equals
    2. 实例方法,则是Instance::methodName
    3. 构造函数,则是 类名::new;
  • 单个参数
    Function<入参1, 返回类型> func = 方法引用
    应用 func.apply(入参);
  • 两个参数
    BiFunction<入参1,入参2, 返回类型> func = 方法引用
    应用 func.apply(入参1,入参2);
class User {
    private String username;
    private Integer age;
    public User() {}
    public User(String username) {
        this.username = username;
    }
    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }
 }

public class Test{

    public static void main(String[] args) {
        // 使用双冒号::来构造静态函数引用
        Function<String, Integer> fun = Integer::parseInt;
        Integer value = fun.apply("1024");
        System.out.println(value);
        // 使用双冒号::来构造非静态函数引用
        String content = "测试使用";
        Function<Integer, String> func = content::substring;
        String result = func.apply(1);
        System.out.println(result);
        // 构造函数引用,多个参数
        BiFunction<String, Integer, User> biFunction = User::new;
        User user1 = biFunction.apply("Test", 28);
        System.out.println(user1.toString());
        //构造函数引用,单个参数
        Function<String, User> function = User::new;
        User user2 = function.apply("Test");
        System.out.println(user2.toString());
        // 函数引用也是一种函数式接用,可以将函数引用作为方法的参数
        sayHello(String::toUpperCase, "Test");
    }
    
    /**
     *
     * @param func 函数引用
     * @param param 对应的参数
     */
    private static void sayHello(Function<String, String> func, Stringparam) {
        String result = func.apply(param);
        System.out.println(result);
    }

}

二、JDK8之流Stream

  • Stream 中文称为 “流”,通过将集合转换为这么⼀种叫做 “流”的元素队列,通过声明性方式,能够对集合中的每个元素进行⼀系列并行或串行的流水线操作。
  • 元素是特定类型的对象,所以元素集合看作⼀种流, 流在管道中传输, 且可以在管道的节点上进行处理, ⽐如 排序,聚合,过滤等操作。


    image.png
  • 操作详情
    1. 数据元素便是原始集合,如List、Set、Map等
    2. 生成流,可以是串行流stream() 或者并行流 parallelStream()
    3. 中间操作,可以是 排序,聚合,过滤,转换等
    4. 终端操作,很多流操作本身就会返回⼀个流,所以多个操作可以直接连接起来,最后统⼀进行收集
List<String> list = Arrays.asList("aaaa","bbbb","cccc","dddd","eeee);
List<String> resultList = list.stream().map(obj->"遍历:"+obj).collect(Collectors.toList());
System.out.println(resultList);

三、JDK8之流操作map和filter函数

  • map函数
    1. 将流中的每⼀个元素 T 映射为 R(类似类型转换)
    2. 类似遍历集合,对集合的每个对象做处理
    3. 场景:转换对象,如javaweb开发中集合里面的DO对象转换为DTO对象
List<String> list = Arrays.asList("aaaa","bbbb","cccc","dddd","eeee);
List<String> resultList = list.stream().map(obj->"遍历:"+obj).collect(Collectors.toList());
System.out.println(resultList);
@Data
class User {
    private String name;
    private Integer age;
    public User(String name, Integer age) {
        this.name= name;
        this.age = age;
    }
}

@Data
class UserDTO {
    private String name;
    private Integer age;
    public User(String name, Integer age) {
        this.name= name;
        this.age = age;
    }
}

public class Test{
    public static void main(String[] args) {
        List<User> list = Arrays.asList(new User("peter",11),new User("jack",12),new User("tom",10),new User("marry",14));
        List<UserDTO> userDTOList = list.stream().map(obj->{
            UserDTO userDTO = new UserDTO(obj.getName(),obj.getAage());
            return userDTO;
        }).collect(Collectors.toList());
        System.out.println(userDTOList);
    }
}
  • filter函数
    1. 用于通过设置的条件过滤出元素
    2. 场景:主要用于筛选过滤出符合条件的元素
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
List<String> resultList = list.stream().filter(obj -> obj.length() >5).collect(Collectors.toList());
System.out.println(resultList);

四、JDK8之流操作limit和sorted函数

  • limit函数
    1. 截断流使其最多只包含指定数量的元素
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
//limit截取
List<String> resultList=list.stream().sorted(Comparator.comparing(String::length).reversed()).limit(3).collect(Collectors.toList());
System.out.println(resultList);
  • sorted函数
    1. sorted() 对流进⾏自然排序, 其中的元素必须实现Comparable 接口
    2. sorted(Comparator<? super T> comparator) 用来自定义升降序
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
List<String> resultList1 = list.stream().sorted().collect(Collectors.toList());
List<String> resultList2 = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
List<String> resultList3 = list.stream().sorted(Comparator.comparing(obj ->obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
List<String> resultList4 = list.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());

五、JDK8之流操作allMatch和anyMatch函数

  • allMatch函数
    1. 检查是否匹配所有元素,只有全部符合才返回true
List<String> list = Arrays.asList("springboot", "springcloud", "redis","git", "netty", "java", "html", "docker");
boolean flag = list.stream().allMatch(obj->obj.length()>1);
System.out.println(flag);
  • anyMatch函数
    1. 检查是否⾄少匹配⼀个元素
List<String> list = Arrays.asList("springboot", "springcloud", "redis","git", "netty", "java", "html", "docker");
boolean flag = list.stream().anyMatch(obj->obj.length()>18);
System.out.println(flag)

六、JDK8之流操作max和min函数

  • max和min函数
  1. 最大值和最小值
@Data
class Student {
    private int age;
    public Student(int age) {
        this.age = age;
    }
}

public class Test{
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(new Student(32),newStudent(33),new Student(21),new Student(29),new Student(18));
        //最大值
        Optional<Student> optional = list.stream().max((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
        //最小值
        Optional<Student> optional = list.stream().min((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
        System.out.println(optional.get().getAge());
    }
}

七、JDK8之并行流parallelStream

  • 为什么会有这个并行流
    1. 集合做重复的操作,如果使⽤串行执行会相当耗时,因此⼀般会采用多线程来加快, Java8的paralleStream用fork/join框架提供了并发执行能力。
    2. 底层原理
      (1) 线程池(ForkJoinPool)维护⼀个线程队列
      (2) 可以分割任务,将父任务拆分成子任务,完全贴合分治思想
//顺序输出
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.stream().forEach(System.out::println);
//并⾏乱序输出
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.parallelStream().forEach(System.out::println);
  • paralleStream并行是否⼀定比Stream串行快?
    1. 错误,数据量少的情况,可能串行更快,ForkJoin会耗性能
    2. 多数情况下并行比串行快,是否可以都用并行
      (1) 不行,部分情况会有线程安全问题,parallelStream里⾯使用的外部变量,比如集合⼀
      定要使用线程安全集合,不然就会引发多线程安全问题。
for(int i=0;i<10;i++) {
     //List list = new ArrayList();
    List list = new CopyOnWriteArrayList();
     IntStream.range(0, 100).parallel().forEach(list::add);
     System.out.println(list.size());
 }
image.png
image.png

八、JDK8之reduce操作

  • 什么是reduce操作

    1. 聚合操作,中文意思是 “减少”
    2. 根据⼀定的规则将Stream中的元素进行计算后返回⼀个唯⼀的值
  • 常用方法一

Optional<T> reduce(BinaryOperator<T> accumulator);

//accumulator 计算的累加器
//例子: 第⼀个元素相加和第⼆个元素相加,结果再和第三个元素相加,直到全部相加完成
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1+ item2).get();

//不⽤lambda的写法
int result = Stream.of(1,2,3,4,5).reduce(new BinaryOperator<Integer>() {
    @Override
    public Integer apply(Integer item1, Integer item2) {
        return item1 + item2;
    }
 }).get();
  • 常用方法二
T reduce(T identity, BinaryOperator<T> accumulator);

//identity ⽤户提供⼀个循环计算的初始值
//accumulator 计算的累加器
//例子: 100作为初始值,然后和第⼀个元素相加,结果在和第⼆个元素相加,直到全部相加完成
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum + item);
  • 例子应用
int value = Stream.of(1645, 234345, 32,44434,564534,435,34343542,212).reduce( (item1, item2) -> item1 > item2 ? item1 : item2 ).get();
System.out.println(value);

九、JDK8之集合的foreach

  • 集合遍历的方式
    1. for循环
    2. 迭代器 Iterator
  • 注意点
    1. 不能修改包含外部的变量的值
    2. 不能用break或者return或者continue等关键词结束或者跳过循环
  • Jdk8里面的新增接口
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
  • 使用案例
List<Student> results = Arrays.asList("aaaa","bbbb","ccccc","ddddd","eeeee");
results.forEach(obj->{System.out.println(obj.toString());});

十、JDK8之collector收集器

  • collect()方法的作用
    1. ⼀个终端操作, 用于对流中的数据进行归集操作,collect方法接受的参数是⼀个Collector
    2. 有两个重载方法,在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的作用
    1. 就是收集器,也是⼀个接口, 它的工具类Collectors提供了很多工厂方法
  • Collectors 的作用
    1. 工具类,提供了很多常见的收集器实现
      (1)Collectors.toList()
//ArrayList::new,创建⼀个ArrayList作为累加器
// List::add,对流中元素的操作就是直接添加到累加器中reduce操作, 对⼦任务归集结果addAll,后⼀个子任务的结果直接全部添加到前⼀个子任务结果中
// CH_ID 是⼀个unmodifiableSet集合
 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);
}
  1. Collectors.toMap()
  2. Collectors.toSet()
  3. Collectors.toCollection() :⽤⾃定义的实现Collection的数据结构收集
Collectors.toCollection(LinkedList::new)
Collectors.toCollection(CopyOnWriteArrayList::new)
Collectors.toCollection(TreeSet::new)

十一、JDK8之joining函数

  • 拼接函数 Collectors.joining
//3种重载⽅法
Collectors.joining()
Collectors.joining("param")
Collectors.joining("param1", "param2", "param3")
  • 其中⼀个的实现
public static Collector<CharSequence, ?, String> joining() {
    return new CollectorImpl<CharSequence, StringBuilder, String>(
        StringBuilder::new, StringBuilder::append,(r1, r2) -> { r1.append(r2); return r1; },StringBuilder::toString, CH_NOID);
 }
  • 该方法可以将Stream得到⼀个字符串, joining函数接受三个参数,分别表示 元素之间的连接符、前缀和后缀。
String result = Stream.of("springboot", "mysql", "html5","css3").collect(Collectors.joining(",", "[", "]"));

十二、JDK8之收集器 partitioningBy分组

  • Collectors.partitioningBy 分组,key是boolean类型
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? superT> predicate) {
    return partitioningBy(predicate, toList());
}
  • 例子: 根据list里面进行分组,字符串长度大于4的为⼀组,其他为另外⼀组
List<String> list = Arrays.asList("java", "springboot","HTML5","nodejs","CSS3");
Map<Boolean, List<String>> result = list.stream().collect(partitioningBy(obj -> obj.length() > 4));

十三、JDK8之收集器 group by分组

  • 分组 Collectors.groupingBy()
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<?super T, ? extends K> classifier) { 
    return groupingBy(classifier, toList());
}
  • 例子:根据学生所在的省份,进行分组
@Data
class Student {
    private String province;
    private int age;
    public Student(String province, int age) {
       this.age = age;
       this.province = province;
    }
}

public class Test{
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student("广东", 23), newStudent("广东", 24), new Student("广东", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
        Map<String, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
        listMap.forEach((key, value) -> {
            value.forEach(obj -> {
                System.out.println(obj.getAge());
            });
        });
    }
}

十四、JDK8之summarizing集合统计

  • summarizing 统计相关, 下面是summarizingInt的源码
  • 作用:可以⼀个方法把统计相关的基本上都完成
  • 分类
    1. summarizingInt
    2. summarizingLong
    3. summarizingDouble
public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) { 
    return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(IntSummaryStatistics::new,(r, t) -> r.accept(mapper.applyAsInt(t)),(l, r) -> { l.combine(r); return l; }, CH_ID);
}
  • 例子:统计学生的各个年龄信息
@Data
class Student {
    private String province;
    private int age;
    public Student(String province, int age) {
       this.age = age;
       this.province = province;
    }
}

public class Test{
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student("广东", 23), newStudent("广东", 24), new Student("广东", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
        IntSummaryStatistics summaryStatistics = students.stream().collect(Collectors.summarizingInt(Student::getAge));
        System.out.println("平均值:" + summaryStatistics.getAverage());
        System.out.println("人数:" + summaryStatistics.getCount());
        System.out.println("最大值:" + summaryStatistics.getMax());
        System.out.println("最小值:" + summaryStatistics.getMin());
        System.out.println("总和:" + summaryStatistics.getSum());
    }
}

十五、 JDK8 新的内存空间和异常处理

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

相关文章

  • JDK8新特性介绍

    JDK8新特性介绍 JDK8新特性:​ 1,Lambda表达式​ 2,新的日期API​ 3,引入Optional​...

  • JDK8新特性(二)

    一、方法引用与构造函数引用 说明:方法引用是⼀种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类...

  • jackson parser LocalDataTime 问题

    jackson parser LocalDataTime 问题 LocalDataTime 是 jdk8 的新特性...

  • 面试

    sql语句 jdk8新特性 lamed 测试单元测试

  • @FunctionalInterface函数式接口

    JDK8新特性:函数式接口@FunctionalInterface的使用说明

  • FunctionalInterface函数式接口

    关于jdk8的新特性函数式接口示例以及描述 代码示例

  • JDK8新特性

    Lambda语法 Lambda是什么? "Lambda表达式"(Lambda expression)是一个匿名函数...

  • jdk8新特性

    API:http://docs.oracle.com/javase/8/docs/api/ 新特性:http://...

  • JDK8 新特性

    为什么要学Java8 Java8让你的编程变得更容易 充分稳定的利用计算机硬件资源 Lambda lambda 是...

  • jdk8新特性

    Jdk8相对之前的jdk加入了很多的新特性。 1:jdk中加入了default关键字。 在java里面,我们通常都...

网友评论

      本文标题:JDK8新特性(二)

      本文链接:https://www.haomeiwen.com/subject/hpgcyltx.html