Java大版本更新之新功能特性总览(JDK5-JDK10)

Posted 3T教学技术派

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java大版本更新之新功能特性总览(JDK5-JDK10)相关的知识,希望对你有一定的参考价值。


1、JDK5主要新特性(2004年10月发布)

  1. 泛型(Generics):为集合(collections)提供编译时类型安全,无需每刻从Collections取得一个对象就进行强制转换(cast);

  2. 增强的“for”循环(Enhanced For loop):减少迭代器(iterator)的潜在错误(error-proneness) ;

  3. 自动装箱/自动拆箱(Autoboxing/unboxing):无需在基本类型(primitive types)(例如double)和包装类型(wrapper types)(例如Double)之间人工地进行转换;

  4. 类型安全的枚举(Typesafeenums):提供类型安全枚举模式的各项好处,诸如编译时安全处理、都是对象、类的一种实现,可以有方法等;

  5. 静态导入(Static import):无需在使用其他类的静态成员变量前缀其类名.这将使得代码更为简洁;

  6. 可变参数(Var args):同类型的参数个数再也不要你一个个的在方法参数列表中穷举了;

  7. 元数据(Metadata):使编程人员避免编写样板化代码(boiler plate code),并提供机会进行宣告式程式设计(declarative programming)。


2、JDK1.6新特性(2006年4月发布)

  1. Desktop类和SystemTray类:前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序;

  2. 使用JAXB2来实现对象与XML之间的映射:JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。

  3. StAX:StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件,然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;

  4. 使用Compiler API:现在我们可以用JDK6 的Compiler API(JSR199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。

  5. 轻量级Http Server API:JDK6 提供了一个简单的Http Server API, 据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法.

  6. 插入式注解处理API(Pluggable Annotation Processing API):插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175) 。JSR 269主要被设计成为针对Tools或者容器的API. 举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法。

  7. 用Console开发控制台程序:JDK6 中提供了java.io.Console类专用来访问基于字符的控制台设备. 你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳. 但我们不总是能得到可用的Console,一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用. 如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例.

  8. 对脚本语言的支持:实现了对ruby, groovy, javascript等语言的支持。

  9. 通用注解(Common Annotations):Common annotations原本是Java EE 5.0(JSR244)规范的一部分,现在SUN把它的一部分放到了Java SE 6.0中. 随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,很多Java 技术(比如EJB,Web Services)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务), 如果这些技术为通用目的都单独定义了自己的Annotations,显然有点重复建设, 所以,为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免重复建设的同时,也保证Java SE和Java EE 各种技术的一致性.

3、JDK7新特性(2011年7月28号发布)

  1. switch中可以使用字串

String s = "astr";switch (s) { case "test" :
   System.out.println("test");case "astr" :
   System.out.println("test1");break ;default :
  System.out.println("break");break ;
}
  1. "<>"的运用:List tempList = new ArrayList<>(); 即泛型实例化类型自动推断:

public class JDK7GenericTest {   public static void main(String[] args) {      // JDK 7以前版
      List<String> lst1 = new ArrayList<String>();      // JDK 7 支持有限的类型推断
      List<String> lst2 = new ArrayList<>();
   
      lst1.add("Mon");
      lst1.add("Tue");
      lst2.add("Wed");
      lst2.add("Thu");   
      for (String item: lst1) {
         System.out.println(item);
      }   
      for (String item: lst2) {
         System.out.println(item);
      }
   }
}
  1. 自定义自动关闭类:新增了AutoCloseable接口只要实现该接口,在该类对象销毁时自动调用close方法,你可以在close方法关闭你想关闭的资源,例子如下:

class TryClose implements AutoCloseable { 
 @Override public void close() throw Exception {
  System.out.println(" Custom close method …                                         close resources ");
 }
}//请看jdk自带类BufferedReader如何实现close方法(当然还有很多类似类型的类)
 public void close() throws IOException {   synchronized (lock) {            
       if (in == null)  return;          in.close();          in = null;
          cb = null;
   }
}
  1. 新增一些取环境信息的工具方法:

File System.getJavaIoTempDir() // IO临时文件夹File System.getJavaHomeDir() // JRE的安装目录File System.getUserHomeDir() // 当前用户目录File System.getUserDir() // 启动java进程时所在的目录.......

5.** Boolean类型反转,空指针安全,参与位运算**:

