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

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

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

JEP 318: Epsilon: A No-Op Garbage Collector Epsilon 垃圾收集器

首先吸引我的是Epsilon这个单词,和CMS、G1这种带有含义的垃圾收集器名称一样,Epsilon 也有特殊的含义。

这个希腊字母同时也是英语音标ɛ的来源,下面的介绍引自:Ε - 维基百科,自由的百科全书 (wikipedia.org)

Epsilon(大写 Ε、小写 ε 或 ϵ;希腊语:έψιλον;中文音译:伊普西龙、厄普西隆、艾普西龙、艾普塞朗),是第五个希腊字母。Epsilon(ἒ ψιλόν)即“e 简单的、e 单一的”的意思,这是为了与中世纪发生单元音化而变为同音的二合字母 ai(αι,古希腊语:[ai̯])做区别,古典时期本来这个字母读作ei(εἶ,古希腊语:[êː]);源自腓尼基字母 HeHe,又从 epsilon 发展出了拉丁字母 E 和西里尔字母 Е。在希腊数字系统中,E 表示 5。

Epsilon 垃圾收集器用法非常简单:


-XX:+UseEpsilonGC

通常建议搭配参数-XX:+UnlockExperimentalVMOptions 使用。

-XX:+UnlockExperimentalVMOptions : 一般使用在一些低版本jdk想使用高级参数或者可能高版本有的参数情况; 解锁实验参数,允许使用实验性参数,JVM中有些参数不能通过-XX直接复制需要先解锁,比如要使用某些参数的时候,可能不会生效,需要设置这个参数来解锁;

JDK的描述是开发只负责内存分配,其他事情一概不做处理的垃圾收集器,“不回收垃圾的垃圾收集器”看起来怪怪的,因此用途也比较特殊:

  • 性能测试(它可以帮助过滤掉GC引起的性能假象);
  • 内存压力临界点测试(比如知道测试用例应该分配不超过1 GB的内存,我们可以使用-Xmx1g配置-XX:+UseEpsilonGC,如果违反了该约束,则会heap dump并崩溃);
  • 非常短的JOB任务(对于这种任务,接受GC清理堆那都是浪费空间);
  • VM接口测试;
  • Last-drop 延迟&吞吐改进;

这里直接通过一个程序了解Epsilon垃圾收集器的效果:


/**  
 * JDK11 新的垃圾收集器 Epsilon  
 * 需要配置启动参数:  
 * -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC  
 */public class EpsilonGcTest {  
    public static void main(String[] args) {  
        boolean flag = true;  
        List<Garbage> list = new ArrayList<>();  
        long count = 0;  
        while (flag){  
            list.add(new Garbage());  
            if(list.size() == 100000 && count == 0){  
                list.clear();  
                count++;  
            }  
        }  
        System.out.println("程序结束");  
    }  
}  
class Garbage{  
    int n = (int)(Math.random() * 100);  
    @Override  
    protected void finalize() throws Throwable {  
        System.out.println(this + "  : "+ n + "is dying");  
    }  
}

启动之前,不要忘了设置VM Option,如果看不到VM Option这一行,可以点击"Modify options"中添加VM option。

PS:下面的环境变量和program arguments设置启动参数是无效的。

image.png

启动之后一会儿控制台会打印下面的内容并且结束。


Terminating due to java.lang.OutOfMemoryError: Java heap space

如果是传统的垃圾收集器,那么输出的结果将会是System.out.println(this + "  : "+ n + "is dying");的内容,虽然整个程序依然会继续运行直到OOM,但是要花更多的时间等待。


com.zxd.interview.epsilongctest.Garbage@21abe  : 59is dying
com.zxd.interview.epsilongctest.Garbage@6f6b18fc  : 43is dying
com.zxd.interview.epsilongctest.Garbage@701264d8  : 56is dying
com.zxd.interview.epsilongctest.Garbage@5380a941  : 52is dying
com.zxd.interview.epsilongctest.Garbage@43c78e65  : 72is dying
com.zxd.interview.epsilongctest.Garbage@745cd219  : 11is dying
com.zxd.interview.epsilongctest.Garbage@170b4cee  : 68is dying
com.zxd.interview.epsilongctest.Garbage@411725ef  : 22is dying
com.zxd.interview.epsilongctest.Garbage@3edc2f0e  : 4is dying
com.zxd.interview.epsilongctest.Garbage@2c82eed6  : 58is dying
com.zxd.interview.epsilongctest.Garbage@61a3bb94  : 71is dying
com.zxd.interview.epsilongctest.Garbage@19e3d212  : 70is dying
com.zxd.interview.epsilongctest.Garbage@46182a7f  : 19is dying
com.zxd.interview.epsilongctest.Garbage@7dd78834  : 56is dying
com.zxd.interview.epsilongctest.Garbage@1d4e301  : 68is dying

