Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java程序员说句心里话:麻了

Java程序员说句心里话:麻了

作者头像
腾讯云开发者
发布于 2025-03-13 14:00:13
发布于 2025-03-13 14:00:13
11200
代码可运行
举报
运行总次数:0
代码可运行

Java,一门广受赞誉,却又饱受诟病的语言,在从其诞生至今,便无时不刻的被拿来与其他语言对比,有时候这种对比是空穴来风的诽谤,但更多的是对这门语言未来的担心,而近 10 年来涌现的一个又一个新生的程序语言更是让 Java 一次又一次地被推上风口浪尖,使公众一次又一次的质疑:Java,是否真的停滞不前了?

关注腾讯云开发者,一手技术干货提前解锁👇

2024 年,从大街上随便抓一个 Java 程序员,询问其 Java 有哪些槽点,我相信你的这个下午大概是别想离开这个人的声音了 —— 从泛型不支持基本数据类型到各种各样令人抓耳挠腮的奇怪问题,你绝对可以听这个人滔滔不绝地说上一整天。那么这些问题 Java 官方知道吗?当然知道,他们在解决吗?Ummm,至少我们可以说,他们一直以来都正在积极的为解决这些问题而努力,并且有些槽点,其实早已在最新版本的 Java 中被解决。

因此,本篇文章的目的,便是带领读者从过去走向现在,再走向未来,回顾并前瞻 Java 已经推出,或是即将推出的全新特性,这些特性再 Java 的历史中都扮演着决定性的作用,为 Java“赶 Go 超 Rust”贡献着自己的努力。