Boolean Booleans.negate(Boolean booleanObj)True => False , False => True, Null => Nullboolean Booleans.and(boolean[] array)boolean Booleans.or(boolean[] array)boolean Booleans.xor(boolean[] array)boolean Booleans.and(Boolean[] array)boolean Booleans.or(Boolean[] array)boolean Booleans.xor(Boolean[] array)
  1. 两个char间的equals

boolean Character.equalsIgnoreCase(char ch1, char ch2)
  1. 安全的加减乘除:

int Math.safeToInt(long value) 
int Math.safeNegate(int value) 
long Math.safeSubtract(long value1, int value2) 
long Math.safeSubtract(long value1, long value2) 
int Math.safeMultiply(int value1, int value2) 
long Math.safeMultiply(long value1, int value2) 
long Math.safeMultiply(long value1, long value2) 
long Math.safeNegate(long value) 
int Math.safeAdd(int value1, int value2) 
long Math.safeAdd(long value1, int value2) 
long Math.safeAdd(long value1, long value2) 
int Math.safeSubtract(int value1, int value2)
  1. 对Java集合(Collections)的增强支持:在JDK1.7中,可以不用Java集合接口的实现类,如:ArrayList、HashSet和HashMap。而是直接采用[]、{}的形式存入对象,采用[]的形式按照索引、键值来获取集合中的对象,如下:

List<String> list=["item"]; //向List集合中添加元素String item=list[0]; //从List集合中获取元素
 Set<String> set={"item"}; //向Set集合对象中添加元素Map<String,Integer> map={"key":1}; //向Map集合中添加对象int value=map["key"]; //从Map集合中获取对象
  1. 数值可加下划线: 例如:

int one_million = 1_000_000;
  1. 支持二进制文字: 例如:

int binary = 0b1001_1001;
  1. 简化可变参数方法的调用: 当程序员试图使用一个不可具体化的可变参数并调用一个varargs (可变)方法时,编辑器会生成一个“非安全操作”的警告。

  2. 增强try中catch块: 在try catch异常扑捉中,一个catch可以写多个异常类型,用"|"隔开:

//JDK7以前try {
   ......
} catch(ClassNotFoundException ex) {
   ex.printStackTrace();
} catch(SQLException ex) {
   ex.printStackTrace();
}
//JDK7中try {
   ......
} catch(ClassNotFoundException|SQLException ex) {
   ex.printStackTrace();
}
  1. 资源处理: jdk7之前,你必须用try{}finally{}在try内使用资源,在finally中关闭资源,不管try中的代码是否正常退出或者异常退出。jdk7之后,你可以不必要写finally语句来关闭资源,只要你在try()的括号内部定义要使用的资源即可。其它不需要你担心

4、JDK1.8新特性(2014年3月发布)

  1. 接口的默认方法: Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:

interface Formula {    double calculate(int a);    
    default double sqrt(int a) {        return Math.sqrt(a);
    }
}

Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。代码如下:

Formula formula = new Formula() {
    @Override        public double calculate(int a) {            return sqrt(a * 100);
    }
};
formula.calculate(100);     // 100.0formula.sqrt(16);           // 4.0
  1. Lambda 表达式: 首先看看在老版本的Java中是如何排列字符串的:

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {    @Override    
    public int compare(String a, String b) {            return b.compareTo(a);
    }
});

只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。

在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:

Collections.sort(names, (String a, String b) -> {    return b.compareTo(a); });

看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:

Collections.sort(names, (String a, String b) -> b.compareTo(a));

对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:

Collections.sort(names, (a, b) -> b.compareTo(a));

Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。接下来我们看看lambda表达式还能作出什么更方便的东西来

  1. 函数式接口: Lambda 表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的 接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。 我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。 示例如下:

@FunctionalInterfaceinterface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。

译者注: 将lambda表达式映射到一个单方法的接口上,这种做法在Java 8 之前就有别的语言实现,如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有 org.w3c.dom.events.EventTarget 的addEventListener 第二个参数 EventListener。

  1. 方法与构造函数引用: 前一节中的代码还可以通过静态方法引用来表示:

Converter<String, Integer> converter = Integer::valueOf;Integer converted = converter.convert("123");
System.out.println(converted);   // 123

Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:

converter = something::startsWith;String converted = converter.convert("Java");System.out.println(converted);    // "J"

