<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arkadiusz Rosloniec</title>
    <description>The latest articles on DEV Community by Arkadiusz Rosloniec (@aroso1991).</description>
    <link>https://dev.to/aroso1991</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1843235%2F5acda387-1c04-401c-93cb-c7774939d1b9.png</url>
      <title>DEV Community: Arkadiusz Rosloniec</title>
      <link>https://dev.to/aroso1991</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aroso1991"/>
    <language>en</language>
    <item>
      <title>Camunda 7 vs Camunda 8: Migration and other possible scenarios</title>
      <dc:creator>Arkadiusz Rosloniec</dc:creator>
      <pubDate>Tue, 24 Dec 2024 08:44:17 +0000</pubDate>
      <link>https://dev.to/aroso1991/camunda-7-vs-camunda-8-migration-and-other-possible-scenarios-1em6</link>
      <guid>https://dev.to/aroso1991/camunda-7-vs-camunda-8-migration-and-other-possible-scenarios-1em6</guid>
      <description>&lt;p&gt;The newest Camunda version – Camunda 8 – differs significantly from the previous iteration, Camunda 7, which will lose support in the near future. For many businesses, this creates a dilemma: migrate or stay. In this Camunda 7 vs Camunda 8 comparison article, we’ll show you the benefits of both options and provide some potential scenarios you can follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Camunda?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdijw2a2h04ujy4y0gz67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdijw2a2h04ujy4y0gz67.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Camunda is a powerful BPM system that started as a fork of another open-source solution – Activiti. Currently, there are actually three distinct Camunda products:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Camunda 7 Community Edition&lt;/strong&gt;  – The open-source variant of Camunda, currently still maintained and developed by the company but entering the EOL (end of life) stage on October 14, 2025, when the GitHub repository will be archived and all pull requests will be closed (the code will still be available though).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Camunda 7 Enterprise&lt;/strong&gt; – The older, paid version of the technology, which is slowly being replaced by Camunda 8 and can be considered a subset of it. It offers some of the features the newer platform has (though sometimes named differently), but, overall, the 8 is a better all-around paid alternative.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Camunda 8&lt;/strong&gt; – The newest toy in Camunda’s toolbox, with an entirely new process and decision engine, a different approach to databases, and many other changes “under the hood”. Unfortunately, it has no open-source variant and comes with a new licensing model. It basically means you can no longer use key components for free in the production environment (only during development), so the only way to implement Camunda 8 in your business is to pay for the license. Camunda 8 is available in both SaaS and self-hosted versions, with 2-3 &lt;a href="https://camunda.com/pricing/" rel="noopener noreferrer"&gt;pricing plans&lt;/a&gt; for each variant.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the purpose of this article, whenever we compare Camunda 7 to Camunda 8, we mean the Community Edition of the former. This is because, in our opinion, there’s no point in comparing the paid variants. If you’re determined to pay for the Enterprise version anyway, Camunda 8 is probably the better and more future-proof option. Moreover, from what we heard at NY Camundacon 2024, Camunda 7 Enterprise will stop being actively sold in 2025. Full support will only be provided until &lt;a href="https://docs.camunda.org/enterprise/announcement/" rel="noopener noreferrer"&gt;April 2027&lt;/a&gt;, after which it’ll enter the extended support stage (bug fixes and security updates only).&lt;/p&gt;

&lt;h2&gt;
  
  
  Camunda 7 vs 8: Biggest differences
&lt;/h2&gt;

&lt;p&gt;Camunda introduced significant changes to the latest version of its solution. Let’s examine their most important differences. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Camunda 7 had a free, open-source version, whereas 8 is only available as a paid product.&lt;/li&gt;
&lt;li&gt;Camunda 8 is cloud-native and built for much better scalability (you can still deploy it on-premise if you want, but the SaaS version is the default approach).&lt;/li&gt;
&lt;li&gt;Camunda 8 has a completely new process engine called Zeebe, which was built with horizontal scaling in mind and uses the Event-Driven Architecture.&lt;/li&gt;
&lt;li&gt;Camunda 8 has a new decision engine that automatically triggers DMN models at the level of BPMN processes and provides them with input data.&lt;/li&gt;
&lt;li&gt;Camunda 8 is based on microservices (distributed architecture that runs on a Kubernetes cluster), whereas Camunda 7 is designed to be used more in monolithic applications.&lt;/li&gt;
&lt;li&gt;Camunda 8 uses the eventual consistency asynchronous model, which is popular in distributed systems (this means that the data across different nodes might be temporarily inconsistent but will achieve consistency with time, as all replicas of data items will converge at some point).&lt;/li&gt;
&lt;li&gt;Camunda 8 uses a document database instead of the relational database that Camunda 7 requires.&lt;/li&gt;
&lt;li&gt;Camunda 8 provides Cockpit – a ready-made front-end component (dashboard) you can use to access and do all sorts of cool things, like process tracking, heatmaps, detecting critical spots in your workflows, etc. Camunda 7 provides a similar functionality, though less robust and only in the Enterprise version.&lt;/li&gt;
&lt;li&gt;Camunda 8 has a built-in Web Modeler – a web-based tool for modeling diagrams for execution and deployment with BPMN-powered flowcharts.&lt;/li&gt;
&lt;li&gt;Camunda 8 offers plenty of ready-made, one-click plugins you can use to integrate with various popular SaaS tools without a single day of custom development.&lt;/li&gt;
&lt;li&gt;Camunda 8 will soon get Copilot support with useful AI-powered capabilities, such as providing AI-powered suggestions for process development and orchestration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problems with migrating from Camunda 7 to 8
&lt;/h2&gt;

