首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【原创】万字长文带你了解 JDK8 - JDK13 的新特性

【原创】万字长文带你了解 JDK8 - JDK13 的新特性

作者头像
良月柒
发布2020-04-14 14:44:45
8500
发布2020-04-14 14:44:45
举报

某次面试中,面试官问到我这个问题,只勉强说出了 JDK 8 的部分特性,今天就来盘一盘!

画外音:JDK 8 就是 JDK 1.8 版本的意思,后续同理。

JDK 8 新特性

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

1. 接口增强,default,static 关键字

在 JDK 8 之前接口中只能使用抽象方法,而不能有任何方法的实现。

JDK 8 里面则可以声明 default 和 static 修饰的方法。

/**
 * jdk8中接口可以使用声明default和static修饰的方法
 * static修饰的方法和普通的方法一样,可以被直接调用
 * default修饰的方法有方法体,就和普通的方法一样,可以被重写,有点像抽象类的方法一样,但是java是单继承多实现的
 */
public interface Today {

    void dream();

    void striver();

    default void victory(){
        System.out.println("公众号:程序员的成长之路");
    }

    static void test(){
        System.out.println("接口里的静态方法");
    }

    // jdk9 中还新增了private方法
    private void test3() {
        System.out.println("私有方法");
    };
}

2.Base64 API

Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64 就是一种基于 64 个可打印字符来表示二进制数据的方法,基于 64 个字符 A-Z,a-z,0-9,+,/ 的编码方式,是一种能将任意二进制数据用 64 种字元组合成字符串的方法。

JDK 8 以前的写法

编码和解码的效率比较差,公开信息说以后的版本会取消这个方法。

BASE64Encoder encoder = new BASE64Encoder();
BASE64Decoder decoder = new BASE64Decoder();
byte[] textByte = "公众号:程序员的成长之路".getBytes("UTF-8");
//编码
String encodedText = encoder.encode(textByte);
//5Zyj6a2U5a+85biI(类似这样的)
System.out.println(encodedText);
//解码 
//公众号:程序员的成长之路
System.out.println(new String(decoder.decodeBuffer(encodedText),"UTF-8"));

JDK 8 的写法

编解码效率远大于 sun.misc 和 Apache commons Codec,可以自己动收压测一下速度。

Base64.Decoder decoder2 = Base64.getDecoder();
Base64.Encoder encoder2 = Base64.getEncoder();
byte[] textByte2 = "公众号:程序员的成长之路".getBytes("UTF-8");
//编码
String encodedText2 = encoder2.encodeToString(textByte2);
//5Zyj6a2U5a+85biI(类似这样的)
System.out.println(encodedText);
//解码 
//公众号:程序员的成长之路
System.out.println(new String(decoder2.decode(encodedText2), "UTF-8"));

3.日期处理类

JDK 8 之前,SimpleDateFormate,Calendar 等类 API涉及比较差,涉及的比较差,日期时间的计算,比较都相对的麻烦,java.util.Date 还是非线程安全的 API。

JDK 8 新增日期处理类:LocalDate、LocalTime、Instant、Duration 以及 Period,这些类都包含在 java.time 包中。

LocalTime localTime = LocalTime.now();
// 现在时间:18:00:49.476
System.out.println("现在时间:"+localTime);

4.Optionnal类

Optional类的作用: 主要解决的问题是:空指针异常 NullPointerException

本质上是一个包含有可选值的包装类,Opertional类既可以为含有对象也可以为空。

import java.util.Optional;

public class Java8Tester {
   public static void main(String args[]){

      Java8Tester java8Tester = new Java8Tester();
      Integer value1 = null;
      Integer value2 = new Integer(10);
      
      // Optional.ofNullable - 允许传递为 null 参数
      Optional<Integer> a = Optional.ofNullable(value1);

      // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
      Optional<Integer> b = Optional.of(value2);
      System.out.println(java8Tester.sum(a,b));
   }

   public Integer sum(Optional<Integer> a, Optional<Integer> b){

      // Optional.isPresent - 判断值是否存在
      System.out.println("第一个参数值存在: " + a.isPresent());
      System.out.println("第二个参数值存在: " + b.isPresent());

      // Optional.orElse - 如果值存在,返回它,否则返回默认值
      Integer value1 = a.orElse(new Integer(0));

      //Optional.get - 获取值,值需要存在
      Integer value2 = b.get();
      return value1 + value2;
   }
}