碍于篇幅所限,我们将只重点提及几个 Java 语言史上的重大改动,而其他小的(但不代表不重要)更新,我们姑且一概掠过。若要了解Java 从过去到现在全部的特性更新,也许你可以看看 OpenJDK 的 Java 特性提案索引页 JEP 0: JEP Index(https://openjdk.org/jeps/0),了解更多。

01

Java8:Lambda 表达式和 Stream API

Java 8 无论是从 JVM 层面的变动,还是 Java 语法和标准库的变动,都可以说是 Java 有史以来第一次大规模的增补,毋庸置疑的,这次更新也为 Java 带来了第二春,使之焕发新生,而其长达近 20 年的 LTS 支持,也使其成为了 Java 历史上使用率最高,最经久不衰的 Java 版本。

在这次更新中,Java 自然是引入了全新且复杂的 Date & Time API,看起来好像有点用但实际上很鸡肋的 Optional API 这类谈不上小但是也很难说重大的标准库修补。但是更为被人津津乐道,且在本人看来是 Java 8 最重要的两个更新,便是 Lambda 表达式和 Stream API。

1.1 Lambda 表达式

也许是考虑到兼容性,也许就是纯粹 Java 开发者懒,自 Java 7 以前,Java 虚拟机(JVM)基本没有什么重大改动,纵然 Java 语言已经引入了诸如自动拆装箱、参数化类型(泛型)这样的重大语言特性,JVM 依然不动如山,全靠 javac 衬托。

然而到了 Java 7,天塌了。JVM 引入了一个全新的指令 invokedynamic,其可以在运行时动态的分派一个函数调用,这个指令最初并没有被 Java 语言本身所使用,相反,它的出现是为了解决基于 JVM 的动态类型语言(例如 Groovy)在运行时由于 JVM 无法支持函数类型动态分派而导致的巨大性能问题。

而这个指令第一次在 Java 语言中登场,便是神奇的 Lambda 表达式了。

即使你不知道 Lambda 表达式,或者他背后的函数式接口,我相信你一定写过这样的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Thread(() -> Foo.bar()).start(); // 更好的一个写法其实是 new Thread(Foo::bar).start();

这很自然,就像你可能不会泛型编程,但一定也用过带泛型的 Java 容器一样。但如果我告诉你,在过去的 Java 版本中,人们只能这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Thread(new Runnable() {
    @Override
    public void run() {
        Foo.bar();
    }
}).start();

是不是会有一种天然的碰见庞然大物的恐惧感。而事实上,在 Java 8 以前,函数式编程是不可能的,这主要源自于 Java 的一个语法缺陷:在 Java 中,函数(方法)不是一等公民。

什么是“一等公民”?来看看在 JavaScript 中大家习以为常的一段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function foo(){
  console.log("foo!");
}

function bar(barFoo){
  barFoo();
}

bar(foo);

最后一行中,我们为 bar 函数直接传入 foo 函数作为其实参,并在 bar 函数中调用这个函数。我们可以将一个函数(或者说,函数指针)作为参数传入到函数中,就像其他数据类型一样。

但是 Java 是没有办法直接传入函数指针的,如果你了解 C# 的话,C# 用 Delegate(委托)机制解决这个问题,而 Java 则绕的更远一些,选择了 Functional Interface(函数式接口)作为其函数式编程的解决方案。那么,什么是函数式接口?

通俗的来讲,任意一个仅有一个抽象方法的接口,都是函数式接口(无论其是否标注 @FunctionalInterface 注解),例如我们上边看到的 Thread 构造方法中的 Runnable 接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

这个接口只有一个名为 run 的抽象方法,并没有任何返回值。我们可以为需要函数式接口实例的地方传入 Lambda 表达式,在运行时,Lambda 表达式会被转换为对应函数式接口的实例,就像我们为 Thread 传入构造函数参数所做的那样一样。

当然,请不要误解我的意思,并不是自 Java 8 引入函数式接口这个概念之后,才有了 Runnable 接口,相反,Runnable 接口古早有之,是函数式接口的概念被引入后,Runnable 也正巧成为了函数式接口的一部分。

1.2 Stream API

Lambda 表达式的一大创新之处,就是为在 Java 语言进行函数式编程提供了可能,由此,Stream(流) API 应运而生。这里所说的“流”并不是指 I/O 流,而是一种数据流动的管道。举个例子,现在有一个包含 10000 个数字的 int 数组:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int[] array = new int[10000];

我想找出该数组中所有数字大于 5000 的数字,然后让他们加一个不大于 500 的随机数,最后求和。在不使用 Stream API 的情况下我们会这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public int sumRandomNumber(int[] array, Random random){
        int rst = 0;
        for (int i : array) {
            if (i > 5000) {
                rst += i + random.nextInt(500);
            }
        }
        return rst;
    }

但如果有了 Stream API,只需要一行代码就可以解决:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public int sumRandomNumberWithStreamAPI(int[] array, Random random) {
        return Arrays.stream(array).filter(i -> i > 5000).map(i -> i + random.nextInt(500)).sum();
    }

在上述代码中,我们通过调用 Arrays.stream 方法将 array 转换为一个 IntStream 流对象,然后顺次调用 filtermap 流中间方法,过滤和映射数据,最终调用 sum 流终结方法,获得求和结果。

一种特定类型的数据经过流中间方法的加工处理,最终经过流终结方法收集为我们想要的形式,这极大地提高了开发效率,而在以前的 Java 中,想要达成这样的操作,会使代码变得极度复杂。

02

Project Loom:Java 迈向现代化的第一步

相信各位对“Coroutine(协程)”这个名词一定不陌生,被称为“轻量级线程”的它,在 I/O 密集型的应用程序开发领域可谓是如日中天。所谓“协程”,便是一种用户态的线程,它们构建于线程之上,由用户程序负责调度,而不是操作系统。比起原生的操作系统线程,他更轻量,而比起 Event Loop(事件循环)的解决方案,它又能保证对用户程序足够透明,降低开发过程中的心智负担。

许多现代语言都配备了协程的原生支持,尽管它们各自的实现方式并不相同,例如 Go 的 GoroutineKotlinKotlin Coroutines 或是 C++ 20 的 Coroutines。在早期版本的 Java 中,其实有一个名为“Green thread(绿色线程)”的协程实现,但因为各种原因,最终被替换回了现在的操作系统线程。

但是我们确实需要协程,于是 2017 年,Project Loom 应运而生,它的使命就是为 Java 提供自己的有栈协程实现,早期被称为“Fiber(纤程)”,后被称为“Virtual thread(虚拟线程)”,经过两个大版本的预览,其终于在 Java 21 中正式推出,这意味着 Java 平台也拥有了自己的原生协程实现。

于是现在,你可以通过 Thread 对象的静态工厂方法 ofVirtual 创建一个虚拟线程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Thread.ofVirtual().start(()->{
  // some heavy IO stuff
});

就是这么简单,如果你在用 Spring Boot 3,只需要一行配置便可以在你的项目中启用虚拟线程支持:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring.threads.virtual.enabled=true

很简单对不?现在就去试试看吧,我保证带来的性能提升是立竿见影的。

当然有关并发编程,另一个绕不开的话题便是异步编程了,Java 目前原生的异步编程由 Future 等对象支持,用起来不能说十分好用,只能说味同嚼蜡。在 Java 19 引入的 Structured Concurrency(结构化并发)事实上在一定程度上为异步编程提供了更好的解决方案,篇幅所限,在这里我们也不再展开。

03

Project Panama:外地人向本地人的妥协

长期以来,Java 一直以“一次编写,到处运行”作为自己的卖点,然而很不幸的是,Java 没能向开发者提供所有他们想要的原材料,因此,开发者们决定自己做,最终,在各种 JNI 函数和 Unsafe 调用的狂轰滥炸下,Java 最终还是变成了“一次编写,到处调试”的样子。

JNI 好用吗?我相信没人会说好用,不然也不可能会有 JNA 一类的库出现,JNI 看似提供了 Java 向 native 调用的接口,但实际上它完全不够灵活,无法在运行时根据程序的需要动态的链接不同的函数。自 Java 1.1 引入 JNI 开始,这个东西就基本没什么变化,大家只能捏着鼻子用这样一套并不好用的东西,或者只能叹叹气,然后另寻他法。

再回过头来看看 Unsafe,在过去版本的 Java 中,管理堆外内存是非常复杂且危险的,尤其是当我们通过 hacky 的方式获取 sun.misc.Unsafe 类实例,并使用其中的 allocateMemory 方法来分配堆外内存时。这意味着,我们需要手动管理这些堆外内存的分配和释放,一不小心,就可能造成 JVM 虚拟机和 GC 无法处理的内存泄漏。

有些人可能会说:JVM 本来就不希望你使用堆外内存,你为什么要这么用,这不是自找没趣吗?但是很遗憾的是,有时要想获得高性能的数据吞吐或是确保数据的一致性,我们不得不这么做,例如在 Java 中使用 mmap, CAS,或是设置内存屏障。在 Java 8,如果你想设置一个操作系统级别的重量级锁,你可以使用 LockSupport.park;自 Java 9 开始,如果你想对一个对象中的字段 CAS 写入,则可以用 VarHandle.compareAndSet 方法;但是其他 JVM 未能提供的操作,也许你只能像使用 JNI 一样,绕一个大圈,或是看看社区上有没有已经做好的,也许可能充满各种漏洞的小玩具。

但是事情还是需要解决的,最终这场争端以 Java 这个外地人向本地人的妥协而告终:Project Panama 应运而生。经过三个大版本的预览,Project Panama 的一个重要特性,The Foreign Function & Memory (FFM) API 终于在 Java 22 正式落地。FFM API 有什么用?首先,它可以提供灵活的本地库访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
    stdlib.find("strlen").orElseThrow(),
    FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);