接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:

class Person {    String firstName;    
    String lastName;
    Person() {}
 
    Person(String firstName, String lastName) {        this.firstName = firstName;        
        this.lastName = lastName;
    }
}

接下来我们指定一个用来创建Person对象的对象工厂接口:

interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}

这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:

PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

我们只需要使用 Person::new 来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。

  1. Lambda 作用域: 在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。

  2. 访问局部变量: 我们可以直接在lambda表达式中访问外层的局部变量:

final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
stringConverter.convert(2);     // 3

但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确:

int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
stringConverter.convert(2);     // 3

不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:

int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);num = 3;

在lambda表达式中试图修改num同样是不允许的。

  1. 访问对象字段与静态变量: 和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:

class Lambda4 {
    static int outerStaticNum;
    int outerNum;    
    void testScopes() {
        Converter<Integer, String> stringConverter1 = (from) -> {
            outerNum = 23;            
            return String.valueOf(from);
        };
 
        Converter<Integer, String> stringConverter2 = (from) -> {
            outerStaticNum = 72;            
            return String.valueOf(from);
        };
    }
}
  1. 访问接口的默认方法: JDK 1.8 API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能用在lambda上。 Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便,有一些接口是来自Google Guava库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到lambda上使用的。诸如: Predicate接口、Function 接口、Supplier 接口、Consumer 接口、Optional 接口、Stream 接口、Filter 过滤、Sort 排序、Map 映射、Match 匹配、Reduce 规约、Reduce 规约、并行Streams等,这些需要花大精力ilai研究。

  2. Date API: Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样,下面的例子展示了这组新API里最重要的一些部分: Clock 时钟\Timezones 时区、LocalTime 本地时间、LocalDateTime 本地日期时间、LocalDateTime 本地日期时间

  3. Annotation 注解: 在Java 8中支持多重注解了,先看个例子来理解一下是什么意思。 首先定义一个包装类Hints注解用来放置一组具体的Hint注解:

1 2 3 4 5 6 7 @interface Hints { Hint[] value(); } @Repeatable(Hints.class) @interface Hint { String value(); } Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。

例 1: 使用包装类当容器来存多个注解(老方法)

1 2 @Hints({@Hint("hint1"), @Hint("hint2")}) class Person {} 例 2:使用多重注解(新方法)

1 2 3 @Hint("hint1") @Hint("hint2") class Person {} 第二个例子里java编译器会隐性的帮你定义好@Hints注解,了解这一点有助于你用反射来获取这些信息:

Hint hint = Person.class.getAnnotation(Hint.class);
System.out.println(hint);                   // nullHints hints1 = Person.class.getAnnotation(Hints.class);
System.out.println(hints1.value().length);  // 2Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class);
System.out.println(hints2.length);          // 2

即便我们没有在Person类上定义@Hints注解,我们还是可以通过 getAnnotation(Hints.class) 来获取 @Hints注解,更加方便的方法是使用 getAnnotationsByType 可以直接获取到所有的@Hint注解。 另外Java 8的注解还增加到两种新的target上了:

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})@interface MyAnnotation {}

关于Java 8的新特性就写到这了,肯定还有更多的特性等待发掘。JDK 1.8里还有很多很有用的东西,比如Arrays.parallelSort, StampedLock和CompletableFuture等等。

5、JDK1.9新特性(2017年9月21号发布)

Java 9 包含了丰富的特性集。虽然Java 9没有新的语言概念,但是有开发者感兴趣的新的API和诊断命令。其新特性一览图如下:


  1. 台级模块化系统–Jigsaw

模块化是一个很通用的概念。在软件中,模块化可以运用到编写和实现一个程序和计算系统,他们都是作为独立的模块,而不是作为一个单一的和完整的设计。 Java 9中主要的变化是已经实现的模块化系统。模块化的引入使得JDK可以在更小的设备中使用。采用模块化系统的应用程序只需要这些应用程序所需的那部分JDK模块,而非是整个JDK框架了。模块化系统也可以将公共的类封装到一个模块中。因此一个封装在模块中的定义为public的类不能再任何地方使用,除非一个模块显式的定义了这个模块。由于Java 9的这个变化,Java内部的API(例如com.sun.*)默认情况下是不能使用的。