输出结果为:

第一个参数值存在: false
第二个参数值存在: true
10

5.方法引用

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 :: 。

构造器引用,它的语法是Class::new,或者更一般的Class< T >::new实例如下:

Demo demo = Demo::new;

静态方法引用,它的语法是Class::static_method,实例如下:

Demo::静态方法();

特定类的任意对象的方法引用:它的语法是Class::method实例如下:

Demo::方法名();

特定对象的方法引用:它的语法是instance::method实例如下:

demo::方法名();

6.Lambda 与 函数式编程

函数式编程

  • 面向对象编程是对数据的抽象(各种各样的POJO类);
  • 函数式编程则是对行为的抽象(将行为作为一个参数进行传递);
  • 所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为⼀个参数进行传递。
==================     自定义函数是编程(1)    ====================

/**
 * 像Runnable接口一样用FunctionalInterface注解修饰
 * 加了这个注解后,接口里面必须有且只能有一个方法
 */
@FunctionalInterface
public interface Test1<R,T>{

    // R表示返回值,T表示参数类型,t1 t2是具体参数
    R operator(T t1, T t2);
}

public class Compute {
    /**
     * 定义一个函数方法
     * 需要传入a和b两个参数,
     *  后面的Test1<Integer,Integer> of就是传入的一个函数(行为),of是随便起的一个别名
     */
    public static Integer operator(Integer a,Integer b,Test1<Integer,Integer> of){
        return of.operator(a,b);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Compute.operator(2,3,(a,b)-> a+b));
        System.out.println(Compute.operator(2,3,(a,b)-> a-b));
        System.out.println(Compute.operator(2,3,(a,b)-> a*b));
        System.out.println(Compute.operator(2,3,(a,b)-> a/b));
    }
}


==================     自定义函数是编程(2)    ====================

@FunctionalInterface
public interface Test2{

    void test();
}

public class Main {
    public static void main(String[] args) throws Exception {
        Main.casesc(()-> System.out.println("函数式编程案例二"));
    }

    public static void casesc(Test2 t){
        t.test();
    }
}

Lambda

  • Lambda表达式,使⽤场景:接口中只能有一个方法;
  • 比如Runnable接口里的run方法;Comparator接口里的compareTo方法;
  • Lambda 表达式的实现方式在本质是以匿名内部类的方式进行实现的。
public static void main(String[] args) throws Exception {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("jdk8以前创建线程");
        }
    });
    //()对应run()没有一个参数,->后面是方法体内容
    //如果{}中的代码只有⼀行,⽆论有返回值,可以省略{}、return、分号,其他则需要加上
    new Thread(()-> System.out.println("lambda表达式创建线程"));


    List<String> list = Arrays.asList("a","c","d","b","e");
    // jdk8以前排序
    Collections.sort(list, new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o2.compareTo(o1);
        }
    });
    // lambda表达式排序
    //,前面的对应接口前面的参数,a b 对应compare里面的参数
    Collections.sort(list,(a,b)->b.compareTo(a));
}

7. 四大核心函数式接口

Lambda表达式必须先定义接口,创建相关方法之后才能调用,这样做十分不便,其实java8已经内置了许多接口, 例如下面四个功能型接口.所有标注@FunctionalInterface注解的接口都是函数式接口。

Consumer 消费型接口:有入参,无返回值。适用场景:因为没有出参,常⽤用于打印、发送短信等消费。

public class Main {
    public static void main(String[] args) throws Exception {
        Consumer<String> c1 = obj->System.out.println(obj+": 调⽤用短信接⼝口发送短信,或者打印⽇日志");
        c1.accept("订单id—001");

        Consumer<List> c2 = obj->{
            if(obj==null || obj.size()<1)return;
            obj.forEach(o-> System.out.println(o));
        };
        List<Integer> list = Arrays.asList(2,4,0,8,9,7);
        c2.accept(list);
    }
}

Supplier 供给型接口:无入参,有返回值。适用场景:泛型一定和方法的返回值类型是同一种类型,并且不需要传入参数,例如:无参的工厂方法。

public class Main {
    public static void main(String[] args) throws Exception {
        Student student = newStudent();
        System.out.println(student);
    }

    public static Student newStudent(){
        Supplier<Student> supplier = ()-> {
            Student student = new Student();
            student.setName("默认名称");
            return student;
        };
        return supplier.get();
    }
}