try (Arena arena = Arena.ofConfined()) {
    MemorySegment cString = arena.allocateFrom("Hello");
    long len = (long)strlen.invokeExact(cString); // 5
}

上述代码创建了一个操作系统标准库的链接器,在其中查找 strlen 函数并以一个从 JVM 创建的堆外字符串作为参数执行,获取结果。在这个过程中,还需要告诉 JVM 函数和参数的内存布局,以便 JVM 可以正确传入他们。

接下来,FFM API 向我们提供了更适合 Java 宝宝的堆外内存 API,Arena,你可以通过这种方式创建一个会自动被 GC 清理的堆外内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
MemorySegment segment = Arena.ofAuto().allocate(100, 1);
...
segment = null; // the segment region becomes available for deallocation after this point

或者,你可以直接创建一个基于作用域的堆外内存,并使用 try-with-resource 语法包裹,只要离开 try 作用域,则分配的堆外内存会被自动释放:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
MemorySegment segment = null;
try (Arena arena = Arena.ofConfined()) {
    segment = arena.allocate(100);
    ...
} // segment region deallocated here
segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateExceptio

别忘了 mmap,现在 FFM API 可以直接提供这种支持,只需要调用 FileChannel.map 方法即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Arena arena = Arena.ofAuto();
try {
    try (FileChannel channel = FileChannel.open(Path.of("large_file"), StandardOpenOption.READ)) {
        MemorySegment segment = channel.map(FileChannel.MapMode.READ_ONLY, 0, FILE_SIZE, arena);
        // use segment in your way
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

是不是简简又单单呢?有了 FFM API 这把瑞士军刀,相信以后 Java 能做的事情会更有趣和疯狂。

04

Project Valhalla:走向未来

至此,我们已经介绍完了 Java 走向现代化三座大山中已经落地的前两座,如你所见的是,他们每一个都充满诱惑,十分大胆,令 Java 焕发新生,但是 Project Valhalla 将带给我们的,比前面我讲过的那些特性更加疯狂,更加颠覆:为 Java 引入值类型对象,补上长久以来 Java 泛型编程的缺陷,并为 JVM 虚拟机提供运行时可见的泛型参数。

让我们先来回忆一下泛型的前世今生:泛型于 Java 1.5 被首次引入,其更官方、也更直观的名称应该是 Parameterized Type(参数化类型),其允许将类型作为类或函数的参数提供,以便于更好的进行类型检查或是根据不同的泛型特化代码实现,然而后者并不被 Java 泛型所支持,因为 Java 泛型采用的方案于 C++, Go, Rust 这些语言的泛型方案有本质不同:Java 的泛型只是编译器语法糖,在运行时并没有影响代码执行,这意味着,当你在 C++ 中使用 Vector<bool>Vector<int> 时,C++ 编译器事实上会生产两个不同版本的 Vector 类(这也是其名称“模板”的由来),但 Java 并不会改变这一点,List<Boolean>List<Integer> 和其未泛化原始类型 List 没有任何差别,编译器会在需要提供或返回泛型参数时帮你做类型安全检查或自动类型转换,而 JVM 不会感知到泛型的存在。

泛化泛型和具化泛型的争端从未停止,本文也无心讨论此两者之间各自的优劣,但是不可否认是,泛化泛型确实为 Java 引入了一个难以逾越的语法鸿沟:那就是参数化类型无法接受基本数据类型作为参数,这意味着在 C# 程序员眼中看起来十分正常的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<int> list = new List<>();

在 Java 中是不可能的。而长久以来,Java 程序员只能被迫在需要将基本数据类型放入集合的场景下进退两难:要么把 int 装箱成 Integer,忍受额外的对象创建开销;要么自行构建,或者使用各种工具库提供的特化集合类型(例如 IntArrayList, DoubleArrayList 等)。而事实上,这种语法鸿沟在 Java 中由来已久,例如 switch 语句不支持 double 等类型,instanceof 关键字不支持针对基本数据类型的模式匹配等,颇令新手疑惑,好在在最近的版本(Java 23)中,这些问题都逐步得到完善(https://openjdk.org/jeps/455),进入预览的流程。

再回过头来看看基本数据类型的装箱机制,这实际上是十分不明智的,因为基本数据类型这种可能被程序大量使用的数据,他们本应将其数值直接存储到内存中,而不是被包装一个含有比他们实际内容更为复杂的对象和对象头,这无疑增加了系统的内存压力。而参数化类型对基本数据类型的缺位更是加剧了这一问题。

为此,Project Valhalla 横空出世,直指这些痛点问题,并推出了它们的解决方案:值类型和通用泛型。

在未来的 Java 版本中,我们将可以通过 value class 标识创建一个值类型类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
value record Color(byte red, byte green, byte blue) {} // 值记录类型

这种类型没有对象头,其 hashCode 直接据其所含字段计算,这同时也意味着,对值类型进行 == 比较将会比较其值,而不是其地址。在未来,所有的基本数据类型包装类都会被升级为这种值类型。而原本的类型将会被称为 Identity class,意为具有身份的类型。

而通用泛型(这是一个早前叫法,但我觉得放到这里更直观,所以接着沿用下来)将允许我们在未来在泛型中直接使用基本数据类型作为泛型参数,而这种实现有可能依然是通过自动拆装箱实现的。

如果你恰巧用过 Java 16 及以上的版本,你可能会发现有一个新特性和上述特性有点类似,那就是 Record(记录)类型,该特性允许你通过简单的语法创建一个不可变的 POJO 对象,并为其实现 equals/hashCode/toString 方法和构造函数,而不必由你手动实现,或是使用额外的 @lombok.Data@lombok.AllArgsConstructor注解:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
record Point(int x, int y) { } // 通过 new Point(0, 0) 构造,通过 point.x()/point.y() 访问

但实际上,record 和 value class 是有本质区别的。Record 本质上还是一个对象,他依然是一个特殊的语法糖,并没有改变对象的本质;而 value class 则彻底颠覆了 Java 原有的对象模型。

除此之外,Project Valhalla 还有一些很有意思的提案,例如为 JVM 添加可 null 和非 null 类型,就将 C# 和 Kotlin 所做的那样;亦或者在运行时保留泛型参数,提供特化类型的实现等。

最后要说的是,Project Valhalla 的相关提案仍在不断更新,早在草案时期,相关提案就已被推翻重置了多次,因此对于该提案的相关描述在未来可能会是不准确的,希望读者悉知。

引用

  • JEP 444: Virtual Threads (openjdk.org):https://openjdk.org/jeps/444
  • JEP 454: Foreign Function & Memory API (openjdk.org):https://openjdk.org/jeps/454
  • JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal (openjdk.org):https://openjdk.org/jeps/471
  • java.lang.foreign (Java SE 22 & JDK 22) (oracle.com):https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/package-summary.html
  • Arena (Java SE 22 & JDK 22) (oracle.com):https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/Arena.html
  • FileChannel (Java SE 22 & JDK 22) (oracle.com)):https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/nio/channels/FileChannel.html#map(java.nio.channels.FileChannel.MapMode,long,long
  • Project Valhalla (openjdk.org):https://openjdk.org/projects/valhalla/
  • JEP 395: Records (openjdk.org):https://openjdk.org/jeps/395
  • JEP 401: Value Classes and Objects (Preview) (openjdk.org):https://openjdk.org/jeps/401
  • JEP 402: Enhanced Primitive Boxing (Preview) (openjdk.org):https://openjdk.org/jeps/402
  • JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview) (openjdk.org):https://openjdk.org/jeps/455
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java 19 已至,虚拟线程 = 王炸!!
JDK 19 定于 9 月 20 日正式发布以供生产使用,非长期支持版本。不过,JDK 19 中有一些比较重要的新特性值得关注。
Guide哥
2022/11/07
8300
Java 19 已至,虚拟线程 = 王炸!!
Java 24(Oracle JDK 24)正式发布,全网最全的新特性速览。Java 8 骨灰级程序员前来报道!
Java 24(Oracle JDK 24)已于 2025 年 3 月 18 日正式发布,包含 24 项功能。作为标准 Java 的短期支持版本,JDK 24 将仅获得 Oracle 六个月的Premier 级支持,而长期支持 (LTS) 版本将获得至少五年的 Premier 级支持。作为 JDK 21 以来的第三个非 LTS 版本,也是六个月周期开始以来的第 15 个版本,同时具有 24 个功能,远远超过于 2024 年 9 月 17 日发布的具有 12 个功能的 JDK 23。
一个正经的程序员
2025/03/21
6410
Java 24(Oracle JDK 24)正式发布,全网最全的新特性速览。Java 8 骨灰级程序员前来报道!
Java 21:有什么新变化?
这篇文章详细介绍了Java 21 的新特性和改进。Java 21是新的长期支持(LTS)版本,其中包括了15个Java增强提案(JEPs)。其中最重要的特性之一是虚拟线程的最终化,这些线程的创建和调度成本较低,使并发应用程序的编写变得更容易。文章还介绍了一些新的预览特性,如字符串模板(用于字符串插值)、序列化集合(增强了 Java 的集合 API)、未命名模式和变量、未命名类和实例 main 方法等。此外,还讨论了从预览状态转变为标准特性的一些功能,如记录模式、switch 的模式匹配和虚拟线程等。文章还提到了性能和安全等方面的改进。
终有救赎
2023/10/16
5660
Java 21:有什么新变化?
Java20的新特性
ScopedValue是一种类似ThreadLocal的线程内/父子线程传递变量的更优方案。ThreadLocal提供了一种无需在方法参数上传递通用变量的方法,InheritableThreadLocal使得子线程可以拷贝继承父线程的变量。但是ThreadLocal提供了set方法,变量是可变的,另外remove方法很容易被忽略,导致在线程池场景下很容易造成内存泄露。ScopedValue则提供了一种不可变、不拷贝的方案,即不提供set方法,子线程不需要拷贝就可以访问父线程的变量。具体使用如下:
code4it
2023/03/25
7400
Java20的新特性
最新Java JDK 21:全面解析与新特性探讨
JDK 21 的生产版本是在 6 月份的缩减和候选版本阶段之后发布的。作为长期支持版本,JDK 21 将获得五年的首要支持和扩展支持,直至 2031 年 9 月。之前的 LTS 版本是JDK 17,于 2021 年 9 月发布。非 LTS 版本,例如JDK 20和JDK 19,仅获得六个月的首要支持,并且没有扩展支持。LTS 版本每两年发布一次。
猫头虎
2024/04/09
3.8K0
最新Java JDK 21:全面解析与新特性探讨
Java21的新特性
在java21之前,字符串拼接或者字符串与表达式组合主要是用StringBuilder、String::format、java.text.MessageFormat,不过可读性都不是太好,java21引入了StringTemplate(java.lang.StringTemplate)来解决这个问题。
code4it
2023/09/20
1K0
Java21的新特性
Java21的新特性
在java21之前,字符串拼接或者字符串与表达式组合主要是用StringBuilder、String::format、java.text.MessageFormat,不过可读性都不是太好,java21引入了StringTemplate(java.lang.StringTemplate)来解决这个问题。
code4it
2023/09/22
7680
Java21的新特性
聊聊 Java 新特性与设计模式
JDK 中使用 Builder:使用 StringBuilder 或者像下面这样:
Java技术江湖
2023/01/04
3710
聊聊 Java 新特性与设计模式
Java:未来已来
在10月22的 Oracle Codeone大会上,Java平台的首席架构师 Mark Reinhold 做了The Future of Java is Today的演讲, 回顾了最近Java的几个版本的新的功能,Java的每年两次的发布周期, 澄清了关于发布流程和Java版本的几个误区,最后花了很大的篇幅介绍了未来Java几个令人非常期待的几个孵化中项目,可以为Java带来更好的生产力、性能和可扩展性。我整理了这四个项目相关的知识,你可以提前了解到Java未来的这些酷炫的特性。
芋道源码
2019/10/29
7790
Java:未来已来
Java22的新特性
主要是通过引入Region Pinning来降低使用JNI时G1收集器的延时。与Java代码不同,JNI交互可能使用指向堆中对象的显式指针。当Java线程执行JNI 代码的关键区域时,无法在堆中重新定位这些对象。为了避免此问题,G1在关键区域禁用GC,这可能会导致延迟增加,因为如果其他非JNI线程触发GC,它们将被阻止。此更改允许G1 GC通过固定JNI代码使用的内存区域但允许重新定位和收集其他内存区域,即使线程位于关键区域也可以运行。
code4it
2024/03/27
3940
Java22的新特性
Java19的新特性
上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 19 Release Notes,这里举几个例子。
code4it
2022/09/21
4970
Java19的新特性
Java22的新特性
主要是通过引入Region Pinning来降低使用JNI时G1收集器的延时。与Java代码不同,JNI交互可能使用指向堆中对象的显式指针。当Java线程执行JNI 代码的关键区域时,无法在堆中重新定位这些对象。为了避免此问题,G1在关键区域禁用GC,这可能会导致延迟增加,因为如果其他非JNI线程触发GC,它们将被阻止。此更改允许G1 GC通过固定JNI代码使用的内存区域但允许重新定位和收集其他内存区域,即使线程位于关键区域也可以运行。
code4it
2024/03/25
1620
Java : 未来已来
在10月22的 Oracle Codeone大会上,Java 平台的首席架构师 Mark Reinhold 做了The Future of Java is Today的演讲, 回顾了最近 Java 的几个版本的新的功能,Java 的每年两次的发布周期, 澄清了关于发布流程和 Java 版本的几个误区,最后花了很大的篇幅介绍了未来 Java 几个令人非常期待的几个孵化中项目,可以为Java带来更好的生产力、性能和可扩展性。我整理了这四个项目相关的知识,你可以提前了解到 Java 未来的这些酷炫的特性。
用户1257393
2018/12/11
5700
Java : 未来已来
Java: 未来已来
在10月22的 Oracle Codeone大会上,Java平台的首席架构师 Mark Reinhold 做了The Future of Java is Today的演讲, 回顾了最近Java的几个版本的新的功能,Java的每年两次的发布周期, 澄清了关于发布流程和Java版本的几个误区,最后花了很大的篇幅介绍了未来Java几个令人非常期待的几个孵化中项目,可以为Java带来更好的生产力、性能和可扩展性。我整理了这四个项目相关的知识,你可以提前了解到Java未来的这些酷炫的特性。
慕容千语
2019/06/12
4770
Java 20 发布,新特性一览:Amber、Loom 和 Panama 项目
作者 | Michael Redlich 译者 | 张卫滨 策划 | 丁晓昀 甲骨文发布了Java编程语言和虚拟机的 20 版本,最终的特性集中包含了 7 个 JEP: JEP 429:作用域值(Scoped Values,孵化阶段) JEP 432:记录模式(Record Patterns,第二轮预览) JEP 433: switch 的模式匹配(Pattern Matching for switch,第四轮预览) JEP 434:外部函数与内存API(Foreign Function & Memory
深度学习与Python
2023/03/29
5120
Java 20 发布,新特性一览:Amber、Loom 和 Panama 项目
Java 11正式发布,新特性解读
北京时间 9 月 26 日,Oracle 官方宣布 Java 11 正式发布。这是 Java 大版本周期变化后的第一个长期支持版本,非常值得关注。你可以点击以下地址即刻下载:
纯洁的微笑
2019/09/05
8060
Java 11正式发布,新特性解读
JAVA16版本.JDK16即将发布,你准备好了吗?
岁月无声,岁月有声.2020实鼠不易,2021牛转乾坤。 当我们开发者与大多企业还停留在JDK8的时候,JDK16即将问世,你准备好了吗?
张哥编程
2024/12/19
880
这年头,能坐上火箭的东西不多啊!Java版本号算一个!
Sun早已经不在了,如今只剩Oracle,也就是Java目前的抚养人。从2019年4月16号开始,Oracle版本的JDK,已经宣布收费,目前有更多的企业转向OpenJDK。
xjjdog
2021/12/13
4020
并发王座易主?Java 21 虚拟线程强势崛起,Go & Kotlin还稳得住吗 | 盘点
据 JetBrain 前不久发布的 《2023 开发者生态系统现状》调研报告,在开发者主要采用的编程语言中,最受欢迎的分别是 Java、Python、JavaScript,Java 在 2023 年重夺第一名宝座,JavaScript 则在下降三个百分点后跌至第三;Rust 在 2023 年最受欢迎的编程语言中,创造了新的使用记录,其用户群在过去五年中稳步增长,有望凭借其严格的安全性和内存所有权机制取代 C++;此外,Rust 2023 年首次取代 Go 成为希望迁移到其他语言的开发者的首选,而且 Go 用户也是第一批准备采用 Rust 的人,JetBrains 数据表明,有六分之一的 Go 用户正在考虑采用 Rust。
深度学习与Python
2024/01/17
3290
并发王座易主?Java 21 虚拟线程强势崛起,Go & Kotlin还稳得住吗 | 盘点
JEP解读与尝鲜系列1 - Java Valhalla与Java Inline class
最主要的一点就是,让Java适应现代硬件:在Java语言发布之初,一次内存访问和一次数字计算的消耗时间是差不多的,但是现在,一次内存访问耗时大概是一次数值计算的200~1000倍。从语言设计上来说,也就是间接访问带来的通过指针获取的需要操作的内存,对于整体性能影响很大。
干货满满张哈希
2021/04/12
6170
JEP解读与尝鲜系列1 - Java Valhalla与Java Inline class
相关推荐
Java 19 已至,虚拟线程 = 王炸!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验