JDK8 新特性

本贴最后更新于 1584 天前,其中的信息可能已经渤澥桑田

概述

  • 语法变化

    • Lamada 表达式
    • Default 方法
    • 重复注解
    • 扩展注解支持
  • 集合

    • 新增 Stream 流
    • HashMap 性能提升
  • 安全方面

    • 客户端 TLS 1.2 默认启用;
    • Sha-224 消息摘要;
    • 对高熵随机数生成的更好支持;
    • 持 Kerberos 5 协议转换和受限代理。
    • ...
  • 工具

    • 提供 jjs 命令来调用 Nashorn 引擎;
    • Jdeps 命令行工具用于分析类文件;
    • JMX 提供远程访问诊断命令。
  • 国际化

    • Unicode 增强,包括对 Unicode 6.2.0 的支持;
    • 新的日历和语言环境 API;
    • 可安装自定义资源包。
  • 新增日期处理包

  • IO 和 NIO

    • 减小 <JDK_HOME>/jre/lib/charsets.jar 文件大小;
    • java.lang.String(byte[], *)和 java.lang.String.getBytes()性能提升。
  • 新增工具类

    • 并行数组排序;
    • Base64 编码解码;
    • 无符号算术支持 。
  • 网络

    • 新增 java.net.URLPermission;
    • 在 java. net 类中。 如果安装了安全管理器,则 HttpURLConnection 调用打开连接的请求需要权限。
  • 并发

    • 添加新的类和接口

JDK8 之 default 关键字

在 jdk1.8 以前接口里面是只能有抽象 ⽅法,不能有任何 ⽅法的实现。jdk1.8 ⾥ ⾯打破了这个规定,引入了新的关键字 default,使用 default 修饰方法,可以在接口里面定义具体的方法实现。

  • 默认方法:接口里面定义一个默认方法,这个接口的实现类实现了这个接口之后,不用管这个 default 修饰的方法就可以直接调调用,即接口方法的默认实现
  • 静态方法: 接口名.静态方法来访问接口中的静态方法。
public interface StudentService {

    /**
     * JAVA8中新增default关键字
     */
    default void test()
    {
        System.out.print("hello world");
    }


    static void test1() {
        System.out.println("这是静态⽅法");
    }
}


JDK8 之 base64 加解密 API

Jdk1.8 的 java.util 包中,新增了 Base64 的类。相比于传统 sun.misc 和 Apache Commons Codec 效率较高,不用导包。

public class Base64Demo {

    /**
     * java 8新增 base64编码解码
     * @param args
     * @throws UnsupportedEncodingException
     */
    public static void main(String[] args) throws UnsupportedEncodingException {
        Base64.Encoder encoder = Base64.getEncoder();
        Base64.Decoder decoder = Base64.getDecoder();

        byte[] src = "hello world".getBytes();
        String encodeData = encoder.encodeToString(src);
        System.out.println("编码数据:"+encodeData);

        System.out.println("解码数据:"+ new String(decoder.decode(encodeData),"UTF-8"));
    }
}

JDK8 之时间日期处理类

JAVA8 新增 LocalDate、LocalTime、LocalDateTime 日期处理类,LocalDate 只精确到天、LocalTime 只包含具体时间(时分秒)、LocalDateTime 包含日期和时间。新增 DateTimeFormatter(线程安全)和 Duration 对时间的处理变得极为方便,具体使用如下。

class LocalDateDemo {

    public static void main(String[] args) throws InterruptedException {

        /**
         * LocalDate不包含具体时间(小时、分、秒),只有日期
         */
        LocalDate localDate = LocalDate.now();

        System.out.println("当前时间:"+ localDate);
        System.out.println("当前月份"+localDate.getMonthValue());

        //增加
        LocalDate newLocalDate = localDate.plusYears(2);
        System.out.println("增加的时间"+newLocalDate);

        //减小
        LocalDate minLocalDate = localDate.minusYears(66);
        System.out.println("减小的时间"+minLocalDate);

        //修改月份
        LocalDate localDate1 =localDate.withMonth(5);
        System.out.println(localDate1);

        LocalDateTime localDateTime = LocalDateTime.now();
        Thread.sleep(1111);
        System.out.println(localDateTime.isAfter(LocalDateTime.now()));


        //DateTimeFormatter线程安全
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String ldtStr = dtf.format(ldt);
        System.out.println(ldtStr);

        //时间比较
        LocalDateTime today = LocalDateTime.now();
        System.out.println(today);
        LocalDateTime changeDate = LocalDateTime.of(2020,10,1,10,40,30);
        System.out.println(changeDate);
        Duration duration = Duration.between( today,changeDate);//第⼆个参数减第⼀个参数

        System.out.println(duration.toDays());//两个时间差的天数
        System.out.println(duration.toHours());//两个时间差的⼩时数
        System.out.println(duration.toMinutes());//两个时间差的分钟数
        System.out.println(duration.toMillis());//两个时间差的毫秒数
        System.out.println(duration.toNanos());//两个时间差的纳秒数


    }
}