从上面的案例可以看到,有时候不回收垃圾也是有帮助的。

JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (可伸缩低延迟垃圾收集器)

这应该是JDK11最为瞩目的特性, 没有之一, 但是后面带了Experimental, 说明JDK11这一个版本不建议用到生产环境。(JDK13才算是真正完善),ZGC问世对外宣传如下:

  • GC暂停时间不会超过10ms;
  • 即能处理几百兆小堆,也能处理几个T的大堆(OMG);
  • 和G1相比,应用吞吐能力不会下降超过15%;
  • 为未来的GC功能和利用colord指针以及Load barriers优化奠定基础;
  • 初始只支持64位系统;

现代系统可用内存不断增大,GC垃圾收集器同样需要不断进化,现代的应用追求低延迟高吞吐量,ZGC的特点正好切中了GC的痛点。

ZGC的设计目标是:支持TB级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于15%。

美团在2020年有一篇关于ZGC的分析文章质量很高: # 新一代垃圾回收器ZGC的探索与实践,如果比较难理解,还可以看看这一篇文章:# 理解并应用JVM垃圾收集器-ZGC

ZGC的了解程度停留在简单理解理论概念即可,下面是从网络整理的资料归档:

GC术语

注意下面的并行、串行、并发更偏向GC的概念:

  • 并行:可以存在多个GC线程同时进行工作,但是无法确定是否需要暂停用户线程
  • 串行:指的是只有单个GC线程进行工作。注意串行也不一定需要暂停用户线程
  • STW:用户线程暂停,此时只有GC线程进行工作。
  • 并发:GC的并发指的是具备并发性,如果说垃圾收集器某些阶段是并发的,那么可以简单在某些阶段GC线程可以和应用程序线程同时进行,但是这需要十分复杂的设计防止用户线程操作导致GC工作无效。
  • 增量阶段指的是某个阶段可以再运行一段时间之后提前中止。

权衡

权衡主要是针对并行和并发阶段带来的问题,并行阶段如果GC占用过多的线程可能导致用户线程性能抖动,而并发阶段如果需要保证能同时处理GC的有效性和用户线程正常工作的问题。

多层堆和压缩

多层堆指的是让JVM管理内存可以像高速缓存一样分为多级缓存存储对象,通过对象分类将频繁访问对象和很少使用对象分开管理的技术。该功能可以通过扩展指针元数据来实现,指针可以实现计数器位并使用该信息来决定是否需要移动对象到较慢的存储上。

压缩是指对象可以以压缩形式保存在内存中,而不是将对象重定位到较慢的存储层。获取压缩对象的时候通过读屏障将其解压并且重新分配。

多重映射

这里不过多介绍计算机的虚拟内存和物理内存概念,简单知道操作系统通过映射表实现了物理内存和虚拟内存的映射,最终通过使用页表和处理器的内存管理单元(MMU)和转换查找缓冲器(TLB)来实现这一点。

而多重映射则指的是多个虚拟内存映射到同一块物理内存的技术。ZGC中使用三个映射来完成多重映射操作。

读屏障

读屏障是每当应用程序线程从堆加载引用时运行的代码片段(即访问对象上的非原生字段(non-primitive field)):

读屏障是JVM向应用代码插入一小段代码的技术。当应用线程从堆中读取对象引用时,就会执行这段代码。需要注意的是,仅“从堆中读取对象引用”才会触发这段代码。


void printName( Person person ) {
  // 这里触发读屏障
  String name = person.name;
  // 因为需要从heap读取引用
  //
  System.out.println(name); // 这里没有直接触发读屏障
}

如注释所说String name = person.name;这一行因为访问了对象非原生字段,将引用加载到本地的name变量,此时操作触发了读屏障。

如前面所说,读屏障是在返回对象引用之前“做手脚”,比较能想到的思路是引用中设置某些“标志位”的方式,但是ZGC实际用的是“测试加载的引用”检查是否满足条件,最后根据结果判断是否执行自己需要的特殊操作。

ZGC 最终选择在读屏障上动手脚,一部分原因是源自Shenadoah收集器的挑战,这个非JDK官方设计的垃圾收集器给Oracle不小的冲击。

ZGC标记

