【JAVA】JDK11新特性个人分析(一)

简介: 【JAVA】JDK11新特性个人分析

历史背景

2018年9 月 26 日,Oracle 官方宣布 Java 11 正式发布。这个版本中一共包含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)

JDK 11 是一个长期支持版本(LTS, Long-Term-Support),在编写本文的时间节点下和JDK17一样被用于编写项目代码的主流版本。

本文结合了各方资料整理出JDK11的新特性,工作上使用高版本JDK的机会确实不多,但是自己体验的过程中确实切身体会到JDK升级的好处。

升级JDK11的意义

  • 大量的新特性、Bug 修复,例如,容器环境支持,GC 等基础领域的增强。
  • 安全协议更新,比如废弃TLS1.2中不安全的加密算法,部分支持TLS1.3协议。
  • JVM的零成本优化。
  • 划时代的垃圾收集器ZGC,关键目的是实现GC时间不超过10ms。
  • G1垃圾收集器的免费升级
  • 并行的 Full GC(JDK11之前Oracle没有考虑过G1需要并行Full GC)
  • 快速的 CardTable 扫描
  • 自适应的堆占用比例调整(IHOP)
  • 在并发标记阶段的类型卸载
  • JVM自带工具增强
  • JEP 328: Flight Recorder(JFR),商用版工具JFR转为开源。
  • JEP 331: Low-Overhead Heap Profiling 实现底层成本堆分析JVM扩展
  • TLS协议精简
  • 完善Java标准HTTP类库上的扩展能力。
  • JEP 332: Transport Layer Security (TLS) 1.3,完全支持TLS 1.3(协议部分部分支持,加密算法部分基本满足要求)。
  • HTTP/2 Client API
  • 完善了Java语言自身进行Http Client的能力
  • 等同于把HttpClient官方化(难听点就是搬来了)
  • 只要不写作者,谁也不知道自己写的还是抄的谁的
  • 废弃Nashorn JavaScript引擎
  • 实际上是全力推动Graal VM虚拟机的开发。

升级内容

下面就是根据"JEP(JDK Enhancement Proposals,JDK 增强提案)"进行介绍。关于原始的提案名称,这里放到了“附录”部分。

新特性

JEP 309: Dynamic Class-File Constants 类文件新结构

属于JVM层面的优化,简单了解即可。下面是搜集到的的一些国外网站的解释:

Dynamic class-file constants JEP 309 extends the existing Java class-file format, creating CONSTANT_Dynamic. This is a JVM feature and doesn't depend on the higher software layers. The loading of CONSTANT_Dynamic delegates the creation of a bootstrap method. When comparing it to the invokedynamic call, you will see how it delegates linking to a bootstrap method. One of the main goals of dynamic class-file constants is to make it simple to create new forms of materializable class-file constants, which provides language designers and compiler implementers with broader options for expressivity and performance. This is achieved by creating a new constant pool form that can be parameterized using a bootstrap method with static arguments.

下面是简单概括和了解:

动态类文档常量: JEP 309扩展了现有的Java类文档格式,创建了CONSTANT_Dynamic。这是JVM 功能,不依赖于更高的软件层。加载CONSTANT_Dynamic委派引导方法的创建。将其与动态调用进行比较时,将看到它如何委托链接到引导方法。动态类文档常量的主要目标之一,是使创建可具体化的类文档常量的新形式变得简单,这为语言设计者和编译器实现者提供了更广泛的表达性和性能选项。

这是通过创建一个新的常量池形式来实现的,该表单可以使用带有静态参数的引导方法进行参数化。

其目标是降低开发新形式的可实现类文件约束带来的成本和干扰

这里的介绍还是不是很懂,所以我又找了一篇英文博客,它阐述了从JDK7出现的invokeDynamic指令到JDK11的新指令出现的含义。

动手 Java 11 的常量动态 - Java 代码极客 - 2023 (javacodegeeks.com)

Java的指令集新增基本都是大动作,作为对比个人联想到JDK7出现的新指令invokedynamic,周志明的《深入理解JVM虚拟机》中介绍了这个指令,并且JDK8以此为基础实现了Lambada语法。

下面是原书中有关invokedynamic的介绍:

invokedynamic指令是在JDK 7时加入到字节码中的,当时确实只为了做动态语言(如JRuby、 Scala)支持,Java语言本身并不会用到它。而到了JDK 8时代,Java有了Lambda表达式和接口的默认方 法,它们在底层调用时就会用到invokedynamic指令,这时再提动态语言支持其实已不完全切合,我们 就只把它当个代称吧。

所以从JDK11的这一次变动来看,又是一次类似 invokedynamic 的大更新?

JEP 323: Local-Variable Syntax for Lambda Parameters

注意是“语法糖”,实际Class字节码中会被识别为正确的数据类型,并不是变为弱类型语言了,Java依旧是强类型语言

这个改进主要目的实际上是侧重于Lambada的缺陷改善,下面通过实际代码演示进行介绍:


var javastack = "javastack";
System.out.println(javastack);

局部变量类型推断指的是左边的类型直接使用 var 定义,而不用写具体的类型,编译器能根据右边的表达式自动推断类型,如上面的 String 。


var javastack = "javastack";

就等于:


String javastack = "javastack";

var的变量还对于Lambada语法进行了更多改进,声明隐式类型的lambda表达式的形参时允许使用var。使用var的好处是在使用lambda表达式时给参数加上注解

比如我们常见的隐式类型的写法如下,JDK11之前都只能是这样的“隐式类型”写法:


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

有声明var之后,从表面上看可以让变量“可读性”变强了一点:


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

实际上有了“变量类型”之后,之前Java版本无法给Lambada表达式的隐式变量进行标记的问题就得到解决:


(@Deprecated var x, @Nullable var y) -> x.process(y)

另外这里扩展一下JDK的非Lambada的声明隐式类型,这是属于Java10出现的东西,具体含义下面的代码一看便知:


var foo = new Foo(); 
for (var foo : foos) { ... } 
try (var foo = ...) { ... } catch ...

这样的写法可以使得我们改变对象的时候更小概率改动遍历的代码,比如之前需要使用DtoA做遍历,现在里面的数据包装为Dtob了,这时候只需要动for循环里面的内容即可。

JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms 实现RFC7539中指定的ChaCha20和Poly1305两种加密算法, 代替RC4