JDK8 之 Lambda 表达式

在 JDK8 之前,Java 是不志持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为 ⼀个参数进 行传递, ⾯向对象编程是对数据的抽象,⽽函数式编程则是对 行为的抽象(将行为作为 ⼀个参数进行传递)。
lambda 表达式 使 ⽤场景(前提):⼀个接 ⼝中只包含 ⼀个方法,则可以使 ⽤ Lambda 表达式,这样的接口称之为“函数接口” 语法: (params) -> expression。

public class LamadaDemo {

    public static void main(String[] args) {

        /**
         * JDK8之前创建线程
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        });

        //JDK8
        new Thread(()->System.out.println("hello world"));


        //JDK8之前排序
        List<String> list = Arrays.asList("aaa","ggg","ffff","ccc");
        Collections.sort(list, new Comparator<String>() {
                    @Override
                    public int compare(String a, String b) {
                        return b.compareTo(a);
                    }
                }
        );
        for (String string : list) {
            System.out.println(string);
        }

        //JDK8排序
        Collections.sort(list, (a,b)->b.compareTo(a)
        );
        for (String string : list) {
            System.out.println(string);
        }

        
    }
}

自定义函数编程
定义一个函数式接口:

//声明这是一个函数式接口
@FunctionalInterface
public interface MyLamada<R,T> {
    R operator(T t1,T t2);
}

测试:

public class MyLamadaTest {

    public static void main(String[] args) throws Exception {
        System.out.println(operator(20, 5, (Integer x, Integer y) -> {
            return x * y;
        }));
        System.out.println(operator(20, 5, (x, y) -> x + y));
        System.out.println(operator(20, 5, (x, y) -> x - y));
        System.out.println(operator(20, 5, (x, y) -> x / y));
    }
    public static Integer operator(Integer x, Integer y,
                                   MyLamada<Integer, Integer> of) {
        return of.operator(x, y);
    }
}

JDK8 函数式编程

Lambda 表达式必须先定义接口,创建相关 ⽅法之后才可使用,这样做 ⼗分不便,其实 java8 已经内置了许多接口, 例如下面四个功能型接口,所以 ⼀般很少会由用户去定义新的函数式接口。Java8 内置的四大核心函数式接口:

  1. Consumer : 消费型接口:有入参,无返回值
  2. Supplier : 供给型接口:无入参,有返回值
  3. Function<T, R> : 函数型接口:有入参,有返回值
  4. Predicate : 断言型接口:有入参,有返回值,返回值类型确定是 boolean
public class FunctionDemo {

    public static void main(String[] args) {
        //声明function函数
        Function<Integer,Integer> function = p->p*10;
        System.out.println(function.apply(99));

        //自定义function函数,只能穿一个参数
        MyFunction<String,String> myFunction = new MyFunction<>();
        System.out.println(myFunction.apply("xw study"));

        //BiFunction支持传两个参数
        BiFunction<String,String,String> biFunction = (a,b)->a+b;
        System.out.println(biFunction.apply("a","b"));


    }
}


/**
 * @author by xw
 * @Description predicate有入参,有返回值,返回类型是boolean类型
 */
public class PredicateDemo {
    public static void main(String[] args) {
        List<String> list =
                Arrays.asList("awewrwe","vdssdsd","aoooo","psdddsd");
        List<String> results = filter(list,obj->obj.startsWith("a"));
        System.out.println(results);
    }
    public static List<String> filter(List<String> list,
                                      Predicate<String> predicate) {
        List<String> results = new ArrayList<>();
        for (String str : list) {
            if (predicate.test(str)) {
                results.add(str);
            }
        }
        return results;
    }
}




/**
 * @author by xw
 * @Description supplier只有返回值,没有入参
 */
public class SupplierDemo {
    public static void main(String[] args) {
        //Student student = new Student();
        Student student = newStudent();
        System.out.println(student.getName());
    }
    public static Student newStudent(){
        Supplier<Student> supplier = ()-> {
            Student student = new Student();
            student.setName("默认名称");
            return student;
        };
        return supplier.get();
    }

    static class Student{
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
}

public class ConsumerDemo {

    public static void main(String[] args) throws Exception {
        Consumer<String> consumer = obj->{
            System.out.println(obj);
            System.out.println("调⽤短信接⼝发送短信,或者打印⽇志");
        };

        sendMsg("8888888",consumer);
    }
    public static void sendMsg(String phone, Consumer<String> consumer){
        consumer.accept(phone);
    }
}

未完待续。。。。。
项目地址:项目地址

JDK8 之 Stream 流

Stream 中 ⽂称为 “流”,通过将集合转换为这么 ⼀种叫做 “流”的元素队列,通过声明性方式, 能够对集合中的每个元素进 行一系列并行或串行的流水线操作。
操作过程

  1. 数据元素便是原始集合,如 List、Set、Map 等
  2. ⽣成流,可以是串行流 stream() 或者并行流 parallelStream()
    3.中间操作,可以是 排序,聚合,过滤,转换等
  3. 终端操作,很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,最后统一进行收集

函数详解

map 函数

  • 作用:将流中的每 ⼀个元素 T 映射为 R(类似类型转换)
  • 应用场景: 开发中 Do 转 Dto
private void mapTest()
    {
        List<User> list = Arrays.asList(new User(1,"⼩东","123"),new
                        User(21,"jack","rawer"),
                new User(155,"tom","sadfsdfsdfsd"),
                new User(231,"marry","234324"),new User(100,"2222","122223"));
        List<UserDTO> userDTOList = list.stream().map(obj->{
            UserDTO userDTO = new UserDTO(obj.getId(),obj.getName());
            return userDTO;
        }).collect(Collectors.toList());
        System.out.println(userDTOList);

    }

filter 函数

  • 作用:⽤于通过设置的条件过滤出元素
// 过滤长度大于5的
 private void filterTest() {
        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);
    }

sorted 函数

作用:sorted() 对流进 ⾏排序, 其中的元素必须实现 Comparable 接口

private void sortdTest() {
        //自然排序
        List<String> list = Arrays.asList("springboot", "springcloud",
                "redis", "git", "netty", "java", "html", "docker");
        List<String> resultList =
                list.stream().sorted().collect(Collectors.toList());

        //根据⻓度顺序进⾏排序
        resultList =
                list.stream().sorted(Comparator.comparing(obj ->
                        obj.length())).collect(Collectors.toList());
        //逆序排序
        resultList =
                list.stream().sorted(Comparator.comparing(obj ->
                        obj.length(), Comparator.reverseOrder())).collect(Collectors.toList()
                );
        // 逆序排序,根据effective java规范一般来说在stream表达式中,引用优先于lamada表达式使用。
        resultList =
                list.stream().sorted(Comparator.comparing(String::length).reversed()
                ).collect(Collectors.toList());
        System.out.println(resultList);
    }

limit 函数

作用:截断流使其最多只包含指定数量的元素。

private static void limitTest() {
        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());

        // result  [springcloud, springboot, docker]
        System.out.println(resultList);
    }

allMatch 和 anyMatch

allMatch 检查是否匹配所有元素,只有全部符合才返回 true。anyMatch 检查是否至少匹配一个元素。

private static void anyMatchAndAllMatchTest()
    {
        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);

