JDK

JDK5

JDK6

  • JAVA逃逸分析
    逃逸分析(Escape Analysis)简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术
    逃逸分析的 JVM 参数如下:
    开启逃逸分析:-XX:+DoEscapeAnalysis
    关闭逃逸分析:-XX:-DoEscapeAnalysis
    显示分析结果:-XX:+PrintEscapeAnalysis

    逃逸分析技术在 Java SE 6u23+ 开始支持,并默认设置为启用状态,可以不用额外加这个参数。
    对象的逃逸状态
    1、全局逃逸(GlobalEscape)
    即一个对象的作用范围逃出了当前方法或者当前线程,有以下几种场景:
    对象是一个静态变量
    对象是一个已经发生逃逸的对象
    对象作为当前方法的返回值
    2、参数逃逸(ArgEscape)
    即一个对象被作为方法参数传递或者被参数引用,但在调用过程中不会发生全局逃逸,这个状态是通过被调方法的字节码确定的。
    3、没有逃逸
    即方法中的对象没有发生逃逸。
    逃逸分析优化
    当一个对象没有逃逸时,可以得到以下几个虚拟机的优化
  1. 锁消除
    我们知道线程同步锁是非常牺牲性能的,当编译器确定当前对象只有当前线程使用,那么就会移除该对象的同步锁。
    例如,StringBuffer 和 Vector 都是用 synchronized 修饰线程安全的,但大部分情况下,它们都只是在当前线程中用到,这样编译器就会优化移除掉这些锁操作。
    锁消除的 JVM 参数如下:
    开启锁消除:-XX:+EliminateLocks
    关闭锁消除:-XX:-EliminateLocks
    锁消除在 JDK8 中都是默认开启的,并且锁消除都要建立在逃逸分析的基础上。

  2. 标量替换
    首先要明白标量和聚合量,基础类型和对象的引用可以理解为标量,它们不能被进一步分解。而能被进一步分解的量就是聚合量,比如:对象。
    对象是聚合量,它又可以被进一步分解成标量,将其成员变量分解为分散的变量,这就叫做标量替换。
    这样,如果一个对象没有发生逃逸,那压根就不用创建它,只会在栈或者寄存器上创建它用到的成员标量,节省了内存空间,也提升了应用程序性能。
    标量替换的 JVM 参数如下:
    开启标量替换:-XX:+EliminateAllocations
    关闭标量替换:-XX:-EliminateAllocations
    显示标量替换详情:-XX:+PrintEliminateAllocations
    标量替换同样在 JDK8 中都是默认开启的,并且都要建立在逃逸分析的基础上。

  3. 栈上分配
    当对象没有发生逃逸时,该对象就可以通过标量替换分解成成员标量分配在栈内存中,和方法的生命周期一致,随着栈帧出栈时销毁,减少了 GC 压力,提高了应用程序性能。

JDK7

  • switch 支持String。

JDK8

java8最大的特性就是引入Lambda表达式,即函数式编程,可以将行为进行传递。总结就是:使用不可变值与函数,函数对不可变值进行处理,映射成另一个值。

  • Stream
    基于lambda表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。
    Stream的原理:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

集合有两种方式生成流:
stream() − 为集合创建串行流
parallelStream() - 为集合创建并行流

中间操作主要有以下方法(此类型方法返回的都是Stream):map (mapToInt, flatMap 等)、 filter(过滤)、 distinct(去重)、 sorted、 peek、 limit(返回指定流个数)、 skip(跳过流中的元素)、 parallel、 sequential、 unordered

终止操作主要有以下方法:forEach、 forEachOrdered、 toArray、 reduce(将流中的元素组合起来)、 collect、 min、 max、 count(流中元素的个数)、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

代码演示

@Data
public class Dish {
    private String name;
    private boolean vegetarian;
    private int calories;
}
 private List afterJava8(List dishList) {
        return dishList.stream()
                .filter(d -> d.getCalories() < 400)  //筛选出卡路里小于400的菜肴
                .sorted(comparing(Dish::getCalories))  //根据卡路里进行排序
                .map(Dish::getName)  //提取菜肴名称
                .collect(Collectors.toList()); //转换为List
    }