class Student{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

Function与BiFunctionObj 函数型接口:有入参,有返回值。适用场景:传入参数经过函数的计算返回另一个值。

Function:只能接受一个参数

用法一(用一个类实现接口里面的逻辑,然后直接调用)

public class FunctionObj implements Function {

    @Override
    public Object apply(Object o) {
        return "对参数:"+o+"经过处理后返回结果";
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(test("hello",new FunctionObj()));
    }

    public static String test(String a ,FunctionObj functionObj){
        return functionObj.apply(a).toString();
    }
}

用法二(左边规定好参数和返回值类型,右边写方法体具体逻辑)

public class Main {
    public static void main(String[] args) throws Exception {
        Function<Integer,Integer> func = p->{
            return p*100;
        };
        System.out.println(func.apply(12));

        Function<Integer,Boolean> function = a->a<100;
        System.out.println(function.apply(97));
    }
}

=================================================================

BiFunctionObj:能接受两个参数

// 用法一

public class BiFunctionObj implements BiFunction {
    @Override
    public Object apply(Object o, Object o2) {
        return (Integer.valueOf(o.toString())+Integer.valueOf(o2.toString()));
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(test(2,5,new BiFunctionObj()));
    }

    public static Integer test(Integer a,Integer b, BiFunctionObj func){
        return Integer.valueOf(func.apply(a,b).toString());
    }
}
// 用法二

public class Main {
    public static void main(String[] args) throws Exception {
        BiFunction<Integer, Integer,Boolean> func1 = (a,b)->{
            return a>b;
        };
        System.out.println(func1.apply(1,5));

        BiFunction<String, String,String> func2 = (a,b)->a+b;
        System.out.println(func2.apply("hellow","world"));
    }
}

Predicate 断言型接口:有入参,有返回值,返回值类型确定是boolean。适用场景:接收一个参数,用于判断是否满一定的条件,过滤数据。

public class Main {
    public static void main(String[] args) throws Exception {
        Predicate<Integer> predicate = a->a>10;

        List<Integer> list = Arrays.asList(1,54,9,34,3);
        for(Integer l : list){
            if(predicate.test(l)) System.out.println(l);
        }
    }
}

8.流操作

Stream:通过将集合转换为这么⼀种叫做 “流”的元素队列,能够对集合中的每个元素进行任意操作。

总共分为4个步骤:

  • 数据元素便是原始集合:如List、Set、Map等
  • 生成流:可以是串行流stream() 或者并行流 parallelStream()
  • 中间操作:可以是 排序,聚合,过滤,转换等
  • 终端操作:统一收集返回一个流

一般都采用stream,因为集合操作一般里面就几百条数据,多线程的并行流效率不一定就高,还会出现线程安全问题。

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("张麻子","李蛋","王二狗","Angell");
        List<Student> users = Arrays.asList(new Student("张三", 23),
                                            new Student("赵四", 24),
                                            new Student("二狗", 23),
                                            new Student("田七", 22),
                                            new Student("皮特", 20),
                                            new Student("Tony", 20),
                                            new Student("二柱子", 25));
        /**
         * map:对集合的每个对象做处理
         */        
        List<String> collect = list.stream().map(obj->"哈哈"+obj).collect(Collectors.toList());
        list.forEach(obj->System.out.println(obj));
        System.out.println("----------------");
        collect.forEach(obj->System.out.println(obj));
        /**
         * filter:boolean判断,用于条件过滤
         */
        System.out.println("----------------");
        Set<String> set = list.stream().filter(obj->obj.length()>2).collect(Collectors.toSet());
        set.forEach(obj->System.out.println(obj));
        /**
         * sorted:对流进行自然排序
         */
        System.out.println("----------------");
        Set<String> sorteds = list.stream().sorted().collect(Collectors.toSet());
        sorteds.forEach(obj->System.out.println(obj));
        // 自定义排序规则
        // 根据长度排序(正序)
        System.out.println("----------------");
        List<String> resultList = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
        resultList.forEach(obj->System.out.println(obj));
        System.out.println("----------------");
        // 根据长度排序(倒序)
        List<String> resultList2 = list.stream().sorted(Comparator.comparing(obj -> obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
        resultList2.forEach(obj->System.out.println(obj));
        System.out.println("----------------");
        // 手动指定排序规则(根据年龄大小排序)
        List<Student> collect2 = users.stream().sorted(
                Comparator.comparing(Student::getAge,(x,y)->{
                    if(x>y) {
                        return 1;
                    }else {
                        return -1;
                    }
                })
                ).collect(Collectors.toList());
        collect2.forEach(obj->System.out.println(obj.getAge()+" : "+obj.getProvince()));
        /**
         * limit:截取包含指定数量的元素
         */
        System.out.println("----------------");
        List<String> collect3 = list.stream().limit(2).collect(Collectors.toList());
        collect3.forEach(obj->System.out.println(obj));
        /**
         * allMatch:匹配所有元素,只有全部符合才返回true
         */
        System.out.println("----------------");
        boolean flag = list.stream().allMatch(obj->obj.length()>2);
        System.out.println(flag);
        System.out.println("----------------");
        /**
         * anyMatch:匹配所有元素,至少一个元素满足就为true
         */
        boolean flag2 = list.stream().anyMatch(obj->obj.length()>2);
        System.out.println(flag2);
        System.out.println("----------------");
        /**
         * max和min:最大值和最小值        
         */
        Optional<Student> max = users.stream().max(Comparator.comparingInt(Student::getAge));
        System.out.println(max.get().getAge()+" : "+max.get().getProvince());
        System.out.println("----------------");
        Optional<Student> min = users.stream().min((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
        System.out.println(min.get().getAge()+" : "+min.get().getProvince());

        /**
         * reduce:对Stream中的元素进行计算后返回一个唯一的值      
         */
    
        // 计算所有值的累加
        int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();
        // 100作为初始值,然后累加所有值
        int value2 =Stream.of(1, 2, 3, 4, 5).reduce(100, (sum, item) -> sum + item);
        // 找出最大值
        int value3 =Stream.of(1, 4, 5, 2, 3).reduce((x,y)->x>y?x:y).get();
        
        System.out.println(value);
        System.out.println(value2);
        System.out.println(value3);
    }
}

class Student {
    private String province;
    private int age;
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String province, int age) {
        this.age = age;
        this.province = province;
    }
}

9.终端操作收集器:Collector

/**
 * 数据结构收集:Collectors
 */
public class Main {
    public static void main(String[] args) throws Exception {
        List<String> data = Arrays.asList("张三","王五","李四");
        List<String> list = data.stream().collect(Collectors.toList());
        Set<String> set = data.stream().collect(Collectors.toSet());
        LinkedList<String> linkedList = data.stream().collect(Collectors.toCollection(LinkedList::new));
        System.out.println(list);
        System.out.println(set);
        System.out.println(linkedList);
        /*
         Collectors.toMap()
         Collectors.toSet()
         Collectors.toCollection() :⽤用⾃自定义的实现Collection的数据结构收集
             Collectors.toCollection(LinkedList::new)
             Collectors.toCollection(CopyOnWriteArrayList::new)
             Collectors.toCollection(TreeSet::new)
         */
    }
}

//============================================================

/**
 * 拼接函数:joining
 */
public class Main {
    public static void main(String[] args) throws Exception {
        List<String> list = Arrays.asList("springBoot","springCloud","netty");
        String result1 = list.stream().collect(Collectors.joining());
        String result2 = list.stream().collect(Collectors.joining("——"));
        String result3 = list.stream().collect(Collectors.joining("—", "【",""));

        String result4 = Stream.of("hello", "world").collect(Collectors.joining("—", "【", "】"));

        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);
        System.out.println(result4);
    }
}

//============================================================

/**
 * 分组:partitioningBy
 */
public class Main {
    public static void main(String[] args) throws Exception {
        List<String> list = Arrays.asList("sdfsdf","xxxx","bbb","bbb");
        Map<Boolean, List<String>> collect = list.stream().collect(Collectors.partitioningBy(obj -> obj.length() > 3));
        System.out.println(collect);
    }
}

//============================================================

/**
 * 分组:group by
 * 统计:counting
 */
public class Main {
    public static void main(String[] args) throws Exception {
        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, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
        listMap.forEach((key, value) -> {
            System.out.println("========");
            System.out.println(key);
            value.forEach(obj -> {
                System.out.println(obj.getAge());
            });
        });
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        // 根据名称分组,并统计每个分组的个数
        Map<String, Long> map = students.stream().collect(Collectors.groupingBy(Student::getProvince, Collectors.counting()));
        map.forEach((key,value)->{
            System.out.println(key+"省人数有"+value);
        });
    }
}

class Student {
    private String province;
    private int age;
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String province, int age) {
        this.age = age;
        this.province = province;
    }
}