下面简单了解ZGC垃圾回收截断中的标记截断处理,ZGC的标记分为三个阶段:

  • 第一阶段是STW,其中GC roots被标记为活对象。
  • 从roots访问的对象集合称为Live集。GC roots标记步骤非常短,因为roots的总数通常比较小。
  • 第二阶段遍历对象图并标记所有可访问的对象。
  • 读屏障针使用掩码测试所有已加载的引用,该掩码确定它们是否已标记或尚未标记,如果尚未标记引用,则将其添加到队列以进行标记。
  • 第三阶段是边缘情况的处理,这里会有一个非常短暂的STW操作。也是针对经过前两次标记之后依然没有标记完成的最终检查。

image.png

GC roots类似于局部变量,通过它可以访问堆上其他对象。通过Gc root进行可达性分析查找出无法“到达”的对象则被标记为垃圾对象

ZGC 重定位

ZGC在对象清理上采用和G1类似的思路,也就是标记-复制把活对象移动到另一处,然后将只存在垃圾对象的内存释放掉,但是实现方法上更为取巧。

ZGC首先将堆分成许多页面,重定位开始的时候,会挑选一组需要重定位对象的页面,为了保证挑选准确此时需要短暂STW将该集合中root对象的引用映射到新位置。

移动root后下一阶段是并发重定位,此时GC线程遍历重定位集并重新定位其包含的页中所有对象,如果应用线程访问到这些需要重定位对象,则通过转发引用的方式重新定位读取新位置。

这里需要注意读屏障并不能完全保证所有指向旧对象的引用转到重新定位的地址上,在并发的情况下GC需要反复多次检查是否有引用指向旧的位置。

重定位的操作代价十分高昂,为了提高效率会和GC周期的标记阶段一起并行执行,GC周期标记阶段遍历对象对象图的时候,如果发现未重映射的引用则将其重新映射,然后标记为活动状态。

这两步可以抽象认为是一个人负责干活,另一个人负责把前面干活遗留的工作进行检查和标记。

image.png

ZGC 表现

ZGC的SPECjbb 2015吞吐量与Parallel GC(优化吞吐量)大致相当,但平均暂停时间为1ms,最长为4ms。 与之相比G1和Parallel有很多次超过200ms的GC停顿。

ZGC的状态

ZGC 依然有很多亟待解决的问题,以G1为例从发布到支持之间超过3年,ZGC最终到JDK13被正式对外使用。

小结

从整体上看,ZGC的垃圾收集将所有的暂停控制只依赖于GC roots集合上,将停顿控制在一处以达到更好的GC效果。

标记垃圾对象的过程中,标记阶段处理标记终止的最后一次暂停是唯一的例外,但是它是增量的(不一定执行),如果超过GC时间预算,那么GC将恢复到并发标记,直到再次尝试。

删除内容

JEP 320: Remove the Java EE and CORBA Modules

Java EE和CORBA两个模块在JDK9中已经标记"deprecated",在JDK11中正式移除。这部分内容基本上没有Java开发者接触到(连网络搜索都不会碰到)所以忘记即可。

JavaEE由4部分组成:

  • JAX-WS (Java API for XML-Based Web Services),
  • JAXB (Java Architecture for XML Binding)
  • JAF (the JavaBeans Activation Framework)
  • Common Annotations.