Optional

Optional 类主要解决的问题是空指针异常(NullPointerException),本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步

  1. 使用Optional工厂的of() 和 ofNullable() 方法创建包含值的 Optional对象。两个方法的不同之处在于如果你把 null 值作为参数传递进去,of() 方法会抛出NullPointerException
  2. 访问 Optional 对象的值
    从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法。但是这个方法会在值为 null 的时候抛出异常。验证是否有值一个方法是isPresent(),另一个方法是ifPresent(u->method()),该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式:
  3. orElse(method())
    它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值
  4. orElseGet(()->method())
    这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果
  5. 比较上面两个方法
    当对象为空时,两个并没有什么差别,但是当对象不为空时前者会继续调用,尔后者不会。
    6: orElseThrow(()->new Exception()) :它会在对象为空的时候抛出异常,而不是返回备选的值:这个方法让我们可以决定抛出什么样的异常,而不总是抛出NullPointerException。

转换值

  1. map()
    JDK_第1张图片map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 —— 这里的下一环就是 orElse()。
  2. flatMap()
  3. filter()

JDK9

Optional

Java 9 为 Optional 类添加了三个方法:or()、ifPresentOrElse() 和 stream()。
1: or() 方法与 orElse() 和 orElseGet() 类似,它们都在对象为空的时候提供了替代情况。or() 的返回值是由 Supplier 参数产生的另一个 Optional 对象。
2: ifPresentOrElse() 方法需要两个参数:一个 Consumer 和一个 Runnable。如果对象包含值,会执行 Consumer 的动作,否则运行 Runnable。
3: stream() 方法,它通过把实例转换为 Stream 对象,让你从广大的 Stream API 中受益。如果没有值,它会得到空的 Stream;有值的情况下,Stream 则会包含单一值。

JDK10

JDK11

JDK12

  • 文件对比
public static void main(String[] args) throws IOException {
    Path dir = Paths.get("d:/");
    Path path1 = dir.resolve("javastack1.txt");
    Path path2 = dir.resolve("javastack2.txt");
    long result = Files.mismatch(path1, path2);
    System.out.println(result);
}

Files.mismatch方法源码如下:

public static long mismatch(Path path, Path path2) throws IOException {
    if (isSameFile(path, path2)) {
        return -1;
    }
    byte[] buffer1 = new byte[BUFFER_SIZE];
    byte[] buffer2 = new byte[BUFFER_SIZE];
    try (InputStream in1 = Files.newInputStream(path);
         InputStream in2 = Files.newInputStream(path2);) {
        long totalRead = 0;
        while (true) {
            int nRead1 = in1.readNBytes(buffer1, 0, BUFFER_SIZE);
            int nRead2 = in2.readNBytes(buffer2, 0, BUFFER_SIZE);

            int i = Arrays.mismatch(buffer1, 0, nRead1, buffer2, 0, nRead2);
            if (i > -1) {
                return totalRead + i;
            }
            if (nRead1 < BUFFER_SIZE) {
                // we've reached the end of the files, but found no mismatch
                return -1;
            }
            totalRead += nRead1;
        }
    }
}

解释:返回-1:同一文件,或者两个文件内容一样;其他数字:文件内容对比差异的位置,从0开始

  • switch 有以下几点特色:
    箭头语法 ->,类似 Java 8 中的 Lambda 表达式;
    可以直接返回值给一个变量,并且可以不用 break 关键字;
    case 条件,多个可以写在一行,用逗号分开;
    可以省略 break 关键字;
    当然你也可以使用 break 关键字,后面跟值(不推荐):
private static void testSwitch3(Status status) {
    var result = switch (status) {
        case OPEN -> {
            break 1;
        }
        case PROCESS, PENDING -> {
            break 2;
        }
        case CLOSE -> {
            break 3;
        }
        default -> {
            break 5;
        }
    };
    System.out.println("result is " + result);
}

JDK13

private static void testSwitch2(Status status) {
    var result = switch (status) {
        case OPEN -> 1;
        case PROCESS, PENDING -> 2;
        case CLOSE -> 3;
        default -> throw new RuntimeException("状态不正确");
    };
    System.out.println("result is " + result);
}
  • 文本块升级
    1:html例子
