{"id":604053,"date":"2025-09-16T12:15:34","date_gmt":"2025-09-16T11:15:34","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=604053"},"modified":"2025-09-26T13:34:23","modified_gmt":"2025-09-26T12:34:23","slug":"java-25-lts-and-intellij-idea","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/zh-hans\/idea\/2025\/09\/java-25-lts-and-intellij-idea","title":{"rendered":"Java 25 LTS and IntelliJ IDEA"},"content":{"rendered":"\n<p>The Java release cadence means we get a new Java version every six months. Java 25 was released on September 16, 2025. At JetBrains, we are committed to supporting new technologies in IntelliJ IDEA and adding useful enhancements for both stable and preview features. In this blog post, we will give you an overview of some changes to the Java language and how they are supported in IntelliJ IDEA. This post is limited to stable features only. Preview features will be covered separately in dedicated blog posts on relevant topics.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/projects\/jdk\/25\/\" target=\"_blank\" rel=\"noopener\">Java 25<\/a> includes several changes to the language that make Java easier to use. Features like <a href=\"https:\/\/openjdk.org\/jeps\/512\" target=\"_blank\" rel=\"noopener\">compact source files and instance main methods<\/a>, as well as <a href=\"https:\/\/openjdk.org\/jeps\/511\" target=\"_blank\" rel=\"noopener\">module import declarations<\/a>, make it easier to get started with Java, both for students and when creating small projects like prototypes or hobby projects. <a href=\"https:\/\/openjdk.org\/jeps\/513\" target=\"_blank\" rel=\"noopener\">Flexible constructor bodies<\/a> allow more flexibility in constructors, giving you the option to calculate or validate data before calling the constructor of the super class. <a href=\"https:\/\/openjdk.org\/jeps\/506\" target=\"_blank\" rel=\"noopener\">Scoped values<\/a> are a new model for thread-local variables, adapted to virtual threads. They will be more useful with <a href=\"https:\/\/openjdk.org\/jeps\/505\" target=\"_blank\" rel=\"noopener\">structured concurrency<\/a>, which is currently still in preview.<\/p>\n\n\n\n<p>Apart from changes to the language itself, there are improvements to both performance and performance insights. <a href=\"https:\/\/openjdk.org\/jeps\/519\" target=\"_blank\" rel=\"noopener\">Compact object headers<\/a> reduce memory footprint and improve cache efficiency. <a href=\"https:\/\/openjdk.org\/jeps\/515\" target=\"_blank\" rel=\"noopener\">Ahead-of-time method profiling<\/a> lets the JVM warm up more quickly by using execution data from prior runs, improving startup performance. Improvements to garbage collection (GC) like <a href=\"https:\/\/openjdk.org\/jeps\/521\" target=\"_blank\" rel=\"noopener\">generational Shenandoah<\/a>, plus better class-loading and linking optimizations, contribute to noticeably smoother server-style workloads.<\/p>\n\n\n\n<p>As Java 25 is an <a href=\"https:\/\/www.oracle.com\/nl\/java\/technologies\/java-se-support-roadmap.html\" target=\"_blank\" rel=\"noopener\">LTS (long-term support) release<\/a>, many people will be migrating to this version from Java 21, 17, 11, or even earlier. If you are coming to Java 25 from Java 21, have a look at the section describing the most relevant changes since Java 21.<\/p>\n\n\n\n<p>Before diving into the new features, let\u2019s set up IntelliJ IDEA to use Java 25.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Using Java 25 in IntelliJ IDEA (setup)<\/h1>\n\n\n\n<p>To use Java 25, you will need to download the JDK. You can do so from inside IntelliJ IDEA or by using tools like SDKMAN! To download a JDK from IntelliJ IDEA, open the <em>Project Structure<\/em>, go to the tab <em>Project Settings | Project<\/em>, open the drop-down menu in the <em>SDK <\/em>field, and select <em>Download JDK<\/em>.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image18.png\" alt=\"\" class=\"wp-image-604055\"\/><figcaption class=\"wp-element-caption\"><em>Downloading JDK from inside IntelliJ IDEA<\/em><\/figcaption><\/figure>\n\n\n\n<p>In the <em>Download JDK<\/em> popup that opens, set <em>Version<\/em> to <em>25<\/em>,<em> <\/em>and in the <em>Vendor<\/em> field, select the vendor you want to use.&nbsp;<\/p>\n\n\n\n<p>You can also download Early Access (EA) versions of the JDK from inside IntelliJ IDEA, for example, when the next release becomes available or if you\u2019d like to try Valhalla (which is based on Java 23). IntelliJ IDEA will warn you that these are not intended for production use.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image17.png\" alt=\"\" class=\"wp-image-604066\"\/><figcaption class=\"wp-element-caption\"><em>Downloading an Early Access version<\/em><\/figcaption><\/figure>\n\n\n\n<p>Next, you need to configure IntelliJ IDEA to use the right language level. To use Java 25 stable features, which is recommended for production code, set <em>Language level<\/em> to <em>25 &#8211; Compact source files, module imports<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image4-2.png\" alt=\"\" class=\"wp-image-604273\"\/><figcaption class=\"wp-element-caption\"><em>Setting <\/em>Language level<em> to <\/em>25<\/figcaption><\/figure>\n\n\n\n<p>If you want to try out preview features, set <em>Language level<\/em> to <em>25 (Preview) &#8211; Primitive Types in Patterns, etc<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image5.png\" alt=\"\" class=\"wp-image-604284\"\/><figcaption class=\"wp-element-caption\"><em>Setting <\/em>Language level<em> to <\/em>25 (Preview)<\/figcaption><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">New stable features in Java 25<\/h1>\n\n\n\n<p>Let\u2019s take a look at some of the features Java 25 introduces and how IntelliJ IDEA can help you use them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Compact Source Files and Instance Main Methods (JEP 512)<\/h2>\n\n\n\n<p>Java has been working on the so-called \u201con-ramp\u201d, making the language easier to use. <a href=\"https:\/\/openjdk.org\/jeps\/512\" target=\"_blank\" rel=\"noopener\">Compact source files and instance main methods<\/a> are part of that effort. It is now possible for beginners to start writing code without needing to learn about language concepts that they won\u2019t need until they start writing larger programs. For experienced programmers, this feature can help them quickly prototype ideas without needing a lot of boilerplate code. Code can be evolved and expanded as skills and applications grow.&nbsp;<\/p>\n\n\n\n<p>To quickly see the difference, let\u2019s look at a classic example: <code>HelloWorld<\/code>. We have probably all written a HelloWorld example when we first started, possibly in a language other than Java or English. The classic <code>HelloWorld.java<\/code> looks like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class HelloWorld {\n\u00a0\u00a0\u00a0public static void main(String[] args) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0System.out.println(\"Hello, World!\");\n\u00a0\u00a0\u00a0}\n}<\/pre>\n\n\n\n<p>To write this code, you had to declare a class and a lengthy main method, including concepts like <code>public<\/code> and <code>static<\/code> that are not relevant to beginners. Let\u2019s compare this to the <code>HelloWorld<\/code> example using new features from compact source files and instance main methods.&nbsp;<\/p>\n\n\n\n<p>When creating a new Java class via <em>New | Java Class<\/em>, in the <em>New Java Class<\/em> popup, select the <em>Compact source file <\/em>option. Note that this compact source file is created in the root directory of your project, even if you create it from another package. IntelliJ IDEA automatically adds an instance main method \u2013 <code>void main()<\/code> \u2013 to the file. Next, you can add a method to print \u201cHello, World!\u201d. You can now use <code>IO.println()<\/code> as a convenience method without needing to understand what <code>System.out<\/code> means and without even needing to add a static import. If you do want to add a static import for <code>java.lang.IO<\/code>, IntelliJ IDEA offers a quick-fix to do so.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_HelloWorld-2.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Creating `HelloWorld.java`<\/em><\/figcaption><\/figure>\n\n\n\n<p>Note that different variations of the main method are now possible, as described <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/02\/helloworld-and-main-meet-minimalistic\/#variations-of-the-main-method-in-the-implicit-class\">here<\/a>.<\/p>\n\n\n\n<p>IntelliJ IDEA has some new <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/using-live-templates.html\" target=\"_blank\" rel=\"noopener\">live templates<\/a> to add a main method to an implicit class, either with or without arguments: <code>main<\/code>, <code>maina<\/code>, <code>psvm<\/code>, and <code>psvma<\/code>. Using the <code>psvm<\/code> or <code>main<\/code> live templates inside a compact source file will add the new main method, while they will continue to add the classic main method inside a class, as you can see in the preview.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image15.png\" alt=\"\" class=\"wp-image-604121\"\/><figcaption class=\"wp-element-caption\"><em>Live templates for the main method in a compact source file<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image1-1.png\" alt=\"\" class=\"wp-image-604110\"\/><figcaption class=\"wp-element-caption\"><em>Live templates for the main method in a compact source file<\/em><\/figcaption><\/figure>\n\n\n\n<p>Our new version of <code>HelloWorld<\/code> now looks like this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void main() {\n\u00a0\u00a0\u00a0IO.println(\"Hello, World!\");\n}<\/pre>\n\n\n\n<p>Compare this code to the original example. It is much shorter, contains less boilerplate, and is limited to only the things we need: a main method and a call to print a line with the provided \u201cHello, World!\u201d <code>String<\/code>.<\/p>\n\n\n\n<p>As beginners often need to interact with the console, a convenient <code>readln()<\/code> method was also added. This is an overloaded method which can take a <code>String<\/code> argument that is printed to the console before reading the input. Let\u2019s expand our previous example to read a name from the console. To help you use these new convenience methods, IntelliJ IDEA introduces two new live templates: <code>iop<\/code> for <code>println()<\/code> and <code>ior<\/code> for <code>readln()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_ReadName-2.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Expanding the example to use the convenience method readln()<\/em><\/figcaption><\/figure>\n\n\n\n<p>Note that these changes to the language are also taken into account when creating new projects. When you create a new Java project, set <em>Build system<\/em> to <em>IntelliJ<\/em>, and select <em>Add sample code<\/em>, a compact source file with a <code>void main()<\/code> method will be added.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_NewProject_IJ-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Creating a new project with the IntelliJ build system<\/em><\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Prototyping and teaching<\/h3>\n\n\n\n<p>While extremely useful for students and teachers, this feature does not just benefit beginners. It also allows experienced developers to quickly try out ideas or create a prototype.&nbsp;<\/p>\n\n\n\n<p>When you create a new Java project with Maven or Gradle as the selected build system, the generated source code will include a regular class, but with <code>IO.println()<\/code> instead of <code>System.out.println()<\/code>. If you are using Maven or Gradle, you\u2019re likely working on something bigger, with actual classes instead of compact source files. Another reason to use classes is that a compact source file needs to be in the default package, and frameworks generally don\u2019t support this.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_NewProject_Maven-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Creating a new project with Maven<\/em><\/figcaption><\/figure>\n\n\n\n<p>To quickly create a prototype, you can create a Java compact file from the <code>src\/main\/java<\/code> directory in the <em>Project <\/em>tool window. IntelliJ IDEA will provide a default name for the file, so your thought process is not disrupted when you want to quickly try something out.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_CompactSourceFile-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Creating a Java compact file<\/em><\/figcaption><\/figure>\n\n\n\n<p>When prototyping, learning, or teaching, you can gradually expand your code to include features you might need when writing code that is part of a larger project, or when introducing new concepts to your students. You can convert an implicit class to a regular class using the <em>Convert an implicitly declared class of a compact source file into a regular class <\/em>quick-fix.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_ConvertFileToClass-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Converting an implicitly declared class of a compact source file into a regular class<\/em><\/figcaption><\/figure>\n\n\n\n<p>Should you prefer to use an implicit class at any point, the reverse is also possible. Similarly, there are quick-fixes to convert <code>IO.println()<\/code> to <code>System.out.println()<\/code>, and vice versa. These are probably not things you would do as part of your daily work. But you might use features like this for coding challenges, like Advent of Code, or other fun side projects.<\/p>\n\n\n\n<p>The new <code>void main()<\/code> method does not need <code>String[] args<\/code>. However, should you decide to use the <code>args<\/code> in your code, IntelliJ IDEA will help you by adding them to the method, as you can see below. If you like this kind of completion, please let us know in the comments what you are currently missing.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_Args-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Completion to add `args` to the main method<\/em><\/figcaption><\/figure>\n\n\n\n<p>With this feature, we finally have a separation in Java between prototypes and other small projects, and enterprise applications. IntelliJ IDEA supports both small and large applications.&nbsp;<\/p>\n\n\n\n<p>We have already covered this feature in a previous <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/03\/java-24-and-intellij-idea\/\">Java 24 and IntelliJ IDEA<\/a> post, when it was still in preview. Please have a look at that post to learn about additional support for this feature in IntelliJ IDEA. For a more in-depth explanation of this specific feature, see <a href=\"https:\/\/blog.jetbrains.com\/author\/malagupta\/\">Mala Gupta<\/a>\u2019s previous post <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/02\/helloworld-and-main-meet-minimalistic\/\">Java 24: \u2018HelloWorld\u2019 and \u2018main()\u2019 meet minimalistic<\/a>. There are examples of practical use cases on when and how to use it to create small programs and prototypes in <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/02\/java-24-build-games-prototypes-utilities-and-more-with-less-boilerplate\/\">Java 24: Build Games, Prototypes, Utilities, and More \u2013 With Less Boilerplate<\/a>. Note that (among other things) the following was changed in Java 25: Compact source files were previously called simple source files, and you now need to use the qualified name <code>IO.println()<\/code> or use an import statement.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Module Import Declarations (JEP 511)<\/h2>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/511\" target=\"_blank\" rel=\"noopener\">Module import declarations<\/a> simplify the importing of frequently used classes (<code>java.base<\/code>) or modular libraries, without having to keep adding individual import statements to keep the compiler happy (even though IntelliJ IDEA can do this for you ?). This feature makes things easier. You can write code without needing to worry about imports, which is useful when learning or prototyping.<\/p>\n\n\n\n<p>Alternatively, if you have a class that imports multiple classes from a module, you can replace them with a module import statement. When you perform the <em>Optimize imports <\/em>action, the individual imports for classes imported by the module will be removed.<\/p>\n\n\n\n<p>As your codebase grows, you might prefer to add import statements with specific imports, which you can do using the <em>Replace with single class imports <\/em>quick-fix.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_OptimizeImports-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Optimizing imports<\/em><\/figcaption><\/figure>\n\n\n\n<p>If you would like to remove unused module imports when performing <em>Optimize imports<\/em>, you can configure this in the settings. Open <em>Settings<\/em> | <em>Editor | Code Style | Java<\/em> and go to the <em>Imports<\/em> tab. Then, select the <em>Delete unused module imports <\/em>option.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"1125\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image12.png\" alt=\"\" class=\"wp-image-604209\"\/><figcaption class=\"wp-element-caption\"><em>Configuring the IDE to delete unused module imports<\/em><\/figcaption><\/figure>\n\n\n\n<p>To see which packages are exported by a module, click on the module name in the editor or use the relevant shortcut for <em>Go to Declaration or Usages<\/em>, as shown <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/03\/java-24-and-intellij-idea\/#which-packages-are-exported-by-the-module-java.base-or-other-modules\">here<\/a>.&nbsp;<\/p>\n\n\n\n<p>You might wonder what the difference is between module imports and wildcard imports. Wildcard imports in Java allow you to replace the import for multiple classes from the same package with one line, containing an <code>*<\/code>. Module imports allow you to import classes from different packages. One downside of this is the risk of potential namespace clashes. But don\u2019t worry, IntelliJ IDEA can help you identify and fix these, as described <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/07\/module-import-declarations-no-more-import-hell\/#name-conflicts-compilation-error\">here<\/a>.&nbsp;<\/p>\n\n\n\n<p>Should you replace your current import statements with module imports? Probably not. In enterprise code, most developers prefer to have single imports. Note that IntelliJ IDEA allows you to configure the number of imports to add before replacing them with a wildcard. By default, this number is set to five. To change it, open <em>Settings<\/em>, go to <em>Editor | Code Style | Java<\/em>, and open the <em>Imports<\/em> tab. Then, set <em>Class count to use import with \u2018*\u2019<\/em> to the desired number. Since most coding standards prefer single imports over wildcard imports, we assume the same will be true for module imports. For this reason, we are not planning to have an inspection to automatically replace existing imports with <code>import module java.base;<\/code>.&nbsp;<\/p>\n\n\n\n<p>However, even if you\u2019re not using this feature explicitly, you will use it implicitly when using compact source files (described above). This feature was previously described in <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/03\/java-24-and-intellij-idea\/#module-import-declarations\">Java 24 and IntelliJ IDEA<\/a>. For more background information, see <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/07\/module-import-declarations-no-more-import-hell\/\">Module Import Declarations: No More Import Hell<\/a> by Mala Gupta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"jep-513\">Flexible Constructor Bodies (JEP 513)<\/h2>\n\n\n\n<p>With <a href=\"https:\/\/openjdk.org\/jeps\/513\" target=\"_blank\" rel=\"noopener\">flexible constructor bodies<\/a>, previously known as \u201cstatements before super()\u201d, you are now allowed to write statements in the constructor of a derived class before calling the constructor of the super class. This is useful if you want to validate or compute data in your constructor before passing it to <code>super()<\/code>, or when a superclass calls a method from its constructor that you want to override in the subclass and access a field from the subclass inside this method.&nbsp;<\/p>\n\n\n\n<p>Previously, the call to <code>super()<\/code> had to be the first call in the constructor. IntelliJ IDEA would give you a warning if you tried to add statements before <code>super()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1874\" height=\"1046\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/image11.png\" alt=\"\" class=\"wp-image-604220\"\/><figcaption class=\"wp-element-caption\"><em>Warning about a statement before `super()`<\/em><\/figcaption><\/figure>\n\n\n\n<p>A workaround for this restriction is to call static methods inline, as arguments passed to <code>super()<\/code>. While this is still possible, you now have the flexibility to call these methods before calling <code>super()<\/code> with the results.<\/p>\n\n\n\n<p>There are some limitations on which types of statements you can execute before the call to <code>super()<\/code>. The statements cannot access the object under construction, which means you cannot access instance members of a class before the execution of <code>super()<\/code> completes or call methods of the derived class.<\/p>\n\n\n\n<p>This new functionality should be used responsibly. Just because you <em>can<\/em> put arbitrary code before <code>super()<\/code> doesn\u2019t mean you should move every possible validation or I\/O operation into constructors. Constructors are best kept lightweight, deterministic, and free of heavy side effects. Expensive operations, retries, or external resource access are better handled in factories, builders, or initialization methods.<\/p>\n\n\n\n<p>In short, this feature lets you model object invariants more naturally through inheritance, but it doesn\u2019t change the golden rule \u2013 constructors should remain focused and predictable.<\/p>\n\n\n\n<p>While this feature might not be that exciting by itself, it is a necessary step to make <a href=\"https:\/\/openjdk.org\/jeps\/401\" target=\"_blank\" rel=\"noopener\">value classes and objects<\/a> (currently in preview), as well as upcoming <a href=\"https:\/\/openjdk.org\/jeps\/8316779\" target=\"_blank\" rel=\"noopener\">null-restricted value class types<\/a> (currently in draft), possible. Both of these features are part of <a href=\"https:\/\/openjdk.org\/projects\/valhalla\/\" target=\"_blank\" rel=\"noopener\">Project Valhalla<\/a>. We will discuss this topic later in a separate blog post.<\/p>\n\n\n\n<p>For a more detailed explanation of this feature and examples of how to use it, have a look at the following video featuring Dr. Venkat Subramaniam:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"JEP Explained. JEP 482: Flexible Constructor Bodies\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/3k2bIMFeIp8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>This feature was previously described in <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/03\/java-24-and-intellij-idea\/#flexible-constructor-bodies\">Java 24 and IntelliJ IDEA<\/a>. For additional details and examples, see Mala Gupta\u2019s previous blog post <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/02\/constructor-makeover-in-java-22\/\">Constructor Makeover in Java 22<\/a>. Note that this post was written when this feature was still in preview. The only significant change since then is that a constructor body is now allowed to initialize fields in the same class before invoking a constructor.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Scoped Values (JEP 506)<\/h2>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/506\" target=\"_blank\" rel=\"noopener\">Scoped values<\/a> are a new model for thread-local variables adapted to virtual threads. They make it possible to share immutable data within a thread and with child threads in a convenient, safe, and scalable way.<\/p>\n\n\n\n<p>In some cases, you want to share data between components of your application or between your application and a framework, such as information about a logged-in user and their permissions. While it is possible to use thread-local variables (variables of type <code>ThreadLocal<\/code>), there are several downsides to doing so, which might cause potential issues.<\/p>\n\n\n\n<p><code>ThreadLocal<\/code> variables are mutable, which makes it hard to keep track of their current value and to reason about the code. The value of a <code>ThreadLocal<\/code> variable is retained for the lifetime of a thread, unless explicitly removed by calling the <code>remove()<\/code> method. Developers may forget to do so, which means data might be stored in memory longer than needed, leading to potential performance problems, as well as security issues because data might be visible to unrelated code running on the same thread. <code>ThreadLocal<\/code> variables can be inherited by a child thread, but each child thread will need to create a copy of the variable, which can add to the memory footprint.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/444\" target=\"_blank\" rel=\"noopener\">Virtual threads<\/a>, added in Java 21, allow us to create many more threads than platform threads. If they each retain a copy of a thread-local variable, this will impact the memory usage. On the other hand, virtual threads may not live as long as platform threads, which minimizes the potential for memory leaks.&nbsp;<\/p>\n\n\n\n<p>To use a <code>ScopedValue<\/code>, you need to first declare it. It makes sense to declare it as final. Next, you need to bind the <code>ScopedValue<\/code> to some data and pass a <code>Runnable<\/code> or <code>ScopedValue.CallableOp<\/code>, which may be realized as a lambda. This is done in the <code>ScopedValue.where()<\/code> method. The operation \u2013 and any code called from it \u2013 will be able to get the <code>ScopedValue<\/code>, but once it is done running, this data will be cleaned up. Scoped values have a clearly defined scope, which makes the code easier to reason about. If you try to use a <code>ScopedValue<\/code> that is not bound, a <code>NoSuchElementException<\/code> is thrown, as you can see in the following example.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java25_ScopedValue-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Using `ScopedValue`<\/em><\/figcaption><\/figure>\n\n\n\n<p>While you cannot set a <code>ScopedValue<\/code>, you can rebind it. In the example below, the variable is bound to the value &#8220;24&#8221; inside the main method. The <code>update()<\/code> method is called from here, where the value is bound to &#8220;25&#8221; (24 + 1). When printed, it will print the current value, &#8220;25&#8221;.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class RebindExample {\n\u00a0\u00a0\u00a0ScopedValue&lt;Integer> JAVA_VERSION = ScopedValue.newInstance();\n\u00a0\u00a0\u00a0void main() {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ScopedValue.where(JAVA_VERSION, 24).run(this::update);\n\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0private void update() {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ScopedValue.where(JAVA_VERSION, JAVA_VERSION.get() + 1).run(() -> {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IO.println(\"Hello, Java \" + JAVA_VERSION.get()); \/\/ prints 25\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\n\u00a0\u00a0\u00a0}\n}<\/pre>\n\n\n\n<p>Scoped values are even more useful with <a href=\"https:\/\/openjdk.org\/jeps\/505\" target=\"_blank\" rel=\"noopener\">structured concurrency<\/a>, currently in its fifth preview.<\/p>\n\n\n\n<p>Structured concurrency will make it possible for data to be automatically inherited by any threads that a thread forks. The child threads\u2019 scope will be contained in the parent thread\u2019s scope. With scoped values, it is no longer necessary to make copies of the data, meaning they scale very well with many (virtual) threads. This topic deserves its own blog post, where we can dive deeper into new use cases, migration paths, and performance comparisons between different approaches.&nbsp;<\/p>\n\n\n\n<p>As we have seen, scoped values solve several problems associated with <code>ThreadLocal<\/code>.They reduce memory overhead, improve predictability, and make reasoning about concurrent code much easier. Does this mean you should immediately rewrite all your code to use <code>ScopedValue<\/code>? Not necessarily. Frameworks like Spring and others still rely heavily on <code>ThreadLocal<\/code>, and migrating all existing components to Java 25 isn\u2019t something that will happen overnight. Also, the intention behind scoped values was never to deprecate or replace <code>ThreadLocal<\/code> outright, but to offer a cleaner, safer alternative. However, you might consider using scoped values for new code or modules, especially where you are already facing typical <code>ThreadLocal<\/code> issues: leaks, context propagation, and cleanup.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Performance and profiler improvements<\/h2>\n\n\n\n<p>Language features are just half of the story. Java 25 also brings significant runtime improvements. Let\u2019s take a brief look at the changes:<\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/openjdk.org\/jeps\/515\" target=\"_blank\" rel=\"noopener\">Ahead-of-Time Method Profiling<\/a> (JEP 515) speeds up warm-up by using method execution profile data from a prior run. The JVM can use that data immediately at startup so that hot methods are already known, reducing the delay before reaching peak performance.&nbsp;<\/li>\n\n\n\n<li><a href=\"https:\/\/openjdk.org\/jeps\/518\" target=\"_blank\" rel=\"noopener\">JFR Cooperative Sampling<\/a> (JEP 518) and <a href=\"https:\/\/openjdk.org\/jeps\/520\" target=\"_blank\" rel=\"noopener\">JFR Method Timing &amp; Tracing<\/a> (JEP 520) improve observability: Cooperative sampling lets threads report profiling data at safe points to reduce overhead and increase accuracy, and method timing and tracing give more precise, detailed call durations and call stack information.&nbsp;<\/li>\n\n\n\n<li><a href=\"https:\/\/openjdk.org\/jeps\/519\" target=\"_blank\" rel=\"noopener\">Compact Object Headers<\/a> (JEP 519) shrink the object header on 64-bit JVMs from its larger experimental form to a compact 64-bit layout. This reduces memory overhead (especially with many small objects) and improves garbage collection (GC) and cache behavior.&nbsp;<\/li>\n\n\n\n<li><a href=\"https:\/\/openjdk.org\/jeps\/521\" target=\"_blank\" rel=\"noopener\">Generational Shenandoah<\/a> (JEP 521) adds generational GC support to the Shenandoah garbage collector so that young-generation objects can be collected more efficiently, reducing pause times and improving throughput for workloads with many short-lived objects.<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Moving from Java 21 to Java 25<\/h1>\n\n\n\n<p>If you are upgrading to Java 25 from Java 21, here is an overview of some of the stable features you might not be familiar with yet.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Stream Gatherers (JEP 485)<\/h2>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/485\" target=\"_blank\" rel=\"noopener\">Stream Gatherers<\/a> were added in <a href=\"https:\/\/openjdk.org\/projects\/jdk\/24\/\" target=\"_blank\" rel=\"noopener\">Java 24<\/a>. They improve the Stream API, added in Java 8. Stream gatherers allow you to add your own custom intermediate operations to a stream.<\/p>\n\n\n\n<p>For an explanation of this feature and how you can use it, watch the following livestream with Jos\u00e9 Paumard:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Gatherers: The API Your Stream Was Missing\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/oVdWfU_IObY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>If you\u2019d like more background information on this feature, you might be interested in the following video we created when this feature was still in preview:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"JEP Explained. JEP 473: Stream Gatherers\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/m7PW6fMCrmg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Finally, we highly recommend this video from JavaOne by Viktor Klang, the creator of the feature:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Stream Gatherers - Deep Dive with the Expert\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/v_5SKpfkI2U?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Markdown Documentation Comments (JEP 467)<\/h2>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/467\" target=\"_blank\" rel=\"noopener\">Markdown documentation comments<\/a> were added in <a href=\"https:\/\/openjdk.org\/projects\/jdk\/23\/\" target=\"_blank\" rel=\"noopener\">Java 23<\/a>. As the name suggests, it is now possible to use Markdown in your JavaDoc. Back when Java was first created, HTML seemed like a logical choice for JavaDoc, but these days you might prefer Markdown.&nbsp;<\/p>\n\n\n\n<p>IntelliJ IDEA supports the adoption of this feature by offering a quick-fix to convert JavaDoc to Markdown. If you have JavaDoc that you would like to convert, press <em>Alt+Enter<\/em> when the cursor is on your JavaDoc and select the <em>Convert to Markdown documentation comment <\/em>option.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java_ConvertMarkdown-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Converting a documentation comment to Markdown<\/em><\/figcaption><\/figure>\n\n\n\n<p>Does this mean you should convert your existing JavaDoc to Markdown? Not necessarily. You might just consider writing your documentation in Markdown from now on. However, should you want to convert it, IntelliJ IDEA can help you.<\/p>\n\n\n\n<p>For more information on this feature, have a look at <a href=\"https:\/\/blog.jetbrains.com\/idea\/2025\/04\/markdown-in-java-docs-shut-up-and-take-my-comments\/\">Markdown in Java Docs? Shut Up and Take My Comments!<\/a> by Mala Gupta.<\/p>\n\n\n\n<p>If you\u2019re interested in more background on this feature, check out the video that was created when it was still in preview:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"JEP Explained. JEP 467: Markdown Documentation Comments\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/hEWU2OMtNnw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Unnamed Variables &amp; Patterns (JEP 456)<\/h2>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/456\" target=\"_blank\" rel=\"noopener\">Unnamed variables and patterns<\/a> make it possible to use unnamed variables and unnamed patterns when variable declarations or nested patterns are required but the actual variables or patterns are not used. Denoting unnamed variables and patterns with an <code>_<\/code> clearly conveys that they are not used elsewhere in the code. IntelliJ IDEA will detect when an unused local variable could be replaced with an underscore <code>_<\/code> and offer a quick-fix to do so.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/Java_UnnamedVariable-1.mp4\"><\/video><figcaption class=\"wp-element-caption\"><em>Renaming a variable to \u2018_\u2019<\/em><\/figcaption><\/figure>\n\n\n\n<p>For more details on this feature, see <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/03\/drop-the-baggage-use-_-for-unnamed-local-variables-and-patterns-in-java-22\/\">Drop the Baggage: Use \u2018_\u2019 for Unnamed Local Variables and Patterns in Java 22<\/a> by Mala Gupta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Virtual Threads (JEP 444) and Synchronize Virtual Threads without Pinning (JEP 491)<\/h2>\n\n\n\n<p>Added in <a href=\"https:\/\/openjdk.org\/projects\/jdk\/21\/\" target=\"_blank\" rel=\"noopener\">Java 21<\/a>, <a href=\"https:\/\/openjdk.org\/jeps\/444\" target=\"_blank\" rel=\"noopener\">virtual threads<\/a> are lightweight threads. Unlike platform threads, which are limited by the number of cores in your machine, you can create a potentially unlimited number of virtual threads. Virtual threads improve the scalability of your applications. They do need platform threads to perform their work, but can release them when they are waiting for blocking code. Tooling like <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/24\/docs\/specs\/man\/jcmd.html\" target=\"_blank\" rel=\"noopener\">jcmd<\/a> and IntelliJ IDEA can collect thread dumps with virtual threads included.<\/p>\n\n\n\n<p><a href=\"https:\/\/openjdk.org\/jeps\/491\" target=\"_blank\" rel=\"noopener\">Synchronizing virtual threads without pinning<\/a> (added in Java 24) improves the scalability of Java code that uses <code>synchronized<\/code> code. Virtual threads that block in <code>synchronized<\/code> blocks now release their underlying platform threads so they can be used by other virtual threads. This last improvement comes for free when you upgrade from Java 21 to Java 24 or higher. To see this in action, watch the demo we did in the What\u2019s New in IntelliJ IDEA 2025.2 livestream.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"What\u2019s New in IntelliJ IDEA 2025.2 | IntelliJ IDEA Talk\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/_nt-z0FS3tM?start=871&#038;feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Runtime and security improvements<\/h2>\n\n\n\n<p>Java 24 introduced some changes related to post-quantum cryptography readiness. The Java platform is preparing for the future of secure computing:&nbsp;<\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/openjdk.org\/jeps\/496\" target=\"_blank\" rel=\"noopener\">Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism<\/a> (JEP 496) and <a href=\"https:\/\/openjdk.org\/jeps\/497\" target=\"_blank\" rel=\"noopener\">Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm<\/a> (JEP 497), introduced in Java 24, are NIST-standardized post-quantum algorithms (lattice-based) aimed at replacing or augmenting classic public-key operations like RSA and ECDSA. Java also receives a performance boost. Garbage collection, memory footprint, and startup times all see measurable improvements:<\/li>\n<\/ul>\n\n\n\n<ul>\n<li><a href=\"https:\/\/openjdk.org\/jeps\/423\" target=\"_blank\" rel=\"noopener\">Region Pinning for G1<\/a> (JEP 423) allows the G1 garbage collector to continue collecting parts of the heap even when some regions are in JNI critical sections. Instead of stalling GC during such critical regions, only \u201cpinned\u201d regions are excluded, reducing latency in mixed JNI\/native workloads.&nbsp;<\/li>\n\n\n\n<li>The <a href=\"https:\/\/openjdk.org\/jeps\/454\" target=\"_blank\" rel=\"noopener\">Foreign Function &amp; Memory API<\/a> (JEP 454), added in <a href=\"https:\/\/openjdk.org\/projects\/jdk\/22\/\" target=\"_blank\" rel=\"noopener\">Java 22<\/a>, offers better performance and safety over the old JNI for foreign memory and calling native code. Bulk operations are more efficient, with less overhead in cross-boundary calls.&nbsp;<\/li>\n\n\n\n<li><a href=\"https:\/\/openjdk.org\/jeps\/474\" target=\"_blank\" rel=\"noopener\">ZGC: Generational Mode by Default<\/a> (JEP 474). The Z Garbage Collector, which is typically low-pause, uses generational mode by default starting with Java 23. Separation between young and old objects improves GC efficiency for applications that create many short-lived objects.<\/li>\n<\/ul>\n\n\n\n<p>Additionally, there are further enhancements to core libraries, previews, and performance ergonomics \u2013 for example, improvements to default GC settings, memory management, etc.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Upgrading from Java 21 to 25<\/h2>\n\n\n\n<p>You can find a video series that covers the <a href=\"https:\/\/www.youtube.com\/playlist?list=PLX8CzqL3ArzXJ2_0FIGleUisXuUm4AESE\" target=\"_blank\" rel=\"noopener\">Road to Java 25<\/a> on the official <a href=\"https:\/\/www.youtube.com\/@java\" target=\"_blank\" rel=\"noopener\">Java YouTube channel<\/a>. We recommend watching <a href=\"https:\/\/www.youtube.com\/watch?v=9azNjz7s1Ck\" target=\"_blank\" rel=\"noopener\">How to Upgrade to Java 25<\/a> by <a href=\"https:\/\/nipafx.dev\/\" target=\"_blank\" rel=\"noopener\">Nikolai Parlog<\/a>. The Oracle DevRel team also has a <a href=\"https:\/\/dev.java\/community\/java-25-launch\/\" target=\"_blank\" rel=\"noopener\">Java 25 livestream<\/a> on September 16, 2025.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n\n<p>As you have seen, several additions to the language make Java easier to use, both for students and teachers, as well as experienced programmers. In fact, these features completely change the experience of using Java, by no longer requiring boilerplate code like the <code>public static void main(String[] args)<\/code> method, allowing statements before <code>super()<\/code>, offering the possibility to add custom intermediary operations in streams using gatherers, allowing underscores as variable names for unused variables, and and providing scoped values as a convenient, safe, and scalable alternative to <code>ThreadLocal<\/code>. With all of these changes, Java is moving forward fast. IntelliJ IDEA aims to move just as quickly by supporting these new features with relevant inspections and quick-fixes, as well as new live templates, and integrating them into existing features like the <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/debugging-code.html\" target=\"_blank\" rel=\"noopener\">debugger<\/a>. Other than improvements in the language, there are also runtime improvements that you get for free when upgrading your JDK.<\/p>\n\n\n\n<p>We think Java 25 is the best Java release (so far!) and we recommend you switch to it as soon as you can. Even if you\u2019re not using the Java language features, you will still benefit from using the new JDK. Java 25 offers a new baseline for the language, and the runtime is the fastest it has ever been.<\/p>\n\n\n\n<p>If you are on Java 21, we have provided an overview of what you might have missed in terms of language features. And if you\u2019re on an even older version of Java, now would be the time to start the process to upgrade, not just because of the benefits to you but also because the ecosystem is moving forward. Java 17 is the current <a href=\"https:\/\/spring.io\/blog\/2022\/03\/28\/an-update-on-java-17-adoption\" target=\"_blank\" rel=\"noopener\">baseline for Spring and Spring Boot<\/a> as of Spring 6 or Spring Boot 3. The upcoming <a href=\"https:\/\/maven.apache.org\/whatsnewinmaven4.html\" target=\"_blank\" rel=\"noopener\">Maven 4 will require JDK 17<\/a> to run. But don\u2019t worry, you can still compile projects with older Java versions! The upcoming <a href=\"https:\/\/github.com\/junit-team\/junit-framework\/issues\/4246\" target=\"_blank\" rel=\"noopener\">JUnit 6 is also targeting JDK 17<\/a>. If you are still on Java 8 (or older), now is the time to start upgrading!<\/p>\n\n\n\n<p>IntelliJ IDEA will continue to support the latest Java features with Java 26. If you would like to try them out, you can download the EA versions from inside IntelliJ IDEA as soon as they become available. And, as always, please let us know if you have any feedback.<\/p>\n","protected":false},"author":1342,"featured_media":606099,"comment_status":"closed","ping_status":"closed","template":"","categories":[5088,89,2347,3637],"tags":[40,155,8921,8923,8924,8922,477],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/idea\/604053"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/users\/1342"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/comments?post=604053"}],"version-history":[{"count":9,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/idea\/604053\/revisions"}],"predecessor-version":[{"id":644975,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/idea\/604053\/revisions\/644975"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media\/606099"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media?parent=604053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/categories?post=604053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/tags?post=604053"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/cross-post-tag?post=604053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}