        flag = list.stream().anyMatch(obj->obj.length()>18);
        System.out.println(flag);
    }

min 和 max 函数

private static void minAndMaxTest() {
        List<Student> list = Arrays.asList(new Student(32), new
                Student(33), new Student(21), new Student(29), new Student(18));
        
        //求最大值
        Optional<Student> optional = list.stream().max(Comparator.comparingInt(Student::getAge));
        System.out.println(optional.get().getAge());
        
        //求最小值
        optional = list.stream().min(Comparator.comparingInt(Student::getAge));
        System.out.println(optional.get().getAge());
    }

JDK8 之 Optional 类

  • 作用
    • 解决空指针异常
  • 创建
    • of()方法,null 值作为参数传递进去,则会抛异常
       Optional opt = Optional.of(user);
      
    • ofNullable() ,如果对象即可能是 null 也可能是 ⾮ null,应该使 ⽤ ofNullable() ⽅法
       Optional opt = Optional.ofNullable(user);
      
    • orElse()如果有值则返回该值,否则返回传递给它的参数值
package jdk8.optional;


import java.util.Optional;

public class Demo {

    public static void main(String[] args) {

        User user = null;

        // 如果user是null的话,下面这句话会报错。
        //Optional<User> opt = Optional.of(user);

        //  orElse()如果有值则返回该值,否则返回传递给它的参数值
        User user1 = new User("1");
        User user2 = new User("2");
        /*
        如果值存在则isPresent()⽅法会返回true,调⽤get()⽅法会返回该对象⼀般使⽤get之前需要
        先验证是否有值,不然还会报错*/
        Optional<User> opt = Optional.ofNullable(user);
        Optional<User> opt1 = Optional.ofNullable(user1);
        System.out.println("opt " + opt.isPresent());          //false
        System.out.println("opt1 " + opt1.isPresent());       //true
        System.out.println(Optional.ofNullable(user1).orElse(user2));  //user1
    }
}