//============================================================

/**
 * 统计函数:summarizing
 */
public class Main {
    public static void main(String[] args) throws Exception {
        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));
        // summarizingInt;summarizingLong;summarizingDouble
        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());
    }
}

        /**
         * reduce:对Stream中的元素进行计算后返回一个唯一的值
         */
        // 计算所有值的累加
        int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();
        // 100作为初始值,然后累加所有值
        int value2 =Stream.of(1, 2, 3, 4, 5).reduce(100, (sum, item) -> sum + item);
        // 找出最大值
        int value3 =Stream.of(1, 4, 5, 2, 3).reduce((x,y)->x>y?x:y).get();
        
        System.out.println(value);
        System.out.println(value2);
        System.out.println(value3);

JDK 9 新特性

JDK 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。

1. try-with-resource

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Main {
    
    public static void main(String[] args) throws Exception {
        String path = "/Users/jack/Desktop/t.txt";
        
        /**
         * jdk 1.7以前关闭资源一般是在finally里面操作的
         */
        OutputStream out = new FileOutputStream(path);
        try {
            out.write(("公众号:程序员的成长之路").getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        /**
         * jdk1.7的时候,可以在try()里声明资源,会在try-catch代码块结束后自动关闭掉。
         * try结束后自动调用的close方法,这个动作会早于finally里调用的方法
         * bu管是否出现异常,try()里的实例都会被调用close方法
         * try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被close掉
         */
        try (OutputStream out2 = new FileOutputStream(path);){
            out2.write(("公众号:程序员的成长之路").getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        /**
         * jdk1.9之后,对try()做了改进,在try外进行初始化,在括号内引用
         */
        OutputStream out3 = new FileOutputStream(path);
        try (out3) {
            out3.write(("公众号:程序员的成长之路").getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. stream

public class Main {
    /**
     * jdk9中的Stream流新增了两个api
     */
    public static void main(String[] args) throws Exception {
        /**
         * takeWhile:遍历每个对象,直到遇到第⼀个false时,返回前面所有元素,如果没有false,将返回⼀一个空的 Stream
         */
        List<String> list1 = List.of("springboot","java","html","","git").stream()
                            .takeWhile(obj->!obj.isEmpty()).collect(Collectors.toList());
        System.out.println(list1);
        
        /**
         * dropWhile:与takeWhile相反
         */
        List<String> list2 = List.of("springboot","java","html","","git").stream()
                            .dropWhile(obj->!obj.isEmpty()).collect(Collectors.toList());
        System.out.println(list2);
    }
}

3. of 创建只读集合

public class Main {
    
    public static void main(String[] args) throws Exception {
        /**
         * JDK9之前创建只读集合
         */
        List<String> list = new ArrayList<String>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.remove(0);
        System.out.println(list);
        //设置为只读List集合
        // unmodifiableMap(map); unmodifiableMap(set);
        list = Collections.unmodifiableList(list);
        // 报错:java.lang.UnsupportedOperationException
        //list.remove(0);
        System.out.println(list);
        /**
         * jdk9创建只读集合
         */
        List<String> list2 = List.of("mysql", "linux", "redis");
        list2.remove(0);
        System.out.println(list2);
    }
}

JDK 10 新特性

自从 Java 9 开始,Oracle 调整了 Java 版本的发布策略,不再是之前的 N 年一个大版本,取而代之的是 6 个月一个小版本,三年一个大版本,这样可以让 Java 的最新改变迅速上线,而小版本的维护周期缩短到下个版本发布之前,大版本的维护周期则是 3 年之久。

2018 年 3 月 20 日,Oracle 宣布 Java 10 正式发布。

1. var作为局部变量类型推断标识符

public class Main {

    // var作为局部变量类型推断标识符
    public static void main(String[] args) throws Exception {
        var strVar = "springboot";
        System.out.println(strVar instanceof String);
        //根据10L 推断long 类型
        var longVar = Long.valueOf(10l);
        System.out.println(longVar instanceof Long);
        //根据 true推断 boolean 类型
        var flag = Boolean.valueOf("true");
        System.out.println(flag instanceof Boolean);
        // 推断 ArrayList<String>
        var listVar = new ArrayList<String>();
        System.out.println(listVar instanceof ArrayList);
        // 推断 Stream<String>
        var streamVar = Stream.of("aa", "bb", "cc");
        System.out.println(streamVar instanceof Stream);
        if(flag){
            System.out.println("这个是 flag 变量,值为true");
        }
        for (var i = 0; i < 10; i++) {
            System.out.println(i);
        }
        try (var input = new FileInputStream("validation.txt")) {
        }
    }
}

JDK 11 新特性

2018-09-26,Oracle官方宣布Java 11 (18.9 LTS)正式发布,这是自Java 8后推出的首个长期支持版本。根据官方公布的路线图,Java 11将会获得Oracle提供的长期支持服务,直至2026年9月。

1. httpclinet

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
/**
 * 这个功能在JDK9中引入,在JDK10中得到了更新,在JDK11才发布
 */
public class Main {

    private static final URI uri = URI.create("https://www.cnblogs.com/wlwl/");

    public static void main(String[] args) {
        testHttp2();
    }
    /**
     * get请求
     */
    private static void testGet() {
        // 创建连接两种方式:var httpClient = HttpClient.newHttpClient();
        var httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofMillis(5000)).build();
        
        // 封装请求参数(默认get请求)
        HttpRequest request = HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
                                .header("key1", "v1")
                                .uri(uri).build();
        try {
            var response = httpClient.send(request,
            HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * post请求
     */
    private static void testPost() {
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().uri(uri)
                    .POST(HttpRequest.BodyPublishers.ofString("phone=13113777337&pwd=1234567890"))
                    // from表单要用下面格式发送
                    //.header("Content-Type", "application/json")
                    //.POST(HttpRequest.BodyPublishers.ofString("{\"phone\":\"13113777337\",\"pwd\":\"1234567890\"}"))
                    .build();
        
        try {
            var response = httpClient.send(request,
            HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 异步GET请求
     */
    private static void testAsynGet() {
        var httpClient = HttpClient.newBuilder().build();
        var request =
        HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
        .header("key1", "v1")
        .uri(uri).build();
        try {
            // 异步请求通过CompletableFuture实现
            CompletableFuture<String> result = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                         .thenApply(HttpResponse::body);
            System.out.println(result.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 发送http2请求
     *     HTTP2协议的强制要求https,如果目标URI是HTTP的,则无法使用HTTP 2协议
     */
    private static void testHttp2() {
        var httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofMillis(3000))
                                    .version(HttpClient.Version.HTTP_2)
                                    .build();
        var request = HttpRequest.newBuilder().timeout(Duration.ofMillis(3000))
        .header("key1", "v1")
        .uri(uri)
        .build();
        try {
            var response = httpClient.send(request,
            HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
            System.out.println(response.version());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

JDK 12 新特性

2019-03-20,JDK 12 正式发布,新特性如下:

1.Switch 表达式

使用Java 12,switch不仅可以作为语句也可以作为表达式。无论作为语句或者作为表达式,switch都可以使用传统/简化的作用域和控制流行为。这将有助于简化代码,并为在switch中使用模式匹配铺平道路。

Java开发人员正在增强Java编程语言,以使用模式匹配来解决当前switch语句的几个问题。这包括:switch块的默认控制流行为,switch块默认作用域(被视为单个作用域的块)和switch仅作为语句。

在Java 11中,switch语句追随C和C++,默认情况下使用fall-through语义。虽然传统的控制流程在编写低级代码时很有用,但随着switch在更高级别的环境中采用,易出错会盖过其灵活性。

Java 11

Java 12

2.默认CDS归档

通过在64位平台上的默认类列表的帮助下生成CDS归档来改进JDK构建过程,从而有效地消除了运行java -Xshare:dump。此功能的目标包括:1。)改进开箱即用的启动时间,以及2.)摆脱使用-Xshare:dump。

3.Shenandoah GC

Shenandoah是一种垃圾收集(GC)算法,旨在保证低延迟(10 - 500 ms的下限)。它通过在运行Java工作线程的同时执行GC操作减少GC暂停时间。使用Shenandoah,暂停时间不依赖于堆的大小。这意味着无论堆的大小如何,暂停时间都是差不多的。

这是一个实验性功能,不包含在默认(Oracle)的OpenJDK版本中。

4.JMH 基准测试

此功能为JDK源代码添加了一套微基准测试(大约100个),简化了现有微基准测试的运行和新基准测试的创建过程。它基于Java Microbenchmark Harness(JMH)并支持JMH更新。

此功能使开发人员可以轻松运行当前的微基准测试并为JDK源代码添加新的微基准测试。可以基于Java Microbenchmark Harness(JMH)轻松测试JDK性能。它将支持JMH更新,并在套件中包含一组(约100个)基准测试。

5.JVM 常量 API

JEP 334引入了一个API,用于建模关键类文件和运行时artifacts,例如常量池。此API将包括ClassDesc,MethodTypeDesc,MethodHandleDesc和DynamicConstantDesc等类。此 API 对于操作类和方法的工具很有帮助。

6.G1的可中断 mixed GC

此功能通过将Mixed GC集拆分为强制部分和可选部分,使G1垃圾收集器更有效地中止垃圾收集过程。通过允许垃圾收集过程优先处理强制集,g1可以更多满足满足暂停时间目标。

G1是一个垃圾收集器,设计用于具有大量内存的多处理器机器。由于它提高了性能效率,g1垃圾收集器最终将取代cms垃圾收集器。

G1垃圾收集器的主要目标之一是满足用户设置的暂停时间。G1采用一个分析引擎来选择在收集期间要处理的工作量。此选择过程的结果是一组称为GC集的区域。一旦GC集建立并且GC已经开始,那么G1就无法停止。

如果G1发现GC集选择选择了错误的区域,它会将GC区域的拆分为两部分(强制部分和可选部分)来切换到处理Mix GC的增量模式。如果未达到暂停时间目标,则停止对可选部分的垃圾收集。

7.G1归还不使用的内存

此功能的主要目标是改进G1垃圾收集器,以便在不活动时将Java堆内存归还给操作系统。为实现此目标,G1将在低应用程序活动期间定期生成或持续循环检查完整的Java堆使用情况。

这将立即归还未使用的部分Java堆内存给操作系统。用户可以选择执行FULL GC以最大化返回的内存量。

8.移除多余ARM64实现

Java 12将只有一个ARM 64位实现(aarch64)。目标是删除所有与arm64实现相关的代码,同时保留32位ARM端口和64位aarch64实现。

这将把重点转移到单个64位ARM实现,并消除维护两个实现所需的重复工作。当前的JDK 11实现中有两个64位ARM实现。

JDK 13 新特性

2019-09-17,JDK 12 正式发布,新特性如下:

1. switch

public class Main {
    public static void main(String[] args) {
        testOldSwitch1();
    }
    /**
     * 旧:没有break,则匹配的case后⾯面会⼀一直输出
     */
    public static void testOldSwitch1(){
        int i = 1;
        switch(i){
        case 0:
            System.out.println("zero");
            //break;
        case 1:
            System.out.println("one");
            //break;
        case 2:
            System.out.println("two");
            //break;
        default:
            System.out.println("default");
        }
    }
    
    /**
     * 新:使用箭头函数,不用声明break,会自动终止,支持多个值匹配,使用逗号分隔
     */
    public void testNewSwitch(int i){
        switch(i){
        case 0 -> {
            System.out.println("zero");
            System.out.println("这是多⾏行行语句句");
        }
        case 1,11,111 -> System.out.println("one");
        case 2 -> System.out.println("two");
        default -> System.out.println("default");
        }
    }
}

2. 多行文本块

public class Main {
    
    public static void main(String[] args) {
        /**
         * 旧:在java代码里面编写多行源码带有特殊字符则需要转义,如HTML,sql等
         */
        String html = "<html>\n" +
                         "<body>\n" +
                             "<p>Hello, world</p>\n" +
                         "</body>\n" +
                      "</html>\n";
        String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
                       "WHERE `CITY` = 'INDIANAPOLIS'\n" +
                       "ORDER BY `EMP_ID`, `LAST_NAME`;\n";
    
        /**
         * 新:不用对转义字符进行转义
         */
        String html2 = """"
                        <html>
                            <body>
                                <p>Hello, world</p>    
                            </body>
                        </html>
                       """;
        String query = """
                        SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
                        WHERE `CITY` = 'INDIANAPOLIS'
                        ORDER BY `EMP_ID`, `LAST_NAME`;
                       """;
    }
}

JDK 8 - 13 发布时间线

收集整理的信息不全,又不正确的地方,欢迎指出!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JDK 8 新特性
  • JDK 9 新特性
  • JDK 10 新特性
  • JDK 11 新特性
  • JDK 12 新特性
  • JDK 13 新特性
  • JDK 8 - 13 发布时间线
相关产品与服务
短信
腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档