Java8以后各个版本新特性

739 阅读5分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

1.JDK

jdk的发布周期

OpenJDK和OracleJDK

区别如下:

  • OracleJDK每3年发布一次稳定版本,OpenJDK每3个月发布一次
  • OracleJDK支持LTS(Long-Trem-Support),OpenJDK只支持档期版本至下一个版本发布
  • OracleJDK采用Oracle Binary Code License协议,OpenJDK采用GPL v2协议
  • OracleJDK基于OpenJDK构建

Android和JDK

Android最开始使用Java版本基于Apache协议发布的Harmony,从Android N开始使用OpenJDK

JAVA8

1.Lambda和函数式接口

函数式接口就是有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,可以隐式转换为Lambda表达式

定义一个函数式接口

@FunctionalInterface
public interface IOperation {
    int operation(int a, int b);
}

定义操作类

public class OperationImpl {
    public int operation(int a, int b, IOperation operation) {
        return operation.operation(a, b);
    }
}

OperationImpl oImpl = new OperationImpl();

在java8之前操作需要定义匿名实现,

oImpl.operation(1, 2, new IOperation(){
    public int operation(int a, int b) {
        return a + b;
    };
});

使用Lambda表达式之后

oImpl.operation(2, 3, (a, b) -> a + b);

2.方法引用

通过方法应用可以使用方法的名字来指向一个方法,使用一对冒号来应用方法"::"

@FunctionalInterface
public interface IOperation {
    int operation(int a, int b);
}

interface Creator<T> {
    T get();
}

interface TestInt {
    int cp(Test test, Test test2);
}

public class Test {
    public static Test create(Creator<Test> creator) {
        return creator.get();
    }

    public int operation(int a, int b, IOperation operation) {
        return operation.operation(a, b);
    }

    private static int add(int a, int b) {
        return a + b;
    }

    private int sub(int a, int b) {
        return a - b;
    }

    public int testM(Test test) {
        return 0;
    }

    public void test(TestInt testInt) {
        Test t1 = Test.create(Test::new);
        Test t2 = Test.create(Test::new);
        testInt.cp(t1, t2);
    }
}

对应的引用方法

构造方法引用,Class::new

Test test = Test.Create(Test::new);

静态方法引用,Class::staticMethod

test.operation(1, 2, Test::add);

对象的实例引用,instance::method

test.operation(1, 2, test::sub);

类的实例引用,Class::method

test.test(Test::testM);

3.接口默认方法和静态方法

接口通过使用default方法,提供默认方法

public interface KingListener {
    void getName();

    //默认方法
    default void getAge() {
        System.out.println("Age is 1024.");
    }
}

4.重复注解

Java8之前重复注解需要如下:

@interface Author {
    String name();
}

@interface Authors {
    Author[] value();
}

@Authors({@Author(name="a"), @Author(name = "b")})
class Article {
}

Java8之后可采取如下:

@Repeatable(Authors.class)
@interface Author {
    String name();
}

@interface Authors {
    Author[] value();
}

@Author(name = "a")
@Author(name = "b")
class Article {
}

解析注解时,Java8提供新的Api

AnnotatedElement.getAnnotationsByType(Class<T>)

5.类型注解

Java8之前注解智能在声明中,Java8之后可以在任何地方

@Author(name = "a")
private Object name = "";

private String author = (@Author(name="a")String) name;

6.更好的类型推断

Java8更新了类型推断

java7写法如下

List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.addAll(Arrays.<String>asList());

java8后

List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.addAll(Arrays.asList());

7.Optional

Java8中新增了Optional类来解决空指针异常,Optional是一个可以保持null的容器对象。通过isPresent()方法检测值是否存在,通过get()方法获取返回对象

// 创建一个 String 类型的容器
Optional<String> str = Optional.of("str");
// 值是否存在
boolean pre = str.isPresent();
// 值如果存在就调用 println 方法,这里传入的是 println 的方法引用
str.ifPresent(System.out::println);
// 获取值
String res = str.get();
// 传入空值
str = Optional.ofNullable(null);
// 如果值存在,返回值,否则返回传入的参数
res = str.orElse("aa");
str = Optional.of("str");
// 如果有值,对其调用映射函数得到返回值,对返回值进行 Optional 包装并返回
res = str.map(s -> "aa" + s).get();
// 返回一个带有映射函数的 Optional 对象
res = str.flatMap(s -> Optional.of(s + "bb")).flatMap(s -> Optional.of(s + "cc")).get();

8.Stream

Java8中增加了Stream类,提供了新的数据处理方式,可以将元素集合看成一种流,在管道中传输,经过一系列处理节点,最终输出结果

List<String> list = Arrays.asList("maa", "a", "abbb", "cccc");
list.stream().filter(s -> s.contains("a"))
    .map(s -> s + "sb")
    .sorted()
    .forEach(System.out::println);

System.out.println("#####");

list.parallelStream().forEach(System.out::println);

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
int aaaaaa = numbers.stream().map(i -> i + 1).mapToInt(i -> i).summaryStatistics().getMax();
System.out.println(aaaaaa);

9.日期时间Api

LocalDate now = LocalDate.now();
System.out.println(now);
System.out.println(now.getYear());
System.out.println(now.getMonth());
System.out.println(now.getDayOfMonth());

LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalDateTime localDateTime = now.atTime(localTime);
System.out.println(localDateTime);

10.Base64支持

Java8提供了对Base64编码的支持

byte[] base64 = Base64.decode(content, Base64.NO_WRAP);
Base64.encodeToString(data, Base64.NO_WRAP);

11.并行数组ParallelSort

Arrays.parallelSort(new int[] {1, 2, 3, 4, 5});

12.其他新特性

  • 对并发的增强
  • java.util.concurrent.atomic包中增加了

DoubleAccumulator

DoubleAdder

LongAccumulator

LongAdder

  • 提供了新的Nashorn javascript引擎
  • 提供了jjs,是一个给予Nashorn的命令行工具,可以用来执行JavaScript源码
  • 提供了新的类依赖分析工具jdeps
  • JVM新特性,内存永久区被metaspace替换(JEP 122)

\

Java9

1.Jigsaw模块系统

在 Java 9 以前,打包和依赖都是基于 JAR 包进行的。JRE 中包含了 rt.jar,将近 63M,也就是说要运行一个简单的 Hello World,也需要依赖这么大的 jar 包。在 Java 9 中提出的模块化系统,对这点进行了改善。

2.JShell REPL

Java 9 提供了交互式解释器。有了 JShell 以后,Java 终于可以像 Python,Node.js 一样在 Shell 中运行一些代码并直接得出结果了。

3. 私有接口方法,接口中使用私有方法

public interface TestInterface {
    String test();

    // 接口默认方法
    default String defaultTest() {
        pmethod();
        return "default";
    }

    private String pmethod() {
        System.out.println("private method in interface");
        return "private";
    }
}

4. 集合不可变实例工厂方法

在以前,我们想要创建一个不可变的集合,需要先创建一个可变集合,然后使用 unmodifiableSet 创建不可变集合。代码如下:

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");

set = Collections.unmodifiableSet(set);
System.out.println(set);

Java 9 中提供了新的 API 用来创建不可变集合。

List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
Map<String, String> map = Map.of("KA", "VA", "KB", "VB");

5. 改进 try-with-resources

Java 9 中不需要在 try 中额外定义一个变量。Java 9 之前需要这样使用 try-with-resources:

InputStream inputStream = new StringBufferInputStream("a");
try (InputStream in = inputStream) {
    in.read();
} catch (IOException e) {
    e.printStackTrace();
}

在 Java 9 中可以直接使用 inputStream 变量,不需要再额外定义新的变量了。

InputStream inputStream = new StringBufferInputStream("a");
try (inputStream) {
    inputStream.read();
} catch (IOException e) {
    e.printStackTrace();
}

6. 多版本兼容 jar 包

Java 9 中支持在同一个 JAR 中维护不同版本的 Java 类和资源。

7. 增强了 Stream,Optional,Process API

8. 新增 HTTP2 Client

9. 增强 Javadoc,增加了 HTML 5 文档的输出,并且增加了搜索功能

10. 增强 @Deprecated

对 Deprecated 新增了 since 和 forRemoval 属性

11. 增强了钻石操作符 "<>",可以在 匿名内部类中使用了。

在 Java 9 之前,内部匿名类需要指定泛型类型,如下:

Handler<? extends Number> intHandler1 = new Handler<Number>(2) {
}

而在 Java 9 中,可以自动做类型推导,如下:

Handler<? extends Number> intHandler1 = new Handler<>(2) {
}

12. 多分辨率图像 API:定义多分辨率图像API,开发者可以很容易的操作和展示不同分辨率的图像了。

13. 改进的 CompletableFuture API

CompletableFuture 类的异步机制可以在 ProcessHandle.onExit 方法退出时执行操作。

Java 10

1. 新增局部类型推断 var

var a = "aa";
System.out.println(a);

注:var 关键字目前只能用于局部变量以及 for 循环变量声明中。

2. 删除工具 javah

从JDK中移除了 javah 工具,使用 javac -h 代替。

3. 统一的垃圾回收接口,改进了 GC 和其他内务管理

其他特性

ThreadLocal 握手交互

JDK 10 引入一种在线程上执行回调的新方法,很方便的停止单个线程而不是停止全部线程或者一个都不停。

基于Java的实验性JIT编译器

Java 10 开启了 Java JIT编译器 Graal,用作Linux / x64平台上的实验性JIT编译器。

提供默认的 CA 根证书

将 JDK 生态整合到单个仓库

此JEP的主要目标是执行一些内存管理,并将JDK生态的众多存储库组合到一个存储库中。

ava 11

1. Lambda 中使用 var

(var x, var y) -> x.process(y)

2. 字符串 API 增强

Java 11 新增了 一系列字符串处理方法,例如:

// 判断字符串是否为空白
" ".isBlank(); 
" Javastack ".stripTrailing();  // " Javastack"
" Javastack ".stripLeading();   // "Javastack "

3. 标准化 HttpClient API

3. java 直接编译并运行,省去先 javac 编译生成 class 再运行的步骤

3. 增加对 TLS 1.3 的支持

Java12

switch表达式

Java 12 以后,switch 不仅可以作为语句,也可以作为表达式。

private String switchTest(int i) {
    return switch (i) {
        case 1 -> "1";
        default -> "0";
    };
}

总结