简而言之,所有的模块将需要在所谓的module-info.java文件中进行描述,这个文件是位于Java代码结构的顶层。

module me.aboullaite.java9.modules.car {
    requires me.aboullaite.java9.modules.engines;//依赖的模块
    exports me.aboullaite.java9.modules.car.handling;//在模块中导出包
}

我们的模块car(汽车)需要依赖+模块engine(引擎)和需要导出handling(操纵)包。

需要更多深入的例子可以查看OpenJDK中项目Jigsaw:模块化系统快速入门。

  1. JShell–Java 9 REPL:

你可能问:“REPL是什么”?REPL是一种快速运行语句的命令行工具。

在Java中,如果你想执行一个简单的语句,我们要么创建一个带main方法的类,要么创建一个可以执行的Test类。当你正在启动Java程序的时候,如果你想执行某些语句并且想立刻看见执行结果,上面的做法看起来不是那么有用了。

JShell试图去解决这个问题。Java开发者可以利用JShell在没有创建类的情况下直接声明变量,计算表达式,执行语句。JShell也可以从文件中加载语句或者将语句保存到文件中。并且JShell也可以是tab键进行自动补全的特性。

  1. 集合工厂方法

在Java 9之前,Java只能利用一些实用方法(例如:Collections.unmodifiableCollection(Collection<? extends T> c))创建一个不可修改视图的集合。例如,我们可以在Java 8中使用一条如下所示的语句,创建一个Collection的不可修改的视图。虽然这是最简单的创建方式,但是看起来很糟糕!不是吗?

Map<String, String> immutableMap =
Collections.unmodifiableMap(            new HashMap<String, String>() {{
                put("key1", "Value1");
                put("key2", "Value2");
                put("key3", "Value3");
            }});

现在,Java 9引入了一些有用的工厂方法来创建不可修改的集合。我们现在在Java 9中创建不可修改的Map集合,如下所示。

Map<String, String> immutableMap = Map.of("key1", "Value1", "key2", "Value2""key3", "Value3");

下面是工厂方法的例子:

// empty immutable collections 不可修改的空集合List<String> emptyImmutableList = List.of();Set<String> emptyImmutableSet = Set.of();Map emptyImmutableMap = Map.of();// immutable collections 不可修改的集合List<String> immutableList = List.of("one", "two");Set<String> immutableSet = Set.of("value1", "value2");Map<String, String> immutableMap = Map.of("key1", "Value1", "key2", "Value2", "key3", "Value3");
  1. 接口中的私有方法:

Java 8的接口引入了默认方法和静态方法。虽然Java 8首次计划实现接口的私有方法,却是在Java 9中实现。默认方法和静态方法可以共享接口中的私有方法,因此避免了代码冗余,这也使代码更加清晰。如果私有方法是静态的,那这个方法就属于这个接口的。并且没有静态的私有方法只能被在接口中的实例调用。

interface InterfaceWithPrivateMethods {
    private static String staticPrivate() {        return "static private";    
    }

    private String instancePrivate() {        return "instance private";
    }

    default void check() {        String result = staticPrivate();        InterfaceWithPrivateMethods pvt = new InterfaceWithPrivateMethods() {
            // anonymous class 匿名类
        };        result = pvt.instancePrivate();
    }

}
  1. 响应式流:

JDK9中的Flow API对应响应式流规范,响应式流规范是一种事实标准。JEP 266包含了一组最小接口集合,这组接口能捕获核心的异步发布与订阅。希望在未来第三方能够实现这些接口,并且能共享其方式。

java.util.concurrent.Flow包含以下4个接口:

  • Flow.Processor(处理器)

  • Flow.Publisher(发布者)

  • Flow.Subscriber(订阅者)

  • Flow.Subscription(订阅管理器)

这些接口都支持响应式流发布-订阅框架。Java 9也提供了实用类SubmissionPublisher。一个发布者产生一个或多个物品,这些物品由一个或多个消费者消耗。并且订阅者由订阅管理器管理。订阅管理器连接发布者和订阅者。

  1. 多分辨率图像API–JEP 251:

目标是定义多分辨率图像API,这样开发者就能很容易的操作和展示不同分辨率的图像了。

这个新的API定义在java.awt.image包中,这个API能给我们带来如下的帮助:

  • 将不同分辨率的图像封装到一张(多分辨率的)图像中,作为它的变体。

  • 获取这个图像的所有变体。

  • 获取特定分辨率的图像变体–表示一张已知分辨率单位为DPI的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体。