JDK13之前

String html = "\n" +
              "    \n" +
              "        

Hello, world

\n"
+ " \n" + "\n"; JDK13优化的: String html = """ <html> <body> <p>Hello, world</p> </body> </html> """;

2:SQL变化

JDK13之前

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";
JDK13

String query = """
                SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
                WHERE `CITY` = 'INDIANAPOLIS'
                ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

3:解释

文本块
"""
line 1
line 2
line 3
"""
相当于字符串文字:

"line 1\nline 2\nline 3\n"
  • 动态CDS档案
    目标:
    提高应用程序类 - 数据共享(AppCDS)的可用性。消除了用户进行试运行以创建每个应用程序的类列表的需要。
    -Xshare:dump
    使用类列表由该选项启用的静态归档应继续工作。这包括内置类加载器和用户定义的类加载器的类。
  • 取消使用未使用的内存
摘要:增强ZGC以将未使用的堆内存返回给操作系统。
动机:ZGC目前没有取消提交并将内存返回给操作系统,即使该内存长时间未使用。对于所有类型的应用程序和环境,此行为并非最佳, 尤其是那些需要关注内存占用的应用程序和环境 例如:通过使用支付资源的容器环境。应用程序可能长时间处于空闲状态并与许多其 他应用程序共享或竞争资源的环境。应用程序在执行期间可能具有非常不同的堆空间要求。
例如:启动期间所需的堆可能大于稳态执行期间稍后所需的堆。HotSpot中的其他垃圾收集器,如G1和Shenandoah,今天提供 了这种功能,某些类别的用户发现它非常有用。将此功能添加到ZGC将受到同一组用户的欢迎。
  • 重新实现旧版套接字API
摘要:使用更简单,更现代的实现替换java.net.Socket和java.net.ServerSocketAPI 使用的底层实现,易于维护和调试。新的实现很容易适应用户模式线程,也就是光纤,目前正在Project Loom中进行探索。
动机:在java.net.Socket和java.net.ServerSocketAPI,以及它们的底层实现,可以追溯到JDK 1.0。实现是遗留Java和C代码的混合,维护和调试很痛苦。该实现使用线程堆栈作为I/O缓冲区,这种方法需要多次增加默认线程堆栈大小。
  • FileSystems.newFileSystem新方法
核心库/ java.nio中添加了FileSystems.newFileSystem(Path,Map )方法

添加了三种新方法java.nio.file.FileSystems,以便更轻松地使用将文件内容视为文件系统的文件系统提供程序。

1newFileSystem(Path)
2newFileSystem(Path, Map)
3newFileSystem(Path, Map, ClassLoader)
添加为newFileSystem(Path, Map<String, ?>) 已使用现有newFileSystem(Path, ClassLoader)并指定类加载器 的代码创建源(但不是二进制)兼容性问题。例如,由于引用newFileSystem不明确,因此无法编译以下内容:

FileSystem fs = FileSystems.newFileSystem(path, null); 
为了避免模糊引用,需要修改此代码以将第二个参数强制转换为java.lang.ClassLoader。
  • nio新方法
    核心库/ java.nio中新的java.nio.ByteBuffer批量获取/放置方法转移字节而不考虑缓冲区位置。
    java.nio.ByteBufferjava.nio现在,其他缓冲区类型定义绝对批量get和put传输连续字节序列的方法,而不考虑或影响缓冲区位置。
  • 安全库/ java.security
1 该com.sun.security.crl.readtimeout系统属性设置为CRL检索的最大读取超时,单位为秒。如果尚未设置该属性,或者其值为负,则将其设置为默认值15秒。值0表示无限超时。
2 新的keytool -showinfo -tls用于显示TLS配置信息的命令keytool -showinfo -tls添加了一个显示TLS配置信 息的新命令。
3 SunMSCAPI提供程序现在支持以下一代加密(CNG)格式读取私钥。这意味着CNG格式的RSA和EC密钥可从Windows密钥 库加载,例如“Windows-MY”。与EC(签名算法SHA1withECDSA,SHA256withECDSA等等)也支持。

你可能感兴趣的:(JDK)