&lt;p&gt;Let’s be blunt – the biggest problem with a Camunda 7 to Camunda 8 migration is that… it’s actually not a migration, at least in the technical sense. This is because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can’t rewrite the process engine – they’re simply too different.&lt;/li&gt;
&lt;li&gt;Migrating from a relational database to a document database would be complicated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conclusion is that trying to do a technical migration in this case is a recipe for disaster – we advise against it. &lt;strong&gt;The only feasible approach is to simply set Camunda 8 up and move all of your workflows from 7 to 8 manually.&lt;/strong&gt; Unfortunately, this also means it can be quite time-consuming and expensive.&lt;/p&gt;

&lt;p&gt;It’s worth pointing out that Camunda published &lt;a href="https://camunda.com/platform-7/migrate/" rel="noopener noreferrer"&gt;some articles&lt;/a&gt; on the subject of Camunda 7 to 8 migration, but, as you can see, they’re very general in nature. The company can also provide migration consultants to help companies move from 7 to 8, but, the way we see it, in reality, their main job is to tell you just what we wrote above, but in a nicer and more supportive manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camunda 7 to 8 migration and other scenarios
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsegipm7bn7t4xcu4e8zo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsegipm7bn7t4xcu4e8zo.png" alt="Image description" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, in light of that, what to do when you’re still on Camunda 7? The way we see it, you have four main options going forward. Let’s examine each of them in more detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrate to Camunda 8
&lt;/h3&gt;

&lt;p&gt;The first obvious option is to simply move from Camunda 7 to Camunda 8. The process will take some time and may give you a headache or two, and you’ll need to pay for the license, but if you’re interested in cutting-edge features and want the best scalability Camunda can offer right now, this is probably the way to go.&lt;/p&gt;

&lt;p&gt;It’s a feasible approach for big, international companies (think global corporations, Silicon Valley tech leaders, banks, etc.) that truly need a scalable solution, can soak up the costs and will probably make the best use of all the advanced bells and whistles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stay with Camunda 7 and maintain it yourself
&lt;/h3&gt;

&lt;p&gt;The other option is to stay with Camunda 7 Community Edition. The truth is that many companies simply don’t need all the advanced features Camunda 8 offers – all they really require from a BPM solution is already provided by the open-source variant. You can maintain it and even develop new features yourself or with the help of a software partner you trust. It’s also a very mature technology, so there’s a fair chance that you won’t need to do that much maintenance anyway.&lt;/p&gt;

&lt;p&gt;Based on our Camundacon observations, Camunda doesn’t seem very interested in small-scale customers who simply want a functional BPM engine. Their focus is squarely on enterprises, and that’s fine – that’s their business choice. However, that doesn’t mean your only option is to pay for their latest and shiniest.&lt;/p&gt;

&lt;p&gt;The main drawback to this approach is that Camunda 7 Community Edition’s EOL has already been announced. What does that mean in practice? The way we see it, the biggest problem is that whenever some technology – like Spring or Java – gets a significant new version, updating Camunda to eliminate vulnerabilities and bugs will be on you. Sure, there will still be a community around Camunda, and that should help – but the official repository will be closed (only forks will remain, and each might follow a different path) and relying on the community for critical updates may, in itself, be somewhat problematic, depending on your circumstances (industry, business scale, etc.).&lt;/p&gt;

&lt;p&gt;🛟 &lt;strong&gt;Need help with updating or maintaining a Camunda-based solution?&lt;/strong&gt; Check out our &lt;a href="https://pretius.com/services/bpm-system/" rel="noopener noreferrer"&gt;BPM system services&lt;/a&gt; – there’s a good chance we’ll be able to help you out!&lt;/p&gt;

&lt;h3&gt;
  
  
  Use another dedicated BPM tool
&lt;/h3&gt;

&lt;p&gt;Another choice you can make is to migrate to a completely different BPM tool that provides the functionalities you need without the stuff you don’t. There are plenty of solid Camunda alternatives on the market, such as Activiti (check out our &lt;a href="https://pretius.com/blog/camunda-vs-activiti/" rel="noopener noreferrer"&gt;Camunda vs Activiti&lt;/a&gt; comparison piece to learn more about the technology), Webcon, etc.&lt;/p&gt;

&lt;p&gt;The drawback is, of course, that you and your team will need to learn an entirely new solution – but it just might be worth the effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use a low-code platform with BPM capabilities
&lt;/h3&gt;

&lt;p&gt;Finally, there’s also a fourth option. It may not be the first idea that comes to mind, but in some cases, it might be the best choice – instead of a dedicated BPM system, you can invest in a low-code platform with workflow management capabilities and create a BPM application just the way you want it, but without the hassle of long and costly custom software development. &lt;/p&gt;