基于当前屏幕分辨率大小和运用的图像转换算法,java.awt.Graphics类可以从接口MultiResolutionImage获取所需的变体。java.awt.image.AbstractMultiResolutionImage类提供了ava.awt.image.AbstractMultiResolutionImage 默认实现。AbstractMultiResolutionImage的基础实现是java.awt.image.BaseMultiResolutionImage。

  1. 进程API的改进:

迄今为止,通过Java来控制和管理操作系统的进程的能力有限。例如,为了做一些简单的事情,像获取进程的PID,你要么需要访问本地代码,要么使用某种临时解决方案。不仅如此,每个(系统)平台需要一个不同实现来确保你能获得正确的结果。

在Java 9中,期望代码能获取Linux PID,现在是如下方式:

public static void main(String[] args) throws Exception{  Process proc = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "echo $PPID" });  if (proc.waitFor() == 0)
   {    InputStream in = proc.getInputStream();    int available = in.available();
    byte[] outputBytes = new byte[available];    in.read(outputBytes);    String pid = new String(outputBytes);    System.out.println("Your pid is " + pid);
   }
}

你可以变换如下的方式(同样支持所有的操作系统):

System.out.println("Your pid is " + Process.getCurrentPid());
  1. Try-With-Resources:

在Java 7中,try-with-resouces语法要求为每一个资源声明一个新的变量,而且这些资源由try-with-resources语句进行管理。

在就Java 9中,有另外一个改进:如果一个资源被final或者等效于final变量引用,则在不需要声明一个新的变量的情况下,try-with-resources就可以管理这个资源。