阅读这一节内容建议读者先有个印象: Java 11(2018年9 月 26 日) 和  TLS1.3 标准发布(2018年12月20日 · TLS1.3 正式版发布)

  • ChaCha20: 是 Google 设计的另一种加密算法,密钥长度固定为 256 位,纯软件运行性能要超过 AES,在ARMv8引擎升级之后,AES也飞速提升导致ChaCha20被反超。所以现在来看虽然优势不大,但是依然不错的一个算法。
  • Poly1305:是由Daniel Bernstein创建的消息身份验证代码(MAC)。Poly1305 采用 32 字节的一次性密钥和一条消息来生成 16 字节的标记。然后使用该标记对消息进行身份验证。每当Poly1305用作MAC算法时,都需要为完整性密钥分配256位。(引自:Poly1305

题外话:为什么ChaCha20和Poly1305在TLS1.3中合并为一个算法 ChaCha20-Poly1305? 其实很好理解,就好比两个运动员,一个专注长跑,另一个擅长短跑,一合体不就“无敌”了么, ChaCha20-Poly1305就是两个算法取长补短的效果,并且单独分开也是目前非常安全的算法。

RFC7539 也就是IETF制定的TLS1.2的协议标准名称。RC4在很早之前就已经被证实存在漏洞,后面已经被废弃了。

看到这部分的时候,个人联想到之前学习的[[HTTP 面试题 - TLS1.3 初次解读]]的内容。TLS1.3不是把这两个合并成ChaCha20-Poly1305了么,并且它是TLS1.3 IETF指定的AEAD算法,JDK又是如何看待这个问题的呢?

个人抱着这个疑问查阅了JDK官方issue的,最终在下面的连接中找到了答案:

[JDK-8140466] ChaCha20 and Poly1305 TLS Cipher Suites - Java Bug System (openjdk.org)


Fix request (11u)
I would like to backport this to 11u because of Chacha20 and Poly1305 cipher suite SHOULD be implemented for TLSv1.3 according to rfc8446
Original patch applies almost clean except for the CipherSuite.java test - the list of cipher suites was reordered by JDK-8210632
Also, CheckCipherSuites.java and CipherSuitesInOrder.java tests are updated to support CHACHA20 cipher suites.
RFR: https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2021-June/006644.html

翻译过来:

我想将其向后移植到 11u,因为 Chacha20 和 Poly1305 密码套件应该根据 rfc8446 为 TLSv1.3 实现 原始补丁(差不多)可以正常应用,除了 CipherSuite.java 测试 - 密码套件列表由 JDK-8210632 重新排序 此外,CheckCipherSuites.java 和 CipherSuitesInOrder.java 测试也进行了更新,以支持 CHACHA20 密码套件。

当然顺带也查到了JDK代码改动提交地址,感兴趣代码改动细节可以看这一段代码:hg.openjdk.org/jdk/jdk/rev…

ChaCha20-Poly1305 算法,它是TLS 1.3 支持的AEAD算法。

最后是JDK的一段案例程序:


/**  
 * XECPublicKey 和 XECPrivateKey  
 * RFC7748定义的秘钥协商方案更高效, 更安全. JDK增加两个新的接口  
 */  
public class XECPublicKeyAndXECPrivateKeyTest {  
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {  
        generateKeyPair();  
    }  
    private static void generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {  
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");  
        NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");  
        kpg.initialize(paramSpec);  
        KeyPair kp = kpg.generateKeyPair();  
        PublicKey publicKey = generatePublic(paramSpec);  
        generateSecret(kp, publicKey);  
    }  
    private static void generateSecret(KeyPair kp, PublicKey pubKey) throws InvalidKeyException, NoSuchAlgorithmException {  
        KeyAgreement ka = KeyAgreement.getInstance("XDH");  
        ka.init(kp.getPrivate());  
        ka.doPhase(pubKey, true);  
        byte[] secret = ka.generateSecret();  
        // [B@10a035a0  
        System.out.println(secret);  
    }  
    private static PublicKey generatePublic(NamedParameterSpec paramSpec) throws NoSuchAlgorithmException, InvalidKeySpecException {  
        KeyFactory kf = KeyFactory.getInstance("XDH");  
        BigInteger u = new BigInteger("111");  
        XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);  
        PublicKey pubKey = kf.generatePublic(pubSpec);  
        return pubKey;  
    }  
}

JEP 332: Transport Layer Security (TLS) 1.3

实际情况可以看看曾经负责过Java的安全开发工作的大佬文章:

An example of TLS 1.3 client and server on Java | The blog of a gypsy engineer

个人曾经在[[HTTP 面试题 - TLS1.3 初次解读]]对这位大佬做了一些简单阐述,并且建议看这部分内容前对于TLS1.3一定的了解,可能会有更深的印象。