&lt;p&gt;There are many solid low-code platforms to choose from for this purpose, including two trusted solutions we know very well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Oracle APEX&lt;/strong&gt; – APEX is a powerful low-code tool that you actually get for free with an Oracle DB license, which is great from the cost optimization perspective. With APEX, you can access BPM capabilities through the Flows for APEX extension, available in two versions: the free, open-source Community Edition that provides all the basic features you’d expect from a BPM engine, and the Enterprise Edition, a paid variant with additional functionalities (process collaboration tools, BPMN iteration and loops, GenAI support) and product support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mendix&lt;/strong&gt; – Mendix is one of the leading low-code platforms (according to the Gartner’s report on the LCAP market), and it provides powerful workflow management capabilities in the form of a built-in Workflow Editor available within Mendix Studio Pro (it’s basically a visual language integrated with visual editors, such as the microflow editor and page editor). The Workflow Editor allows you to build various extendable processes and automate them end-to-end. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best thing about this approach is that low-code platforms can do so much more than just deliver BPM solutions – they can become fundamental parts of a company’s tech stack. Whatever system you’ll need in the future, there’s a good chance you’ll be able to create it using your chosen low-code tool. And we don’t just mean small internal apps either, but also large-scale, publicly available solutions or products – just check out Przemek Staniszewski’s article on &lt;a href="https://pretius.com/blog/oracle-apex-public-apps/" rel="noopener noreferrer"&gt;Oracle APEX public apps&lt;/a&gt; if you don’t believe us.&lt;/p&gt;

&lt;p&gt;🛠️ &lt;strong&gt;Need help with low-code development based on Mendix or Oracle APEX?&lt;/strong&gt; Write to us at &lt;a href="mailto:hello@pretius.com"&gt;&lt;/a&gt;&lt;a href="mailto:hello@pretius.com"&gt;hello@pretius.com&lt;/a&gt; – we have extensive experience and would be happy to help.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do with your Camunda 7?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flplfy9s4pb38zt26g9zi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flplfy9s4pb38zt26g9zi.png" alt="Image description" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to choosing between Camunda 7 and Camunda 8, understanding the key differences can significantly impact your decision-making process. Camunda 7 Community Edition has long been a staple for businesses seeking to marry great process automation capabilities with cost-effectiveness, and that hasn’t really changed. &lt;/p&gt;

&lt;p&gt;Of course, it doesn’t mean Camunda 8 has no advantages. Its Cockpit provides additional capabilities (better real-time analytics and so on) and improved user experience, and the web modeler and plugins are also great. Most of all, its scalability is a crucial advantage for enterprises; built on microservices architecture, it allows huge businesses to adapt quickly to changing demands without compromising performance. &lt;/p&gt;

&lt;p&gt;Moving from Camunda 7 to 8 is problematic, though, and (depending on your circumstances) not always worth it, considering the licensing costs and compelling alternatives – especially well-established low-code platforms that can help you build apps to cover your workflow management needs, but offer so much more on top of that.&lt;/p&gt;

&lt;p&gt;If you’re still not sure which way to go, just drop us a line at &lt;a href="mailto:hello@pretius.com"&gt;&lt;/a&gt;&lt;a href="mailto:hello@pretius.com"&gt;hello@pretius.com&lt;/a&gt;. We’ll analyze your current tech stack, your business goals and help you with choosing the most future-proof solution.&lt;/p&gt;

&lt;p&gt;And, if you want to read more about Camunda and some of its competitors, check out the other BPM-related articles on our blog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/camunda-bpm/" rel="noopener noreferrer"&gt;Camunda BPM – What is it, how to use it, and how does it compare with Activiti, Webcon and PowerApps?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/camunda-vs-activiti/" rel="noopener noreferrer"&gt;Camunda vs Activiti: Should your business consider a migration?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/business-analyst-tools/" rel="noopener noreferrer"&gt;Business analyst tools you need to do your job well&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>camunda</category>
      <category>bpm</category>
      <category>bpmn</category>
    </item>
    <item>
      <title>Java 23 features: A deep dive into the newest enhancements</title>
      <dc:creator>Arkadiusz Rosloniec</dc:creator>
      <pubDate>Fri, 06 Dec 2024 11:30:08 +0000</pubDate>
      <link>https://dev.to/aroso1991/java-23-features-a-deep-dive-into-the-newest-enhancements-3jg1</link>
      <guid>https://dev.to/aroso1991/java-23-features-a-deep-dive-into-the-newest-enhancements-3jg1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Oracle released yet another version of Java with powerful enhancements for bytecode manipulation, tool development, code quality, and more. Here are the most interesting and useful Java 23 features – from the perspective of a Java Team Leader with 10+ years of experience in this technology.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As Java continues to evolve, each new release aims to introduce features that improve the language’s performance, usability, and flexibility. By adopting this release, you can stay ahead of the curve and prepare for when these features become stable in future LTS versions.&lt;/p&gt;

&lt;p&gt;In this article, I will give you a quick overview of significant changes in Java 23, focusing on the most notable JEPs (JDK Enhancement Proposals). Those interested in previous changes can check out my earlier article on &lt;a href="https://pretius.com/blog/java-21-features/" rel="noopener noreferrer"&gt;Java 21 features&lt;/a&gt;, and you can also read Dariusz Wawer’s older piece with a detailed description of &lt;a href="https://pretius.com/blog/java-17-features/" rel="noopener noreferrer"&gt;Java 17 features&lt;/a&gt; (along with a comparison to Java 8).&lt;/p&gt;