MyAutoCloseable mac = new MyAutoCloseable();try (mac) {   // do some stuff with mac}try (new MyAutoCloseable() { }.finalWrapper.finalCloseable) {  // do some stuff with finalCloseable}
  1. 钻石(diamond)"<>"操作符范围的延伸:

Java 7给出的钻石操作符使我们编写代码更简单了。在下面的例子中,你可以看见Java 7中List(列表)的可读性更强了,并且使代码更加的简洁了。

List<String> preJava7 = new ArrayList<String>();//java 7 之前的写法List<String> java7 = new ArrayList<>();//java 7 之后的写法

但是Java 7中钻石操作符不允许在匿名类上使用。但在Java 9中改善了这一情况,允许钻石操作符在匿名类上使用。下面的例子只有在Java 9中才能通过编译。

List<String> list = new ArrayList<>(){ };
  1. 增强的注释Deprecated

注释@Deprecated可以标记Java API。注释@Deprecated有很多种含义,例如它可以表示在不远的将来的某个时间,被标记的API将会被移除。它也可以表示这个API已经被破坏了,并不应该再被使用。它还有其它很多含义。为了提供更多有关@Deprecated的信息,@Deprecated添加了forRemoval元素和since元素。

Java SE 9 中也提供了扫描jar文件的工具jdeprscan。这款工具也可以扫描一个聚合类,这个类使用了Java SE中的已废弃的API元素。 这个工具将会对使用已经编译好的库的应用程序有帮助,这样使用者就不知道这个已经编译好的库中使用了那些已废弃的API。

  1. 统一的JVM日志:

如今,我们很难知道导致JVM性能问题和导致JVM崩溃的根本原因。解决这个问题的一个方法是对所有的JVM组件引入一个单一的系统,这些JVM组件支持细粒度的和易配置的JVM日志。目前,不同的JVM组件对于日志使用的是不同的机制和规则,这使得JVM难以进行调试。

  1. 注释SafeVarargs范围的延伸

直到Java 8,@SafeVarargs才能在静态方法、final方法和构造器上使用。但是这些方法或者构造器是不能被覆盖的。这些方法中缺少另一个不能被覆盖的方法,这个方法就是私有方法。Java 9可以将@SafeVarargs添加到私有方法上。下面的例子在Java 9中是正确的,但是在Java 8中就会抛出编译时错误: 注释@SafeVarargs不能在非final的实例方法iAmSafeVaragrsMethod上使用。

@SafeVarargs  private void iAmSafeVaragrsMethod(String... varagrgs)
  {     for (String each: varagrgs) {
        System.out.println(each);
     }
  }
  1. HTTP 2 客户端:

Java 9采用了全新的HTTP客户端API,这些API支持HTTP/2协议和WebSocket协议,并且替换了遗留的HTTPURLConnection API。这些改变并不应该在Java 9中完成。这些API可以从Incubator(孵化器)模块中获取。因此在默认情况下,这个模块是不能根据classpath获取的,需要使用--add-modules命令选项配置这个模块,将这个模块添加到classpath中。

我们创建一个HTTPRequest请求和获取异步的响应:

URI testPageURI = new URI("http://127.0.0.1:8080/testPage");  CompletableFuture<HttpResponse> nonBlockingResponse =  HttpRequest
          .create(testPageURI)
          .GET().responseAsync();  int tries = 0;  while(!nonBlockingResponse.isDone() && tries++ < 5) { Thread.sleep(5); } if (nonBlockingResponse.isDone()) { HttpResponse response = nonBlockingResponse.get(); System.out.println("status code : " + response.statusCode() + " --> " +  response.body(HttpResponse.asString()));
  }  else {
      nonBlockingResponse.cancel(true);      System.out.println("Cancelling, could not get response");
  }
  1. html5风格的Java帮助文档

Java 8以及之前的版本生成的Java帮助文档是在HTML 4中,而HTML 4已经是很久的标准了。在Java 9中,javadoc命令行中选项部分添加了输出选项,这个选项的值要么是HTML 4,要么是HTML 5。现在HTML 4是默认的输出标记语言,但是在之后发布的JDK中,HTML 5将会是默认的输出标记语言。Java帮助文档还是由三个框架组成的结构构成,这是不会变的,并且以HTML 5输出的Java帮助文档也保持相同的结构。

  1. 更多的特性:

  • 保留下划线字符。变量不能被命名为_;

  • 废弃Applet API;

  • javac不再支持Java1.4以及之前的版本;

  • 废弃Java浏览器插件;

  • 栈遍历API–栈遍历API能过滤和迟访问在堆栈跟踪中的信息。

6、JDK 10 的 109 项新特性(2017年9 月 21 日)

  • java10新增了不少特性,也导致了几次发布跳票,但最终在2017年9月发布。zheli简要列举一些新特性,不再做示性演示。

  • 一个局部变量类型推断,通过增强语言特性将类型推断扩展到局部变量,目的是减少与编码相关的“仪式”,同时保持对静态类型的安全承诺。

  • 一个干净的垃圾收集器接口,用来改善垃圾收集器源代码之间的隔离效果,这样可以为HotSpot 虚拟机中的内部垃圾收集代码提供更好的模块化功能,也可以更容易向 HotSpot 添加新的垃圾收集器。

  • 并行、完整的 G1 垃圾收集器,通过实现并行性来改善最坏情况下的延迟问题。

  • 启用 HotSpot 将对象堆分配给用户指定的备用内存设备(如 NVDIMM 内存模块),这个特性也侧面预示了未来的系统可能会采用异构的内存架构。

  • 在 Linux / x64 平台上以实验性方式启用基于 Java 的即时编译器(https://www.infoworld.com/article/3187868/application-development/oracles-java-on-java-experiment-picks-up-steam.html)。

  • 将 JDK 的多个存储库合并成一个,简化开发。目前的代码库被分解成了多个库,容易出现源代码的管理问题。

  • 应用程序数据共享,通过跨进程共享通用类的元数据,减少空间占用及启动时长。

  • 线程本地握手,不执行全局 VM 安全点也能对线程执行回调,同时实现单线程停止回调。

  • JDK 提供了一组默认证书,开源 Java SE 的 CA程序,对开发人员更具吸引力。

这些新特性,目前项目中应用还不是很急迫的事情,所以,抓紧打好基础,准备慢慢攻坚吧。

Good Luck To You !



以上是关于Java大版本更新之新功能特性总览(JDK5-JDK10)的主要内容,如果未能解决你的问题,请参考以下文章

Spring 特性总览

Java8中你可能不知道的一些地方之接口默认方法实战

Java 9 中的 9 个新特性

Spring Boot 2.0深度实践之核心技术篇

JAVA在哪一个版本更新力度比较大 由1.X版本直接升级为5.0版本

算法模板学习专栏之总览(会慢慢陆续更新ing)