根据作者所说就是Java11实现是实现了TLS1.3,但是是个“残血版”,比如不支持下面的特性:

  • 0-RTT data 0-RTT 数据
  • Post-handshake authentication 握手后认证
  • Signed certificate timestamps (SCT) 签名证书时间戳 (SCT)
  • ChaCha20/Poly1305 cipher suites (targeted to Java 12) ChaCha20/Poly1305 密码套件(针对 Java 12
  • x25519/x448 elliptic curve algorithms x25519/x448 椭圆曲线算法(针对 Java 12
  • edDSA signature algorithms edDSA 签名算法(针对 Java 12

但是从好的方面来看,Java11已经完全具备兼容TLS1.3的条件,因为这些不支持的仅仅是小部分内容,实际上大部分TLS1.3指定的最新加密套件都是支持的,使用者只需要改改“静态参数”,即可完成TLS1.2到TLS1.3的升级兼容。

提示:为了防止误解,这里个人有必要补充一下。ChaCha20/Poly1305 并不是说JDK12才真正实现ChaCha20和Poly1305,ChaCha20/Poly1305不是ChaCha20+Poly1305,虽然本质上是融合到一块,但是实际上一个全新的算法。

另外这一波也怪不到Oracle,谁让TLS1.3比JDK11晚发布3个月呢。

JEP 321: HTTP Client (Standard) 标准Java异步HTTP客户端

这是自JDK9被引进孵化,直到JDK11才正式可用的处理 HTTP 请求的的 HTTP Client API,如小节标题所说,它支持同步和异步发送。

因为是跨越多个大版本的改建,Java11标准Java异步HTTP客户端最终被叫做 HTTP/2 Client。它定义了一个全新的实现了HTTP/2和WebSocket的HTTP客户端API,并且可以取代 HttpURLConnection。

过去HttpURLConnection 被人诟病的点如下:

  • API 早于HTTP1.1 过于抽象。(HTTP1.0是草稿协议,没有被标准化)
  • API 难懂,编写的代码难以维护。
  • 过度设计,很多支持的协议到现在基本只剩下HTTP。

java.net 包中可以找到这些 API,但是我并没有看到作者是谁=-=。


public class JdkHttpClient {  
    public static void main(String[] args) throws IOException, InterruptedException {  
        var request = HttpRequest.newBuilder()  
                .uri(URI.create("https://cn.bing.com/?mkt=zh-CN"))  
                .GET()  
                .build();  
        var client = HttpClient.newHttpClient();  
// 同步  
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());  
        System.out.println(response.body());  
// 异步  
        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())  
                .thenApply(HttpResponse::body)  
                .thenAccept(System.out::println);  
    }/**  
        截取部分内容:  
     //]]></script><script type="text/rms">//<![CDATA[  
     var sj_appHTML=function(n,t){var f,e,o,r,i,s,h;if(t&&n){var c="innerHTML",l="script",a="appendChild",v="length",y="src",p=sj_ce,u=p("div");if(u[c]="<br>"+t,f=u.childNodes,u.removeChild(f[0]),e=u.getElementsByTagName(l),e)for(o=0;o<e[v];o++)r=p(l),i=e[o],i&&(r.type=i.type=="module"||i.type=="importmap"?
     Process finished with exit code 0  
     */}

JDK官方给JDK引入HTTP Client API了,以后还有必要用 Apache 的 HttpClient 工具包么?

JEP 331: Low-Overhead Heap Profiling 低成本的堆分析

官方说明:JEP 331: Low-Overhead Heap Profiling (openjdk.org)

Provide a low-overhead way of sampling Java heap allocations, accessible via JVMTI.

官方的介绍是说通过JVMTIsampling提供低堆内存开销的分析工具。

为什么有了如Java Flight Recorder、YourKit和VisualVM等非常实用的JVM分析工具,JDK官方还需要提供接口扩展堆分析的手段呢?

One piece of information that is lacking from most of the existing tooling is the call site for particular allocations. Heap dumps and heap histograms do not contain this information.

关键原因在于大多数的分析工具缺少particular allocations,这里的特定分配在个人的理解是“堆外”内存的分配,因为这部分是超出JVM管辖范围内直接通过操作系统底层往物理内存分配。

现代的消息中间件Kafka、RocketMq等底层大量使用了页缓存这个东西,并且进行了大量的直接内存分配,不巧的是这部分内容刚好是JVM堆内存分析工具的痛点。所以JDK开发扩展这些接口也是时代发展的趋势之一。

This proposal mitigates these problems by providing an extensible JVMTI interface that allows the user to define the sampling interval and returns a set of live stack traces.

通过提供一个可扩展的JVMTI接口来缓解这些问题,该接口允许用户定义采样间隔并返回一组实时堆栈跟踪。

因为用的是JVM对外接口,所以这个接口是C++写的,在Use-case example里面有很多的接入案例代码,如果不是要开发JVM堆分析工具,我们了解到这就可以收住了。

低成本的堆分析主要目标:

  • 开销低,可以持续默认启用。
  • 可以通过一个定义明确的程序化接口访问。
  • 可以对所有分配进行采样(即,不限于在某一特定堆区域的分配或以某一特定方式的分配)。
  • 可以以独立于实现的方式进行定义(即,不依赖于任何特定的GC算法或虚拟机实现),并且可以提供关于存活Java对象和垃圾Java对象的信息。

最终的实现如下:

  • 提供用于生产和消费数据作为事件的API
  • 提供缓存机制和二进制数据格式
  • 允许事件配置和事件过滤
  • 提供OS,JVM和JDK库的事件

新增内容

JEP 330: Launch Single-File Source-Code Programs 启动单一文件的源代码程序

提案愿意是:增强java启动器支持运行单个java源代码文件的程序。这是什么意思?在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行两步执行动作。JDK11简化了允许java程序编译运行的过程。

这个功能是免去了Java初学者需要javac和Java运行class文件的步骤,直接java 类名即可编译运行,但是需要注意这种增强需要满足一定条件:

  • 第一点:执行源文件中的第一个类,第一个类必须包含main方法,比如下面的代码main方法在Test2当中就无法使用此特性:


class Test1 {  
    public void otherMethod(){  
    }  
}  
class Test2 {  
    public static void main(String[] args) throws IOException {  
    }  
}
  • 第二点:不可以使用别源文件中的自定义类, 但是当前文件中的自定义类是可以使用的。

到JDK10为止,Java启动器能以三种方式运行,JDK11补齐了另一块短板:

  1. 启动一个class文件;
  2. 启动一个JAR中的main方法类;
  3. 启动一个模块中的main方法类;
  4. 启动java命令直接运行源码级别的Java文件(JDK11)

补充:只要是Java程序,无论多复杂,最终入口一定是main()。

JEP 327: Unicode 10

Unicode 10 增加了8518个字符, 总计达到了136690个字符,并且增加了4个脚本,同时还有56个新的emoji表情符号。

参考:unicode.org/versions/Un…

JEP 328: Flight Recorder

英文名称直译过来是“飞行记录仪”,没错就是我们日常生活中的黑匣子。

在JDK11之前是一个商业版的特性,在java11当中开源出来,它可以导出事件到文件中,之后配合Java Mission Control来分析。

使用Flight Recorder 有两种方式:

  • 应用启动时配置java -XX:StartFlightRecording


-XX: +StartFlightRecording=filename=<path>, duration=<time>
  • 使用jcmd来录制
  • $ jcmd  JFR.start
  • $ jcmd  JFR.dump filename=recording.jfr
  • $ jcmd  JFR.stop


Jcmd <pid> JFR.start filename=<path> duration=<time>

扩展:Java Flight Recorder - Javatpoint

感兴趣可以看看下面的文章介绍的简单的JFR使用教程,但是注意是JDK8 的:

工具篇-性能分析工具JFR和JMC - 麦奇 (mikeygithub.github.io)

实战 JFR

首先是编写一段JFR的测试案例代码:


/**  
 * JFR 的测试程序  
 * 需要使用JDK11以上的版本  
 * <p>  
 * src/main/java/com/zxd/interview/jfr/JfrTestApplication.java  
 */
public class JfrTestApplication {  
    public static void main(String[] args) {  
        List<Object> items = new ArrayList<>(1);  
        try {  
            while (true){  
                items.add(new Object());  
            }  
        } catch (OutOfMemoryError e){  
            System.out.println(e.getMessage());  
        }  
        assert items.size() > 0;  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            System.out.println(e.getMessage());  
        }  
    }  
}