看起来比较多,但是这个特性和JavaSE关系不大。并且Maven也提供了JavaEE(mvnrepository.com/artifact/ja… 第三方引用,所以移除的影响并不会很大。

至于CORBA,使用CORBA开发程序没有太大的兴趣。

CORBA的XML相关模块被移除:java.xml.ws,java.xml.bindjava.xml.wsjava.xml.ws.annotationjdk.xml.bindjdk.xml.ws最终保留:java.xmljava.xml.cryptojdk.xml.dom 模块。

除此之外,还有:

java.se.eejava.activation java.transaction

被移除,但是java11新增一个java.transaction.xa模块

JEP 335: Deprecate the Nashorn JavaScript Engine(弃用 Nashorn JavaScript 引擎)

废除Nashorn javascript引擎,在后续版本准备移除掉,有需要的可以考虑使用GraalVM

最终:Nashorn JavaScript Engine 在 Java 15 已经不可用了。几乎不会用到的东西,为了让读者略微了解一下,这里用JDK8的Nashorn简单做个演示。


public class NashornTest {  
    public static void main(String[] args) throws ScriptException, FileNotFoundException {  
        // 直接使用  
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");  
        engine.eval("print('Hello World!');");  
        // 文件中运行  
        ScriptEngine engine2 = new ScriptEngineManager().getEngineByName("nashorn");  
        engine2.eval(new FileReader("E:\\adongstack\\project\\selfUp\\interview\\src\\main\\resources\\static\\js\\hello.js"));  
    }  
}

现代项目大多数都是前后端分离的,哪怕没有前后端分离也基本没有人会在后端写很多隐患的JS脚本,个人认为是这些原因导致的Nashorn javascript默默无闻的诞生和默默无闻的毁灭。

Nashorn javascript引擎更多了解可以看这篇:mouse0w0.github.io/2018/12/02/…

JEP : 336 : Deprecate the Pack200 Tools and API 废弃Pack200和相关API

Pack200 是自Java5出现的 压缩工具,这个工具能对普通的jar文件进行高效压缩。

Pack200 合并原理是根据类的结构设计以及合并常量池的方式,最后去掉无用信息来实现高效压缩,注意这种压缩只能针对Java文件进行压缩,这种压缩方式是很有意义的,能达到jar包的10% - 40%的压缩率。

Java5中还提供了这一技术的API接口,可以将其嵌入到应用程序中使用。使用的方法很简单,下面的短短几行代码即可以实现jar的压缩和解压:

压缩


Packer packer=Pack200.newPacker();
OutputStream output=new BufferedOutputStream(new FileOutputStream(outfile));
packer.pack(new JarFile(jarFile), output);
output.close();

解压


Unpacker unpacker=Pack200.newUnpacker();
output=new JarOutputStream(new FileOutputStream(jarFile));
unpacker.unpack(pack200File, output);
output.close();

看了上面的介绍,读者可能会跟我有一样的疑问,感觉这不是挺好的一东西么为啥要抛弃? 还能结合SpringBoot的jar包进行压缩,为了进一步了解JDK为啥要在Java11移除,这里找到的JDK官方的说明:

JEP 367: Remove the Pack200 Tools and API (openjdk.org)

我把JDK官方的说明部分拿过来了:


There are three reasons to remove Pack200:
1.  Historically, slow downloads of the JDK over 56k modems were an impediment to Java adoption. The relentless growth in JDK functionality caused the download size to swell, further impeding adoption. Compressing the JDK with Pack200 was a way to mitigate the problem. However, time has moved on: download speeds have improved, and JDK 9 introduced new compression schemes for both the Java runtime ([JEP 220](http://openjdk.java.net/jeps/220)) and the modules used to build the runtime ([JMOD](http://openjdk.java.net/jeps/261#Packaging:-JMOD-files)). Consequently, JDK 9 and later do not rely on Pack200; JDK 8 was the last release compressed with `pack200` at build time and uncompressed with `unpack200` at install time. In summary, a major consumer of Pack200 -- the JDK itself -- no longer needs it.
2.  Beyond the JDK, it was attractive to compress client applications, and especially applets, with Pack200. Some deployment technologies, such as Oracle's browser plug-in, would uncompress applet JARs automatically. However, the landscape for client applications has changed, and most browsers have dropped support for plug-ins. Consequently, a major class of consumers of Pack200 -- applets running in browsers -- are no longer a driver for including Pack200 in the JDK.
3.  Pack200 is a complex and elaborate technology. Its [file format](https://docs.oracle.com/en/java/javase/13/docs/specs/pack-spec.html) is tightly coupled to the [class file format](https://docs.oracle.com/javase/specs/jvms/se13/html/jvms-4.html#jvms-4.1) and the [JAR file format](https://docs.oracle.com/en/java/javase/13/docs/specs/jar/jar.html), both of which have evolved in ways unforeseen by JSR 200. (For example, [JEP 309](http://openjdk.java.net/jeps/309) added a new kind of constant pool entry to the class file format, and [JEP 238](http://openjdk.java.net/jeps/238) added versioning metadata to the JAR file format.) The implementation in the JDK is split between Java and native code, which makes it hard to maintain. The API in `java.util.jar.Pack200` was detrimental to the modularization of the Java SE Platform, leading to [the removal of four of its methods in Java SE 9](http://cr.openjdk.java.net/~iris/se/9/java-se-9-fr-spec/#APIs-removed). Overall, the cost of maintaining Pack200 is significant, and outweighs the benefit of including it in Java SE and the JDK.

一大坨论文一样的英文,这里抽取部分语句的关键点简单概括一下:

第一点:

  • 说白了就是有新人干活还有力气,老东西赶紧退休。过去网络带宽资源吃紧加上网速很慢,超过56k的jar包要下半天,压缩处理能在一定程度上治标。但是现代的网络环境下个几十K的东西几乎都是瞬间完成了,然后JDK9还引入了新的压缩方式(关键)。

第二点:

  • Pack200最后一点夹缝:作为浏览器开发插件压缩的生存空间也没了,现代浏览器插件有独有的开发方式,Java在这一块掀不起什么浪花。

第三点:

  • Pack200 is a complex and elaborate technology。“Pack200是一项复杂而精细的技术”,我愿称之为高情商发言,低情商就是臃肿又难用。后面引经据典“批判了一番多么“精细”和“复杂”导致的问题。

总结:网络下载速度的提升以及java9引入模块化系统之后不再依赖Pack200,因此这个版本将其移除掉。

JDK11 其他内容

Optional 增强

新增了empty()方法来判断指定的 Optional 对象是否为空。


var op = Optional.empty();
System.out.println(op.isEmpty());//判断指定的 Optional 对象是否为空

String 增强


//判断字符串是否为空  
" ".isBlank();//true  
//去除字符串首尾空格  
" Java ".strip();// "Java"  
//去除字符串首部空格  
" Java ".stripLeading();   // "Java "  
//去除字符串尾部空格  
" Java ".stripTrailing();  // " Java"  
//重复字符串多少次  
"Java".repeat(3);             // "JavaJavaJava"  
//返回由行终止符分隔的字符串集合。  
"A\nB\nC".lines().count();    // 3  
"A\nB\nC".lines().collect(Collectors.toList());

移除项

  • 移除了com.sun.awt.AWTUtilities
  • 移除了sun.misc.Unsafe.defineClass
  • 使用java.lang.invoke.MethodHandles.Lookup.defineClass来替代
  • 移除了Thread.destroy()以及 Thread.stop(Throwable)方法
  • 移除了sun.nio.ch.disableSystemWideOverlappingFileLockChecksun.locale.formatasdefault属性
  • 移除了jdk.snmp模块
  • 移除了 javafx ,openjdk 估计是从java10版本就移除了,但是oracle jdk10还尚未移除javafx,而java11版本则oracle的jdk版本也移除了javafx。
  • 移除了Java Mission Control,从JDK中移除之后,需要自己单独下载

移除了这些Root Certificates

  • Baltimore Cybertrust Code Signing CA
  • SECOM
  • AOL and Swisscom

废弃项

  • -XX+AggressiveOpts选项
  • -XX:+UnlockCommercialFeatures
  • -XX:+LogCommercialFeatures选项也不再需要

G1 垃圾收集器升级

JDK11的G1垃圾收集齐相比于 JDK 8可以享受到:

  • 并行的 Full GC
  • 快速的 CardTable 扫描
  • 自适应的堆占用比例调整(IHOP)
  • 在并发标记阶段的类型卸载 ....等等

这些都是针对 G1 的不断增强,串行 Full GC被常常诟病最终Oracle忍无可忍复用了CMS的并行GC代码给实现了(配置参数可以看出端倪,很多和CMS配置仅仅是换了个名字),最终是减少程序员的调优成本和调优时间。

附录

17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)

image.png

下面包含了这17个JEP的提案:

JEP 181: Nest-Based Access Control

JEP 309: Dynamic Class-File Constants

JEP 315: Improve Aarch64 Intrinsics

JEP 318: Epsilon: A No-Op Garbage Collector

JEP 320: Remove the Java EE and CORBA Modules

JEP 321: HTTP Client (Standard)

JEP 323: Local-Variable Syntax for Lambda Parameters

JEP 324: Key Agreement with Curve25519 and Curve448

JEP 327: Unicode 10

JEP 328: Flight Recorder

JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms

JEP 330: Launch Single-File Source-Code Programs

JEP 331: Low-Overhead Heap Profiling

JEP 332: Transport Layer Security (TLS) 1.3

JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)

JEP 335: Deprecate the Nashorn JavaScript Engine

JEP 336: Deprecate the Pack200 Tools and API

Jshell(JDK9)

和Go和Python这种自带Shell的语言进行对比,Java的Shell直到Java9才出现,Java9引入了jshell这个交互性工具,让Java也可以像脚本语言一样来运行,可以从控制台启动 jshell。

一个编程语言本该有的东西,这里就不多介绍了。Jshell比较适合刚刚入门Java语言的学习者使用。

写在最后

这篇文章把大部分JDK11新特性简单分析了一遍,如果有错误的论述欢迎指正。JDK的新版本特性还是非常有意思的,虽然不一定能在工作中用上,但是了解这些特性跟进时代是作为Java开发者的基本操守。

相关文章
|
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