&lt;p&gt;For code examples, you have to add &lt;strong&gt;--enable-preview&lt;/strong&gt; flag to your compiler args.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primitive Types in Patterns, instanceof, and switch (Preview)
&lt;/h2&gt;

&lt;p&gt;Primitive types have always been integral to Java, but handling them in patterns, &lt;strong&gt;instanceof&lt;/strong&gt;, and &lt;strong&gt;switch&lt;/strong&gt; constructs was limited. &lt;a href="https://openjdk.org/jeps/455" rel="noopener noreferrer"&gt;JEP 455&lt;/a&gt; aims to extend pattern matching and the &lt;strong&gt;switch&lt;/strong&gt; statement to support primitive types.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static String processInput(Object obj) {    
   return switch (obj) {        
      case Integer i -&amp;gt; "Integer value: %s".formatted(i);        
      case Double d -&amp;gt; "Double value: %s".formatted(d);        
      default -&amp;gt; "Unknown type";    
   }; 
} 

public static void main(String[] args) {
   System.out.println(processInput(10));    // Integer value: 10
   System.out.println(processInput(5.5));   // Double value: 5.5 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This enhancement allows developers to write cleaner and more concise code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Class-File API (Second Preview)
&lt;/h2&gt;

&lt;p&gt;Java's class file format is crucial for bytecode manipulation and tool development. &lt;a href="https://openjdk.org/jeps/466" rel="noopener noreferrer"&gt;JEP 466&lt;/a&gt; introduces the second preview of a new Class-File API, simplifying access to and manipulation of Java class files without requiring developers to rely on third-party libraries like ASM or BCEL.&lt;/p&gt;

&lt;p&gt;This API will greatly benefit those working on frameworks, compilers, or tools that need to inspect or modify class files. With its straightforward design, it enhances flexibility while keeping developers closer to Java’s native mechanisms. You can find a simple example of interacting with a new API below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
   ClassFile classFile = ClassFile.of();
   ClassModel model=classFile.parse(Paths.get("/home/ExampleClass.class"));
   System.out.println("Class Name: " + model.thisClass());
   // Class Name: 7 java23/ExampleClass
   model.methods().forEach(
method -&amp;gt; System.out.println(" - " + method.methodName()));
   //- &amp;lt;init&amp;gt;
   //- sayHello
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stream Gatherers (Second Preview)
&lt;/h2&gt;

&lt;p&gt;Another preview feature brings very nice enhancements to the Java Stream API. As JEP473 documentation states, the main goals are to make stream pipelines more flexible and expressive and allow custom intermediate operations to manipulate streams of infinite size. Below are a few examples of built-in gathers operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stream.of("A", "B", "C", "D", "E")
       .gather(Gatherers.fold(() -&amp;gt; "", (a, b) -&amp;gt; a + b))
       .forEach(System.out::println);
//ABCDE
Stream.of("A", "B", "C", "D")
       .gather(Gatherers.windowFixed(2))
       .forEach(System.out::println);
//[A, B]
//[C, D]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, there is the possibility of creating your gatherers. To do that, you just have to implement the java.util.stream.Gatherer interface. &lt;/p&gt;

&lt;h2&gt;
  
  
  Scoped Values (Third Preview)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/481" rel="noopener noreferrer"&gt;JEP 481&lt;/a&gt; introduces scoped values, which are an alternative to thread-local variables. They provide a mechanism for sharing values within a specific scope, making it easier to work with multi-threaded applications. Let’s dive into code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Jep481ScopedValues {
   private static ScopedValue&amp;lt;String&amp;gt; X = ScopedValue.newInstance();


   public static void main(String[] args) {
       foo();
   }


   static void foo() {
       ScopedValue.runWhere(X, "foo", () -&amp;gt; bar());
   }


   static void bar() {
       System.out.println("Printing X from bar(): " + X.get());
       ScopedValue.runWhere(X, "bar", () -&amp;gt; baz());
       System.out.println("Printing X from bar(): " + X.get());
   }


   static void baz() {
       System.out.println("Printing X from baz(): " + X.get());
   }
}


Output:


Printing X from bar(): foo
Printing X from baz(): bar
Printing X from bar(): foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Flexible Constructor Bodies (Second Preview)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/482" rel="noopener noreferrer"&gt;JEP 482&lt;/a&gt; revisits constructor flexibility in Java. Traditionally, constructor bodies in Java were limited in how they could be structured and how exceptions could be handled. This JEP introduces more flexibility, allowing developers to write more complex initialization logic within constructors, which enhances control over object creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Java481FlexibleConstructors extends BigInteger {
   Java481FlexibleConstructors(long value) throws Exception {
       if (value &amp;lt; 0) throw new Exception("Invalid value");
//that wasn’t possible before
       System.out.println("Initialized with value: " + value);
       super(String.valueOf(value));
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other notable features in Java 23
&lt;/h2&gt;

&lt;p&gt;In addition to the JEPs I've already covered, Java 23 introduces several other enhancements worth mentioning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance improvements (&lt;a href="https://openjdk.org/jeps/474" rel="noopener noreferrer"&gt;JEP 474: ZGC Generational Mode by Default&lt;/a&gt;): Java 23 optimizes the Z Garbage Collector by enabling its generational mode by default. This feature improves the efficiency of memory management, particularly for applications with long-running processes, by segregating young and old objects in the heap to enhance garbage collection performance​&lt;/li&gt;
&lt;li&gt;Security updates (&lt;a href="https://openjdk.org/jeps/471" rel="noopener noreferrer"&gt;JEP 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal&lt;/a&gt;): This update deprecates certain memory-access methods in &lt;strong&gt;sun.misc.Unsafe&lt;/strong&gt; that were widely used for direct memory manipulation, enhancing the security of the platform.&lt;/li&gt;
&lt;li&gt;Library enhancements (&lt;a href="https://openjdk.org/jeps/467" rel="noopener noreferrer"&gt;JEP 467: Markdown Documentation Comments&lt;/a&gt;): JEP 467 introduces support for Markdown in Javadoc comments. This feature allows developers to write better-formatted and more readable documentation using Markdown syntax within their code comments, improving both internal and external documentation practices​&lt;/li&gt;
&lt;li&gt;Module system improvements (&lt;a href="https://openjdk.org/jeps/476" rel="noopener noreferrer"&gt;JEP 476: Module Import Declarations&lt;/a&gt;): JEP 476 adds the ability to use import module declarations in Java source files. This simplifies module management, especially in multi-module projects, by allowing developers to import entire modules, not just individual classes or packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Java continues to evolve, and version 23 brings a wealth of improvements that will enhance the developer experience, from better handling of primitive types in pattern matching to more flexible constructors and advanced stream processing. Be sure to explore the changes and start incorporating them into your development workflow – as they will probably soon turn from preview features to core ones. &lt;/p&gt;

&lt;p&gt;If you’re interested in more Java-related content (including deep dives into versions 21 and 17), check some of the other publications on our blog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/java-21-features/" rel="noopener noreferrer"&gt;Java 21 features: A detailed look at the most important changes in the new LTS release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/java-17-features/" rel="noopener noreferrer"&gt;Java 17 features: A comparison between versions 8 and 17. What has changed over the years?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/jvm-kubernetes/" rel="noopener noreferrer"&gt;JVM Kubernetes: Optimizing Kubernetes for Java Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/github-copilot-tutorial/" rel="noopener noreferrer"&gt;GitHub Copilot tutorial: We’ve tested it with Java and here's how you can do it too&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/java-code-quality-tools/" rel="noopener noreferrer"&gt;How to code well? With good practices, a great team, and Java code quality tools&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>java23</category>
    </item>
    <item>
      <title>Java 21 features: A detailed look at the most important changes in the new LTS release</title>
      <dc:creator>Arkadiusz Rosloniec</dc:creator>
      <pubDate>Mon, 29 Jul 2024 11:22:51 +0000</pubDate>
      <link>https://dev.to/aroso1991/java-21-features-a-detailed-look-at-the-most-important-changes-in-the-new-lts-release-90o</link>
      <guid>https://dev.to/aroso1991/java-21-features-a-detailed-look-at-the-most-important-changes-in-the-new-lts-release-90o</guid>
      <description>&lt;p&gt;&lt;strong&gt;Another LTS Java release is already here, bringing some exciting changes and improvements. Let’s analyze the most important Java 21 features, check out how they work in practice, and try to predict their significance for the future of this technology.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since the Java platform adopted a six-month release cycle, we’ve moved past the perennial questions such as “Will Java die this year?” or “Is it worth migrating to the new version?”. Despite 28 years since its first release, Java continues to thrive and remains a popular choice as the primary programming language for many new projects.&lt;/p&gt;

&lt;p&gt;Java 17 was a significant milestone, but Java 21 has now taken 17’s place as the next long-term support release (LTS). It’s essential for Java developers to stay informed about the changes and new features this version brings. Inspired by my colleague Darek, who detailed Java 17 features in his article, I’ve decided to discuss JDK 21 in a similar fashion.&lt;/p&gt;

&lt;p&gt;JDK 21 comprises a total of 15 JEPs (JDK Enhancement Proposals). You can review the complete list on the official Java site. In this article, I’ll highlight several Java 21 JEPs that I believe are particularly noteworthy. Namely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/430" rel="noopener noreferrer"&gt;String Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/431" rel="noopener noreferrer"&gt;Sequenced Collections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openjdk.org/jeps/441" rel="noopener noreferrer"&gt;Pattern Matching for switch&lt;/a&gt; and &lt;a href="https://openjdk.org/jeps/440" rel="noopener noreferrer"&gt;Record Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;Virtual Threads&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without further delay, let’s delve into the code and explore these updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  String Templates (Preview)
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://openjdk.org/jeps/430" rel="noopener noreferrer"&gt;Spring Templates&lt;/a&gt; feature is still in preview mode. To use it, you have to add &lt;strong&gt;–enable-preview&lt;/strong&gt; flag to your compiler args. However, I’ve decided to mention it despite its preview status. Why? Because I get very irritated every time I have to write a log message or sql statement that contains many arguments or decipher which placeholder will be replaced with a given arg. And Spring Templates promise to help me (and you) with that.&lt;/p&gt;

&lt;p&gt;As JEP documentation says, the purpose of Spring Templates is to “simplify the writing of Java programs by making it easy to express strings that include values computed at run time”. &lt;/p&gt;

&lt;p&gt;Let’s check if it really is simpler.&lt;/p&gt;

&lt;p&gt;The “old way” would be to use the &lt;strong&gt;formatted()&lt;/strong&gt; method on a String object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var msg = "Log message param1: %s, pram2: %s".formatted(p1, p2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, with &lt;strong&gt;StringTemplate.Processor&lt;/strong&gt; (STR), it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var interpolated = STR."Log message param1: \{p1}, param2: \{p2}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a short text like the one above, the profit may not be that visible – but believe me, when it comes to big text blocks (jsons, sql statements), named parameters will help you a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequenced collections
&lt;/h2&gt;

&lt;p&gt;Java 21 introduced a new Java Collection Hierarchy. Look at the diagram below and compare it to what you probably have learned during your programming classes. You’ll notice that three new structures have been added (highlighted by the green color).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F135aes25de5za4vamlb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F135aes25de5za4vamlb9.png" alt="Image description" width="800" height="444"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://openjdk.org/jeps/431" rel="noopener noreferrer"&gt;JEP 431&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/431" rel="noopener noreferrer"&gt;Sequenced collections&lt;/a&gt; introduce a new built-in Java API, enhancing operations on ordered datasets. This API allows not only convenient access to the first and last elements of a collection but also enables efficient traversal, insertion at specific positions, and retrieval of sub-sequences. These enhancements make operations that depend on the order of elements simpler and more intuitive, improving both performance and code readability when working with lists and similar data structures.&lt;/p&gt;

&lt;p&gt;This is the full listing of the SequencedCollection interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface SequencedCollection&amp;lt;E&amp;gt; extends Collection&amp;lt;E&amp;gt; {
   SequencedCollection&amp;lt;E&amp;gt; reversed();
   default void addFirst(E e) {
       throw new UnsupportedOperationException();
   }
   default void addLast(E e) {
       throw new UnsupportedOperationException();
   }
   default E getFirst() {
       return this.iterator().next();
   }
   default E getLast() {
       return this.reversed().iterator().next();
   }
   default E removeFirst() {
       var it = this.iterator();
       E e = it.next();
       it.remove();
       return e;
   }
   default E removeLast() {
       var it = this.reversed().iterator();
       E e = it.next();
       it.remove();
       return e;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, now, instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var first = myList.stream().findFirst().get();
var anotherFirst = myList.get(0);
var last = myList.get(myList.size() - 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can just write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var first = sequencedCollection.getFirst();
var last = sequencedCollection.getLast();
var reversed = sequencedCollection.reversed();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small change, but IMHO it’s such a convenient and usable feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern Matching and Record Patterns
&lt;/h2&gt;

&lt;p&gt;Because of the similarity of &lt;a href="https://openjdk.org/jeps/441" rel="noopener noreferrer"&gt;Pattern Matching&lt;/a&gt; for &lt;em&gt;switch&lt;/em&gt; and &lt;a href="https://openjdk.org/jeps/440" rel="noopener noreferrer"&gt;Record Patterns&lt;/a&gt;, I will describe them together. Record patterns are a fresh feature – they have been introduced in Java 19 (as a preview). On the other hand, Pattern Matching for &lt;em&gt;switch&lt;/em&gt; is kinda a continuation of the &lt;a href="https://openjdk.org/jeps/394" rel="noopener noreferrer"&gt;extended instanceof&lt;/a&gt; expression. It brings in new possible syntax for switch statements which lets you express complex data-oriented queries more easily.&lt;/p&gt;

&lt;p&gt;Let’s forget about the basics of OOP for the sake of this example and deconstruct the employee object manually (&lt;em&gt;employee&lt;/em&gt; is a POJO class).&lt;/p&gt;

&lt;p&gt;Before Java 21, It looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (employee instanceof Manager e) {
   System.out.printf("I’m dealing with manager of %s department%n", e.department);
} else if (employee instanceof Engineer e) {
   System.out.printf("I’m dealing with %s engineer.%n", e.speciality);
} else {
   throw new IllegalStateException("Unexpected value: " + employee);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we could get rid of the ugly &lt;em&gt;instanceof&lt;/em&gt;? Well, now we can, thanks to the power of Pattern Matching from Java 21:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch (employee) {
   case Manager m -&amp;gt; printf("Manager of %s department%n", m.department);
   case Engineer e -&amp;gt; printf("I%s engineer.%n", e.speciality);
   default -&amp;gt; throw new IllegalStateException("Unexpected value: " + employee);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While talking about the switch statement, we can also discuss the Record Patterns feature. When dealing with a Java Record, it allows us to do much more than with a standard Java class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch (shape) { // shape is a record
   case Rectangle(int a, int b) -&amp;gt; System.out.printf("Area of rectangle [%d, %d] is: %d.%n", a, b, shape.calculateArea());
   case Square(int a) -&amp;gt; System.out.printf("Area of square [%d] is: %d.%n", a, shape.calculateArea());
   default -&amp;gt; throw new IllegalStateException("Unexpected value: " + shape);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the code shows, with that syntax, record fields are easily accessible. Moreover, we can put some additional logic to our case statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch (shape) {
   case Rectangle(int a, int b) when a &amp;lt; 0 || b &amp;lt; 0 -&amp;gt; System.out.printf("Incorrect values for rectangle [%d, %d].%n", a, b);
   case Square(int a) when a &amp;lt; 0 -&amp;gt; System.out.printf("Incorrect values for square [%d].%n", a);
   default -&amp;gt; System.out.println("Created shape is correct.%n");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use similar syntax for the &lt;em&gt;if&lt;/em&gt; statements. Also, in the example below, we can see that Record Patterns also work for nested records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (r instanceof Rectangle(ColoredPoint(Point p, Color c),
                          ColoredPoint lr)) {
   //sth
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Virtual Threads
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;Virtual Threads&lt;/a&gt; feature is probably the hottest one among all Java 21 – or at least one the Java developers have waited the most for. As JEP documentation (linked in the previous sentence) says, one of the goals of the virtual threads was to “enable server applications written in the simple thread-per-request style to scale with near-optimal hardware utilization”. However, does this mean we should migrate our entire code that uses &lt;strong&gt;java.lang.Thread&lt;/strong&gt;? &lt;/p&gt;

&lt;p&gt;First, let’s examine the problem with the approach that existed before Java 21 (in fact, pretty much since Java’s first release). We can approximate that one &lt;strong&gt;java.lang.Thread&lt;/strong&gt; consumes (depending on OS and configuration) about 2 to 8 MB of memory. However, the important thing here is that one Java Thread is mapped 1:1 to a kernel thread. For simple web apps which use a “one thread per request” approach, we can easily calculate that either our machine will be “killed” when traffic increases (it won’t be able to handle the load) or we’ll be forced to purchase a device with more RAM, and our AWS bills will increase as a result.&lt;/p&gt;

&lt;p&gt;Of course, virtual threads are not the only way to handle this problem. We have asynchronous programming (frameworks like WebFlux or native Java API like CompletableFuture). However, for some reason – maybe because of the “unfriendly API” or high entry threshold – these solutions aren’t that popular.&lt;/p&gt;

&lt;p&gt;Virtual Threads aren’t overseen or scheduled by the operating system. Rather, their scheduling is handled by the JVM. While real tasks must be executed in a platform thread, the JVM employs so-called carrier threads — essentially platform threads — to “carry” any virtual thread when it is due for execution. Virtual Threads are designed to be lightweight and use much less memory than standard platform threads. &lt;/p&gt;

&lt;p&gt;The diagram below shows how Virtual Threads are connected to platform and OS threads:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszrgtxh98n74m88vzj9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszrgtxh98n74m88vzj9v.png" alt="Image description" width="626" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, to see how Virtual Threads are used by Platform Threads, let’s run code that starts (1 + number of CPUs the machine has, in my case 8 cores) virtual threads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var numberOfCores = 8; //
final ThreadFactory factory = Thread.ofVirtual().name("vt-", 0).factory();
try (var executor = Executors.newThreadPerTaskExecutor(factory)) {
   IntStream.range(0, numberOfCores + 1)
           .forEach(i -&amp;gt; executor.submit(() -&amp;gt; {
               var thread = Thread.currentThread();
               System.out.println(STR."[\{thread}]  VT number: \{i}");
               try {
                   sleep(Duration.ofSeconds(1L));
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[VirtualThread[#29,vt-6]/runnable@ForkJoinPool-1-worker-7]  VT number: 6
[VirtualThread[#26,vt-4]/runnable@ForkJoinPool-1-worker-5]  VT number: 4
[VirtualThread[#30,vt-7]/runnable@ForkJoinPool-1-worker-8]  VT number: 7
[VirtualThread[#24,vt-2]/runnable@ForkJoinPool-1-worker-3]  VT number: 2
[VirtualThread[#23,vt-1]/runnable@ForkJoinPool-1-worker-2]  VT number: 1
[VirtualThread[#27,vt-5]/runnable@ForkJoinPool-1-worker-6]  VT number: 5
[VirtualThread[#31,vt-8]/runnable@ForkJoinPool-1-worker-6]  VT number: 8
[VirtualThread[#25,vt-3]/runnable@ForkJoinPool-1-worker-4]  VT number: 3
[VirtualThread[#21,vt-0]/runnable@ForkJoinPool-1-worker-1]  VT number: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, &lt;strong&gt;ForkJonPool-1-worker-X&lt;/strong&gt; Platform Threads are our carrier threads that manage our virtual threads. We observe that Virtual Threads number 5 and 8 are using the same carrier thread number 6.&lt;/p&gt;

&lt;p&gt;The last thing about Virtual Threads I want to show you is how they can help you with the blocking I/O operations.&lt;/p&gt;

&lt;p&gt;Whenever a Virtual Thread encounters a blocking operation, such as I/O tasks, the JVM efficiently detaches it from the underlying physical thread (the carrier thread). This detachment is critical because it frees up the carrier thread to run other Virtual Threads instead of being idle, waiting for the blocking operation to complete. As a result, a single carrier thread can multiplex many Virtual Threads, which could number in the thousands or even millions, depending on the available memory and the nature of tasks performed. &lt;/p&gt;

&lt;p&gt;Let’s try to simulate this behavior. To do this, we will force our code to use only one CPU core, with only 2 virtual threads – for better clarity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.setProperty("jdk.virtualThreadScheduler.parallelism", "1");
System.setProperty("jdk.virtualThreadScheduler.maxPoolSize", "1");
System.setProperty("jdk.virtualThreadScheduler.minRunnable", "1");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thread 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thread v1 = Thread.ofVirtual().name("long-running-thread").start(
       () -&amp;gt; {
           var thread = Thread.currentThread();
           while (true) {
               try {
                   Thread.sleep(250L);
                   System.out.println(STR."[\{thread}] - Handling http request ....");
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
       }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thread 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thread v2 = Thread.ofVirtual().name("entertainment-thread").start(
       () -&amp;gt; {
           try {
               Thread.sleep(1000L);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           var thread = Thread.currentThread();
           System.out.println(STR."[\{thread}] - Executing when 'http-thread' hit 'sleep' function");
       }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v1.join();
v2.join();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#23,entertainment-thread]/runnable@ForkJoinPool-1-worker-1] - Executing when 'http-thread' hit 'sleep' function
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
[VirtualThread[#21,long-running-thread]/runnable@ForkJoinPool-1-worker-1] - Handling http request ....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We observe that both Virtual Threads (&lt;strong&gt;long-running-thread&lt;/strong&gt; and &lt;strong&gt;entertainment-thread&lt;/strong&gt;) are being carried by only one Platform Thread which is &lt;strong&gt;ForkJoinPool-1-worker-1&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To summarize, this model enables Java applications to achieve high levels of concurrency and scalability with much lower overhead than traditional thread models, where each thread maps directly to a single operating system thread. It’s worth noting that virtual threads are a vast topic, and what I’ve described is only a small fraction. I strongly encourage you to learn more about the scheduling, pinned threads and the internals of VirtualThreads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary: The future of the Java programming language
&lt;/h2&gt;

&lt;p&gt;The features described above are the ones I consider to be the most important in Java 21. Most of them aren’t as groundbreaking as some of the things introduced in JDK 17, but they’re still very useful, and nice to have QOL (Quality of Life) changes. &lt;/p&gt;

&lt;p&gt;However, you shouldn’t discount other JDK 21 improvements either – I highly encourage you to analyze the &lt;a href="https://openjdk.org/projects/jdk/21/" rel="noopener noreferrer"&gt;complete list&lt;/a&gt; and explore all the features further. For example, one thing I consider particularly noteworthy is the Vector API, which allows vector computations on some supported CPU architectures – not possible before. Currently, it’s still in the incubator status/experimental phase (which is why I didn’t highlight it in more detail here), but it holds great promise for the future of Java. &lt;/p&gt;

&lt;p&gt;Overall, the advancement Java made in various areas signals the team’s ongoing commitment to improving efficiency and performance in high-demand applications.&lt;/p&gt;

&lt;p&gt;If you’re interested in Java, be sure to check out some of our other articles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/java-17-features/" rel="noopener noreferrer"&gt;Java 17 features: A comparison between versions 8 and 17. What has changed over the years?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/jvm-kubernetes/" rel="noopener noreferrer"&gt;JVM Kubernetes: Optimizing Kubernetes for Java Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/project-valhalla-java/" rel="noopener noreferrer"&gt;Project Valhalla – Java on the path to better performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pretius.com/blog/advanced-java-interview-questions/" rel="noopener noreferrer"&gt;Advanced Java interview questions: A guide for 2023&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Java features FAQ
&lt;/h2&gt;

&lt;p&gt;Here are answers to some common questions regarding JDK 21, as well as Java native interface and features. &lt;/p&gt;

&lt;h3&gt;
  
  
  What is Java SE?
&lt;/h3&gt;

&lt;p&gt;Java SE (Java Platform, Standard Edition) is a fundamental platform for developing and deploying Java applications on desktops and servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Foreign Function and Memory API?
&lt;/h3&gt;

&lt;p&gt;It’s a preview feature that lets Java programs interoperate with data and code outside the Java runtime. The API enables Java programs to call native libraries and process native data more safely than in the case of JNI. The API is a tool for safely accessing foreign memory and code, and efficiently invoking foreign functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to write Java code well?
&lt;/h3&gt;

&lt;p&gt;One of the key aspects is code review (you can use &lt;a href="https://pretius.com/blog/open-ai-code-review/" rel="noopener noreferrer"&gt;AI code review tools&lt;/a&gt; to make this process a bit less time-consuming).&lt;/p&gt;

&lt;h3&gt;
  
  
  What is dynamic loading in Java?
&lt;/h3&gt;

&lt;p&gt;Dynamic loading in Java refers to loading classes or resources at runtime, rather than during the initial program startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is structured concurrency?
&lt;/h3&gt;

&lt;p&gt;Structured concurrency in Java is an approach that organizes concurrent processes in a controlled manner, aiming to enhance the maintainability, reliability, and observability of multithreaded code.&lt;/p&gt;

</description>
      <category>java</category>
      <category>softwaredevelopment</category>
      <category>lts</category>
    </item>
  </channel>
</rss>