为了编译成功需要删除中文内容:


/**  
 * JFR 的测试程序  
 * 需要使用JDK11以上的版本  
 *  
 * src/main/java/com/zxd/interview/jfr/JfrTestApplication.java */

运行之后发现报错,这是因为中文导致的问题,这里把中文注释掉之后就OK了。


D:\adongstack\project\interview>javac -d out -sourcepath src/main src/main/java/com/zxd/interview/jfr/JfrTestApplication.java
src\main\java\com\zxd\interview\jfr\JfrTestApplication.java:7: error: unmappable character (0x8F) for encoding GBK
 * JFR 鐨勬祴璇曠▼搴?
              ^
src\main\java\com\zxd\interview\jfr\JfrTestApplication.java:8: error: unmappable character (0x80) for encoding GBK
 * 闇?瑕佷娇鐢↗DK11浠ヤ笂鐨勭増鏈?
    ^
src\main\java\com\zxd\interview\jfr\JfrTestApplication.java:8: error: unmappable character (0xAC) for encoding GBK
 * 闇?瑕佷娇鐢↗DK11浠ヤ笂鐨勭増鏈?

通过下面的命令执行,编译JfrTestApplication:


java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr -cp ./out/ com/zxd/interview/jfr/JfrTestApplication

运行结果:


D:\adongstack\project\interview>java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr -cp ./out/ com/zxd/interview/jfr/JfrTestApplication
Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UnlockCommercialFeatures; support was removed in 11.0
Started recording 1. The result will be written to:
D:\adongstack\project\interview\flight.jfr
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
[70.761s][warning][jfr,system,event] Exception occured during execution of period hook for jdk.ThreadContextSwitchRate(345)

因为程序执行的是一个“死循环”,安静等待执行死循环直到OOM即可。执行完成之后,在Idea的项目根路径当中会出现下面的文件内容:


这个文件要如何阅读?这里要用JDK的另一个工具JMC。令人遗憾的是,JFR为JDK自带的工具,但是JMC需要我们自己去Oracle官网下载(JMC被官方从JDK中移除)。

JMC安装

下载链接:www.oracle.com/java/techno…

这里直接下载当前的最新版本即可。

image.png

Windows平台直接打开程序:

image.png

看到下面的界面说明可以正常使用:

image.png

Java Mission Control 分析代码

进入主界面,我们直接打开刚刚生成的jfr文件:

image.png

首先是一份报告,简单介绍了jfr的情况:

image.png


Application efficiency was affected by halts
The highest ratio of application halts to execution time was 84.7 % during 2023/3/13 下午9:11:53.000 – 下午9:12:53. 2.59 % of the halts were for reasons other than GC. The halts ratio for the entire recording was 86.6 %. 2.21 % of the total halts were for reasons other than GC. Application halts are often caused by garbage collections, but can also be caused by excessive thread dumps or heap dumps. Investigate the VM Operation information and possibly the safepoint specific information.

报告主要说明了整个应用程序大部分的时间都是在进行停顿,也就是对象的分配速度远远高于垃圾回收速度,垃圾收集器长时间工作而出现停顿和等待。

因为我们是while的死循环程序,可以明显CPU使用率逐渐飙升。

image.png

我们可以阅读“方法调用的统计信息”来查看整个死循环的过程中哪些方法被大量调用:

image.png

通过“方法”板块我们可以发现示例程序的另一个缺点:方法java.util.ArrayList.grow(int)已被调用147次,在每次没有足够的空间添加对象时扩大数组容量。

image.png

我们可能会看到许多其他有用的信息:

  • 有关创建对象的统计信息,当垃圾回收器创建和销毁这些对象时
  • 有关线程年表的详细报告,它们何时被锁定或处于活动状态
  • 应用程序正在执行哪些 I/O 操作

【JAVA】JDK11新特性个人分析(二)https://developer.aliyun.com/article/1395281



相关文章
|
9天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
26 2
|
10天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
27 3
|
10天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
21 2
|
1天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
7 2
|
4天前
|
Java API 开发者
Java 8新特性之Stream API详解
【10月更文挑战第22天】Java 8引入了重要的Stream API,用于处理集合数据。本文分三部分介绍:基本概念与原理、使用方法及应用实例。Stream API支持延迟执行、惰性求值,提供过滤、映射、排序、聚合等操作,使代码更简洁、易读。文中详细讲解了创建Stream、中间操作、终端操作以及具体应用场景,如排序、过滤、映射和聚合。
10 3
|
7天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
22 3
|
5天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
[Java]静态代理与动态代理(基于JDK1.8)
|
7天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
14 2
|
10天前
|
Java 开发者
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素。通过哈希表和红黑树两种模式,Set能够高效地识别并拒绝重复元素的入侵,确保集合的纯净。无论是HashSet还是TreeSet,都能在不同的场景下发挥出色的表现,成为开发者手中的利器。
22 2
|
10天前
|
Java
Java Set以其“不重复”的特性,为我们提供了一个高效、简洁的处理唯一性约束数据的方式。
【10月更文挑战第16天】在Java编程中,Set接口确保集合中没有重复元素,每个元素都是独一无二的。HashSet基于哈希表实现,提供高效的添加、删除和查找操作;TreeSet则基于红黑树实现,不仅去重还能自动排序。通过这两个实现类,我们可以轻松处理需要唯一性约束的数据,提升代码质量和效率。
22 2