reduce 函数

作用:聚合函数,根据 ⼀定的规则将 Stream 中的元素进行计算后返回 ⼀个唯一的值。

int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();

foreach 函数

作用:循环遍历集合

List results = Arrays.asList(new Student(32),new Student(33),new Student(21),new Student(29),new Student(18));
results.forEach(obj->{ System.out.println(obj.toString()); });

注意点:

  • 不能修改包含外部的变量的值
  • 不能 ⽤ break 或者 return 或者 continue 等关键词结束或者跳过循环

collector 收集器

作用:⼀个终端操作, ⽤于对流中的数据进 ⾏归集操作。

 private static  void collectTest()
    {
        List<Integer> a =Arrays.asList(1,2,3);
        List<Integer> b = a.stream().collect(Collectors.toList());
        Set<Integer> c = a.stream().collect(Collectors.toSet());
        
    }

joining 函数

作用:拼接函数

 /**
     * 该⽅法可以将Stream得到⼀个字符串, joining函数接受三个参数,分别表示 元素之间的连
     * 接符、前缀和后缀。
     */
    private static void joiningTest()
    {

        //3种重载⽅法
       /* Collectors.joining()
        Collectors.joining("param")
        Collectors.joining("param1", "param2", "param3")*/

        String result = Stream.of("springboot", "mysql", "html5",
                "css3").collect(Collectors.joining(",", "[", "]"));
        System.out.println(result); //[springboot,mysql,html5,css3]

    }

partitioningBy 分组

Collectors.partitioningBy 分组,key 是 boolean 类型。

 private static void parttitionByTest()
    {
        List<String> list = Arrays.asList("java", "springboot",
                "HTML5","nodejs","CSS3");
        Map<Boolean, List<String>> result =
                list.stream().collect(partitioningBy(obj -> obj.length() > 4));
        System.out.println(result);
        
        //key是 false 和true
        //result 
       //{false=[java, CSS3], true=[springboot, HTML5, nodejs]}

    }

group by 分组

 private static void groupbyingTest()
    {
        List<Student> students = Arrays.asList(new Student("⼴东", 23), new
                Student("⼴东", 24), new Student("⼴东", 23),new Student("北京", 22), new
                Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
        Map<String, Long> listMap =
                students.stream().collect(Collectors.groupingBy(Student::getProvince,
                        Collectors.counting()));
        listMap.forEach((key, value) -> {System.out.println(key+"省⼈数有"+value);});
    }

summarizing 集合统计

summarizing 统计相关。

private static void summarizingTest() {
        List<Student> students = Arrays.asList(new Student("⼴东", 23), new
                Student("⼴东", 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 之新的内存空间

元空间(Metaspace)

在 JDK8 及版本,有个区域叫做“永久代(permanent generation), 通过 在命令 ⾏设置参数-XX:MaxPermSize 来设定永久代最 ⼤可分配的内存空间。该块内存主要是被 JVM ⽤来存放 class 和 mate 信息的,当 class 被加载 loader 的时候就会 被存储到该内存区中,如 ⽅法的编译信息及字节码、常量池和符号解析、类的层级信息,字段,名字等

在 JDK8 使用本地内存来存储类元数据信息,叫做元空间,另外将常量及静态变量移到堆中,元空间并不在虚拟机中,存储在本地内存里面,在默认的情况下 Metaspace 的大小只与本地内存有关。默认不设置元空间大小的话会自动扩张,设置带下命令
-XX: MaxPermSize

优点:

  • 原来的字符串存在永久代中,容易出现性能问题和内存溢出。
  • 类及方法的信息难以确定,指定永久代的大小比较困难,太小导致出现永久代溢出,太大容易导致老年代溢出。
  • 永久代 GC 效率低

参考文档:

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...