<?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>Forem: Linh Nguyen</title>
    <description>The latest articles on Forem by Linh Nguyen (@vulinh64).</description>
    <link>https://forem.com/vulinh64</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%2F3598325%2Fe81f3ed0-3593-4d75-8a6d-38b2baa8f663.png</url>
      <title>Forem: Linh Nguyen</title>
      <link>https://forem.com/vulinh64</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vulinh64"/>
    <language>en</language>
    <item>
      <title>#Rant: Java Is Not Dead, It Is Not Cool, It Is Lukewarm, But It Is Far From Dead!</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Wed, 04 Feb 2026 04:09:18 +0000</pubDate>
      <link>https://forem.com/vulinh64/rant-java-is-not-dead-it-is-not-cool-it-is-lukewarm-but-it-is-far-from-dead-4oga</link>
      <guid>https://forem.com/vulinh64/rant-java-is-not-dead-it-is-not-cool-it-is-lukewarm-but-it-is-far-from-dead-4oga</guid>
      <description>&lt;p&gt;The original article is located &lt;a href="https://vulinhjava.io.vn/blog/java-is-not-dead" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, Java is dead. Again. For the unknown time this year, apparently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Truth
&lt;/h2&gt;

&lt;p&gt;It is now the early part of 2026, and yet, Java is still among the most popular programming languages, and especially dominates in the enterprise zone. Like a cockroach surviving a nuclear winter, Java just keeps chugging along, powering banks, e-commerce giants, and probably the app that processes your coffee order.&lt;/p&gt;

&lt;p&gt;You ask why, and I shall give you answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lukewarm Reality
&lt;/h2&gt;

&lt;p&gt;Java has existed for over 30 years now. Not too old compared to COBOL, but not too young to look shiny and cool like the new kids Go, Dart, etc...&lt;/p&gt;

&lt;p&gt;Also:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Python is a few years older than Java (created in 1991, compared to Java being created in 1995). But because Python is more &lt;del&gt;handsome&lt;/del&gt; concise, people think Java is the older one. It's like how everyone assumes the quiet kid in class is older because they seem so serious, while the loud, energetic one must be younger.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Being old means being widely adapted. And that means enterprises didn't want breaking changes. When you have a system processing millions of transactions per day, "move fast and break things" suddenly sounds like a lawsuit waiting to happen.&lt;/p&gt;

&lt;p&gt;Sure, JVM costs some memory, and sure, startup time can be better, and its cloud service bills can scare you. But it is hardened, battle proven, constantly optimized, intelligent enough to make your app stable, fast and durable, and its tools are mature.&lt;/p&gt;

&lt;p&gt;There is little reason to tell a bank to just dump Java to use Go or .NET or Python. No real benefits, actually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remember When They Said...
&lt;/h2&gt;

&lt;p&gt;They once said: Applet is dead (it will &lt;a href="https://openjdk.org/jeps/504" rel="noopener noreferrer"&gt;get axed in JDK 26&lt;/a&gt;, scheduled to be released in March 2026), Flash is the future (spoiler alert: Flash got axed too). Turns out the web moved on, but Java didn't need applets to survive.&lt;/p&gt;

&lt;p&gt;They said: Swing is ugly (yes, it abstracts over the UX provided by the host OS). And therefore, we now have React Native polluting everything (looking at you, Windows 11!), its RAM usage comparable to a single JVM instance. The irony is delicious.&lt;/p&gt;

&lt;p&gt;And JavaFX? We don't talk about JavaFX.&lt;/p&gt;

&lt;h2&gt;
  
  
  But Wait, There's More
&lt;/h2&gt;

&lt;p&gt;But did Java just exist in already existing systems, tied to its legacy reputation?&lt;/p&gt;

&lt;p&gt;Hmm, not quite.&lt;/p&gt;

&lt;p&gt;Just because some ugly, bloated code was written by devs who got pressured by deadlines doesn't mean the language itself is bad. Ugly Python is still... ugly, if not a bit more due to indentation madness. Bad code is bad code, regardless of the language choices.&lt;/p&gt;

&lt;p&gt;Starting from JDK 9 in 2017, Java entered the 6-months release cycle, bringing faster testing, faster feedback, and more transparent communication between users and the JDK team.&lt;/p&gt;

&lt;p&gt;A lot of projects like &lt;a href="https://openjdk.org/projects/amber/" rel="noopener noreferrer"&gt;Amber&lt;/a&gt; (enhance quality of life when writing code), &lt;a href="https://openjdk.org/projects/valhalla/" rel="noopener noreferrer"&gt;Valhalla&lt;/a&gt; (code like a class, work like an &lt;code&gt;int&lt;/code&gt;), and Loom (&lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;Virtual Threads&lt;/a&gt;) are actively making Java attractive. These aren't just cosmetic changes; they're fundamental improvements that make Java feel modern again.&lt;/p&gt;

&lt;p&gt;From JDK 8 (itself was a big change in 2014) to JDK 21, a lot has changed. The development experience has increased significantly. Records, sealed classes, pattern matching, text blocks... these features make Java feel fresh. Unless, of course, you brought the mindset of Java 8 to work with a project that uses Java 21.&lt;/p&gt;

&lt;p&gt;So, for newer projects, Java is still a solid choice to start anew. There are still plenty of jobs available for Java developers all around the world.&lt;/p&gt;

&lt;p&gt;Admit it, your eyes shine when you hear you can code in JDK 17 and Spring Boot 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real World Examples
&lt;/h2&gt;

&lt;p&gt;Active cases like Netflix building and embracing its entire ecosystem in Java, or Amazon heavily using Java for AWS are examples of how Java is still very hot and sexy. These aren't legacy systems limping along; these are cutting edge platforms choosing Java:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Netflix &lt;a href="https://blog.bytebytego.com/p/how-netflix-runs-on-java" rel="noopener noreferrer"&gt;recently migrated&lt;/a&gt; thousands of services from JDK 8 to JDK 17+, achieving &lt;a href="https://blog.bytebytego.com/p/evolution-of-java-usage-at-netflix" rel="noopener noreferrer"&gt;20% less CPU time on garbage collection&lt;/a&gt;. They're using modern features like &lt;a href="https://www.infoq.com/presentations/netflix-java/" rel="noopener noreferrer"&gt;generational ZGC for near-zero pause times&lt;/a&gt; and Spring Boot with GraphQL Federation through their open-source DGS framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS added &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/11/aws-lambda-java-25/" rel="noopener noreferrer"&gt;Java 25 support to Lambda&lt;/a&gt; in late 2025, and &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/02/amazon-q-developer-upgrade-java-21/" rel="noopener noreferrer"&gt;Amazon Q Developer now assists with upgrades to Java 21&lt;/a&gt;. Major cloud providers actively invest in Java tooling because their customers demand it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oh, Google uses Kotlin for Android apps, but nothing prevents you from using Java to write one. The compatibility is there, the tooling is there, the choice is yours. Though fair disclosure: over 90% of Android developers now prefer Kotlin for new development, but Java remains fully supported and essential for maintaining existing codebases.&lt;/p&gt;

&lt;p&gt;Beyond traditional enterprise, Java powers the entire big data ecosystem. Apache Hadoop and Apache Spark are Java-based, processing petabytes of data daily. The &lt;a href="https://www.researchandmarkets.com/reports/5767365/hadoop-market-report" rel="noopener noreferrer"&gt;Hadoop market alone is projected to hit $196.53 billion in 2025&lt;/a&gt;. Java's reliability and performance make it increasingly popular for AI and machine learning platforms too. And let's not forget that tools like Elasticsearch, Cassandra and Kafka are written in Java, too!&lt;/p&gt;

&lt;p&gt;Visiting &lt;a href="https://openjdk.org/jeps/0" rel="noopener noreferrer"&gt;JEP 0 Page&lt;/a&gt; and you will see a lot of Enhancement Proposals being made to make Java even better. The language is evolving, adapting, improving.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers Don't Lie
&lt;/h2&gt;

&lt;p&gt;Over 90% of Fortune 500 companies use Java. The language &lt;a href="https://www.tiobe.com/tiobe-index/" rel="noopener noreferrer"&gt;ranks #3-4 globally in popularity indices&lt;/a&gt;. An estimated 18.7 million Java developer jobs are projected between 2024-2026, with median salaries of $116,000 in the US, up 11% over five years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Java
&lt;/h2&gt;

&lt;p&gt;Java isn't a cool kid in the traditional sense, but it is a mature and responsible person who has seen enough of life and gained better appreciation for it. It's the friend who shows up on time, helps you move apartments, and actually remembers your birthday.&lt;/p&gt;

&lt;p&gt;So, Java still being relevant is due to two main reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enterprise inertia;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Its new, shiny toys that are still very attractive to newer projects, as well as various improvements to the ecosystem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;p&gt;Is Java dead? Not quite.&lt;/p&gt;

&lt;p&gt;Is Java cool? Probably not. Java is verbose. But the recent additions to the language will make coding in Java "sexier". Just don't use JDK 8 as a baseline; the new one is now JDK 17!&lt;/p&gt;

&lt;p&gt;But... There is always a catch&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If some recruiters tell you to work with a project using JDK 8 and Spring Boot 2, chances are high that it is a red flag job. Java got its bad reputation mostly from bloated, unstable and brittle old legacy codes (again, not Java's fault, but whoever was in charged of said codes), and chances are that you don't want to get stuck in such a project. JDK 17 is the new norm now. We don't live in the pre-Covid era anymore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  But What About...
&lt;/h2&gt;

&lt;p&gt;Python is cooler? Cool, but try making sense of GIL (recently became optional in the 3.14 version) or indentation, and unexpected runtime errors that only show up in production.&lt;/p&gt;

&lt;p&gt;JavaScript is better? Why did they have to invent TypeScript then?&lt;/p&gt;

&lt;p&gt;Kotlin replacing Java? Maybe, but not in a foreseeable future. Groovy and Scala tried to, and look where they are now (if TIOBE is reliable, then Scala is at #33 and Groovy is not even among the top 50).&lt;/p&gt;

&lt;p&gt;Is Java fast? Its memory usage and startup time can be improved, but once everything is set, its speed, with a warm enough JVM, can be very close to native C/C++.&lt;/p&gt;

&lt;p&gt;No language is perfect. Understanding advantages and tradeoffs, and you will see why people still choose Java in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;So yeah, Java is "dead" again. See you next week when someone writes another blog post declaring its demise for the n+1 time.&lt;/p&gt;

&lt;p&gt;Java isn't going anywhere. Deal with it.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Tue, 18 Nov 2025 06:29:50 +0000</pubDate>
      <link>https://forem.com/vulinh64/-49jf</link>
      <guid>https://forem.com/vulinh64/-49jf</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/vulinh64" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F3598325%2Fe81f3ed0-3593-4d75-8a6d-38b2baa8f663.png" alt="vulinh64"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/vulinh64/remember-to-make-use-of-lazy-evaluation-4h2c" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Remember to Make Use Of Lazy Evaluation&lt;/h2&gt;
      &lt;h3&gt;Linh Nguyen ・ Nov 18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>java</category>
    </item>
    <item>
      <title>Remember to Make Use Of Lazy Evaluation</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Tue, 18 Nov 2025 03:50:32 +0000</pubDate>
      <link>https://forem.com/vulinh64/remember-to-make-use-of-lazy-evaluation-4h2c</link>
      <guid>https://forem.com/vulinh64/remember-to-make-use-of-lazy-evaluation-4h2c</guid>
      <description>&lt;p&gt;Sometimes, being lazy is good. But that's no excuse for being lazy in work! It is only a valid excuse in programming if you apply at the right time and right place. The original article is &lt;a href="https://vulinhjava.io.vn/blog/java-coding-tips-and-tricks/#remember-the-lazy-evaluation-too" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Simple Example of Null-Coalescing
&lt;/h2&gt;

&lt;p&gt;Let's take this simple null-coalescing example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; 
    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;getDefaultObject&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; 
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple but elegant solution when you want to assign a default value to a variable if the object is &lt;code&gt;null&lt;/code&gt;. Classic Java 101!&lt;/p&gt;

&lt;p&gt;Then, you get fancy and create a helper method to adhere to the DRY principle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sweet, sweet juicy usage of generics&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt;
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, FYI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DRY principle stands for Don't Repeat Yourself (ironically, I just repeated that)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then, riding high on your DRY-fueled motivation, you refactor your entire code base like a caffeinated code warrior. You feel invincible. You feel productive. You feel... oh so proud of yourself.&lt;/p&gt;

&lt;p&gt;Hold your horses, cowboy!&lt;/p&gt;

&lt;h2&gt;
  
  
  When Reality Hits (Hard)
&lt;/h2&gt;

&lt;p&gt;Before your brain drowns in dopamine, and you start updating your LinkedIn with "&lt;em&gt;Refactoring Ninja&lt;/em&gt;" as a skill, let me burst your bubble with a question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think will happen in this code snippet?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expensiveComputation&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plot twist: The &lt;code&gt;expensiveComputation()&lt;/code&gt; will &lt;em&gt;ALWAYS&lt;/em&gt; execute, regardless of whether our lovely &lt;code&gt;object&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; or not. Surprise! Java won't help you optimize the hell out of this, so you are on your own!&lt;/p&gt;

&lt;p&gt;The consequences?&lt;/p&gt;

&lt;p&gt;Could range from wasting precious CPU cycles (your laptop fan is already judging you) to the dreaded "&lt;em&gt;oh no, I've accidentally launched the nuclear missiles twice&lt;/em&gt;" scenario. That's programmer speak for "your non-idempotent operations fired twice and caused chaos that should've only happened once, but here we are, with two charges on the customer's credit card and an angry email in your inbox." &lt;/p&gt;

&lt;p&gt;Catastrophic indeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is There a Fix?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: Yes, but you will need JDK 8+. Otherwise, you will need some ugly modification or even give up and switch to JavaScript or Python.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use &lt;strong&gt;lazy evaluation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Or in layman's terms, use &lt;code&gt;Supplier&amp;lt;T&amp;gt;&lt;/code&gt;. Think of it as saying "I'll tell you the answer... but only when you actually need it."&lt;/p&gt;

&lt;p&gt;Specifically, don't delete your current helper method yet (we're collectors, not destroyers). We'll add an overloaded one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Are you ready to get your OCP certificate?&lt;/span&gt;
&lt;span class="c1"&gt;// This is the bliss of Generics Usage&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;defaultValueSupplier&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;defaultValueSupplier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, modify the expensive method call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getOrDefault&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;expensiveComputation&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now rest easy knowing that &lt;code&gt;expensiveComputation()&lt;/code&gt; will only be called if your shiny &lt;code&gt;object&lt;/code&gt; is null. Otherwise? It stays asleep. &lt;strong&gt;Lazy&lt;/strong&gt;. Unbothered. Living its best life.&lt;/p&gt;

&lt;p&gt;And to think that the humble ternary operator from our first example could masterfully handle both eager and lazy evaluation without the hassle of having two methods. Truly a &lt;em&gt;How do you do, fellow kids&lt;/em&gt; moment for the ages.&lt;/p&gt;

&lt;h2&gt;
  
  
  No, No, No, Don't Press the Delete Button!
&lt;/h2&gt;

&lt;p&gt;But wait, don't delete the original helper method! It's still useful. Let's talk about when to use which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The eager evaluation version is perfect for already computed values (simple getters, defined constants, that sort of thing). It's like having fast food: already prepared, ready to go, no waiting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The lazy evaluation one is suitable when the default value requires invoking some rather expensive computations. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the other hand: using lazy evaluation on already computed values is wasteful. You're creating a &lt;code&gt;Supplier&amp;lt;T&amp;gt;&lt;/code&gt; wrapper just to contain a value that's already sitting right there. It's like gift-wrapping a gift that's already unwrapped. Inefficient and slightly ridiculous.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose your approach carefully! Know what you need to do, and know which method to use (both versions are lovingly supported by Apache Commons Lang 3 libraries, bless their hearts). Our null-coalescing task is just a simple one, but the same principle can also be applied to other stuff, for example: hit the database only if the cache does not contain our desired value.&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>Java's Funny Little Heresies</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Fri, 14 Nov 2025 04:53:10 +0000</pubDate>
      <link>https://forem.com/vulinh64/javas-funny-little-heresies-2cng</link>
      <guid>https://forem.com/vulinh64/javas-funny-little-heresies-2cng</guid>
      <description>&lt;p&gt;Okay, calling them heresies may be a bit overexaggerating. Calling them quirks or gotcha would be more appropriate. So let's dig into some of the Java's most unexpected gotcha.&lt;/p&gt;

&lt;h2&gt;
  
  
  When 1000 Is NOT Equal to 1000
&lt;/h2&gt;

&lt;p&gt;You saw this kind of post all over LinkedIn, by people who copy/paste and then post to their profile. No charges here, just a funny poking.&lt;/p&gt;

&lt;p&gt;TL;DR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Yes, you don't use this method&lt;/span&gt;
&lt;span class="c1"&gt;// But this is to prove the point&lt;/span&gt;
&lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// a == b will return false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ah, yes, the classic equality by identity versus equality by value. Never ever compare two objects using &lt;code&gt;==&lt;/code&gt; if your intention was to compare their values (the exception being &lt;code&gt;enum&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But this will return true:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;Integer&lt;/code&gt;, value from -128 to 127 (by default) are cached, so you have this funny &lt;del&gt;heresy&lt;/del&gt; gotcha.&lt;/p&gt;

&lt;p&gt;And then again, why would you use &lt;code&gt;Integer&lt;/code&gt; instead of &lt;code&gt;int&lt;/code&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Type Erasure
&lt;/h2&gt;

&lt;p&gt;The code below will NOT compile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Utils&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will get a nasty warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'doSomething(List&amp;lt;String&amp;gt;)' clashes with 'doSomething(List&amp;lt;Integer&amp;gt;)'; both methods have same erasure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not your fault, that is how Java becomes too committed to preserve backward compatibility. At runtime, the types are erased, leading to two methods with identical signature &lt;code&gt;doSomething(List)&lt;/code&gt;, and by the ultimate rule of overloading, this is not acceptable.&lt;/p&gt;

&lt;p&gt;Can this ever be fixed? Who knows? Will Valhalla fix this? Probably? Do people use Java version 4 or less? They are now old boomers now.&lt;/p&gt;

&lt;p&gt;The original intention of Generics was mainly to turn the nasty &lt;code&gt;ClassCastException&lt;/code&gt; hiccups during runtime to errors that can be caught by compiler, so yeah, get used to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsigned When?
&lt;/h2&gt;

&lt;p&gt;Why didn't Java have unsigned data types? Is there any reason why this was not a thing in Java? Can I have an &lt;code&gt;int&lt;/code&gt; value of 4 billion without needing the 8 bytes of &lt;code&gt;long&lt;/code&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  String's Questionable Immutability
&lt;/h2&gt;

&lt;p&gt;Read my post &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Collection Shenanigans
&lt;/h2&gt;

&lt;p&gt;Look at this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Result: [2, 3, 4, 5] - removes the VALUE 1&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;         &lt;span class="c1"&gt;// Result: [1, 3, 4, 5] - removes the element at INDEX 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, the culprit is due to method overloading. See here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// From Collection interface&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// From List interface  &lt;/span&gt;
&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the rule of method overloading, primitive types trump over Object ones, so for the &lt;code&gt;List&lt;/code&gt; instance, the overloading version of &lt;code&gt;remove(int)&lt;/code&gt; is used, leading to this weird case.&lt;/p&gt;

&lt;p&gt;The fix? Use one of those:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Remove the first occurrence of element `1`&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Yes, why would you?&lt;/span&gt;

&lt;span class="c1"&gt;// Remove all element `1` in this list&lt;/span&gt;
&lt;span class="c1"&gt;// This is for JDK 8+ only&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeIf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still, Java please, can we not have a &lt;code&gt;removeAt(int index)&lt;/code&gt; method, belongs to &lt;code&gt;List&lt;/code&gt; interface?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hostility Between Primitive Types Versus Generics
&lt;/h2&gt;

&lt;p&gt;Have a look&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think the data type of &lt;code&gt;list&lt;/code&gt; would be?&lt;/p&gt;

&lt;p&gt;Is it &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Nope. It is &lt;code&gt;List&amp;lt;int[]&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ah yes, how dare the primitive types throw a hissing fit here. How dare they!&lt;/p&gt;

&lt;p&gt;So we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An &lt;code&gt;int[]&lt;/code&gt; is an &lt;code&gt;Object&lt;/code&gt;, but &lt;code&gt;int[]&lt;/code&gt; is NOT &lt;code&gt;Integer[]&lt;/code&gt;, sorry, no autoboxing here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the same vein, an &lt;code&gt;Integer[]&lt;/code&gt; is indeed an &lt;code&gt;Object[]&lt;/code&gt;, which in turn, an &lt;code&gt;Object&lt;/code&gt; 🤡 Yes, what do you even expect?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yes, this is also a thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomethingObj&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Do something&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomethingInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Do something&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;doSomethingObj&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Not complile&lt;/span&gt;
&lt;span class="n"&gt;doSomethingInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Also not compile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't have everything, I guess. Primitive types have harbored an intense hatred to everything object it seems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Profileration of &lt;code&gt;UnsupportedOperationException&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;That nasty exception is everywhere in Collections API. Yes, it is there to ensure the immutability of the collections. And also yes, it meant stepping out from comfort zone of &lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;HashSet&lt;/code&gt; and &lt;code&gt;HashMap&lt;/code&gt; means walking into an uncharted territory, where every step is a potential trigger to detonate the land mines (except the mines here are the presence of said exception).&lt;/p&gt;

&lt;p&gt;The convenience of &lt;code&gt;List.of&lt;/code&gt;, &lt;code&gt;Set.of&lt;/code&gt; and &lt;code&gt;Map.of&lt;/code&gt;? Those things throw &lt;code&gt;UnsupportedOperationException&lt;/code&gt; when you try to mutate them. Again, why would you, but there are cases when you genuinely need to mutate your collections.&lt;/p&gt;

&lt;p&gt;Do your collections accept &lt;code&gt;null&lt;/code&gt;? Some do, others would ruin your day, for example, thread-safe collection like &lt;code&gt;ConcurrentHashMap&lt;/code&gt;, or some specialized collections like &lt;code&gt;TreeSet&lt;/code&gt; do not tolerate &lt;code&gt;null&lt;/code&gt;. Again, working with &lt;code&gt;null&lt;/code&gt; is generally frowned upon, but again, there will always be &lt;code&gt;null&lt;/code&gt; in data, just like there will always be shadow accompanying someone under a sunny day.&lt;/p&gt;

&lt;p&gt;Test your code carefully!&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaking of &lt;code&gt;UnsupportedOperationException&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Take a look at this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Nope, UnsupportedOperationException&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Also nope, UnsupportedOperationException&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This is okay&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we have some sort of half-hearted immutable collection. Technically, &lt;code&gt;Arrays.asList&lt;/code&gt; creates a &lt;strong&gt;view&lt;/strong&gt; over a backing array. The original array cannot shrink or expand, so add and remove are not supported. However, modification is accepted.&lt;/p&gt;

&lt;p&gt;But then, you run this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Welcome to JDK 25, folks!&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Prints -1, 2, 3, 4, 5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The change you made to the &lt;code&gt;list&lt;/code&gt; now reflects back to the backing &lt;code&gt;array&lt;/code&gt;. The nature of a view, isn't it?&lt;/p&gt;

&lt;p&gt;To truly ensure the complete immutability, use &lt;code&gt;List.of&lt;/code&gt; in JDK 9+, or &lt;code&gt;Collections.unmodifiableList&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Let me know if you have any other gotcha you wish to share, or an experience when you are the victim of above heresies 😂&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>Is String truly immutable? Believe me, I am not engaging in clickbait.</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Fri, 14 Nov 2025 02:23:06 +0000</pubDate>
      <link>https://forem.com/vulinh64/is-string-truly-immutable-believe-me-i-am-not-engaging-in-clickbait-2ge2</link>
      <guid>https://forem.com/vulinh64/is-string-truly-immutable-believe-me-i-am-not-engaging-in-clickbait-2ge2</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00" class="crayons-story__hidden-navigation-link"&gt;Is String Truly Immutable?&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/vulinh64" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F3598325%2Fe81f3ed0-3593-4d75-8a6d-38b2baa8f663.png" alt="vulinh64 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/vulinh64" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Linh Nguyen
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Linh Nguyen
                
              
              &lt;div id="story-author-preview-content-3018954" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/vulinh64" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F3598325%2Fe81f3ed0-3593-4d75-8a6d-38b2baa8f663.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Linh Nguyen&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 13 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00" id="article-link-3018954"&gt;
          Is String Truly Immutable?
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/vulinh64/is-string-truly-immutable-g00#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>java</category>
    </item>
    <item>
      <title>Is String Truly Immutable?</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Thu, 13 Nov 2025 07:27:23 +0000</pubDate>
      <link>https://forem.com/vulinh64/is-string-truly-immutable-g00</link>
      <guid>https://forem.com/vulinh64/is-string-truly-immutable-g00</guid>
      <description>&lt;p&gt;Okay, the title might or might not be clickbait. The original article is &lt;a href="https://vulinhjava.io.vn/blog/string-immutability-truth/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, you can check it for yourself.&lt;/p&gt;

&lt;p&gt;Or if you don't want to, you can view this short by Jose Paumard:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/AcpU5cL2s0s"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Here is your poison:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;String is &lt;em&gt;technically&lt;/em&gt; mutable, but &lt;em&gt;effectively&lt;/em&gt; immutable&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Long Answer (Sorry Jose, Let Me Steal Your Catchphrase)
&lt;/h2&gt;

&lt;p&gt;Examining the &lt;code&gt;String&lt;/code&gt; class, we will immediately see these fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Actual holder of String value&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;coder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// either LATIN (0) or UTF16 (1)&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;hashIsZero&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you still use JDK 8 and below (why would you?), you will see this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see something?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mutability Gotcha
&lt;/h2&gt;

&lt;p&gt;Yes, you saw that right, there are rebellious non-immutable fields in the &lt;code&gt;String&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;And by most definitions of an immutable class (being a &lt;code&gt;final&lt;/code&gt; class and all of its fields must be &lt;code&gt;final&lt;/code&gt;), this makes &lt;code&gt;String&lt;/code&gt; not qualified to be one. The most technical representations of an immutable class in Java include &lt;code&gt;Optional&lt;/code&gt;, &lt;code&gt;LocalDate&lt;/code&gt;, &lt;code&gt;UUID&lt;/code&gt;, and all Java Records.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The finality here is &lt;em&gt;shallow&lt;/em&gt;, not &lt;em&gt;deep&lt;/em&gt;, but we don't talk about that here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another problem here is the backing array. Sure, it is &lt;code&gt;final&lt;/code&gt;, but you know that even though the &lt;em&gt;reference&lt;/em&gt; to said array is &lt;code&gt;final&lt;/code&gt;, nothing really prevents the elements in said array from being changed. You know, the simple assignment?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'H'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'e'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'l'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'l'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'o'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Nothing prevents you from doing this&lt;/span&gt;
&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'h'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's why the method &lt;code&gt;.toCharArray()&lt;/code&gt; needs a defensive copy instead of returning the array that backs the string directly.&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://openjdk.org/jeps/8261007" rel="noopener noreferrer"&gt;JEP Proposal&lt;/a&gt; to make truly frozen arrays, but it is still in draft stage, and there are no words about its prospect of ever making it into production JDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  No Valhalla for You!
&lt;/h2&gt;

&lt;p&gt;For this reason, as explained by Jose Paumard, &lt;code&gt;String&lt;/code&gt; cannot be made into a value class (a class that lacks identity), because a value class requires all of its fields to be &lt;code&gt;final&lt;/code&gt;, shallowly or not.&lt;/p&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%2F6hpg3fogtdub6vvwhsmq.jpg" 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%2F6hpg3fogtdub6vvwhsmq.jpg" alt="Valhalla is a dream come false"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Short Answer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Performance, by using lazy evaluation on the hash value of the String and storing it for future uses.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Long Answer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;String uses the &lt;code&gt;hash&lt;/code&gt; (and &lt;code&gt;hashIsZero&lt;/code&gt; if you use JDK 9+) field to store the computed hash value. &lt;/p&gt;

&lt;p&gt;The calculation of a &lt;code&gt;String&lt;/code&gt; object's hash can be very expensive if the string is long (like a blog post, an HTML page, or your feelings for your crush, j/k), and the hash code is only used in some hash-based use cases (like putting one into a &lt;code&gt;HashMap&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It is due to this reason that Java makers decided to lazily evaluate the hash code of a &lt;code&gt;String&lt;/code&gt; and store this value for future uses.&lt;/p&gt;

&lt;p&gt;You can check the &lt;code&gt;String&lt;/code&gt; class source code and see the implementation of its &lt;code&gt;hashCode()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashIsZero&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isLatin1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;StringLatin1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StringUTF16&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashIsZero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the &lt;code&gt;String&lt;/code&gt; is still &lt;strong&gt;effectively immutable&lt;/strong&gt; due to its design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The internal array does not get exposed to the outside due to defensive copying.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;hash&lt;/code&gt; and &lt;code&gt;hashIsZero&lt;/code&gt; value initialization only happens &lt;em&gt;once&lt;/em&gt; (the exception is zero hash value, I am not sure why), and they will never change after that because there are no public ways to mutate those values. This mutation is completely invisible to outside observers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is also worth mentioning that &lt;code&gt;String&lt;/code&gt; is subjected to a lot of internal optimization, for example, the &lt;code&gt;@Stable&lt;/code&gt; annotation on its &lt;code&gt;value&lt;/code&gt; field, and more recently, on its &lt;code&gt;hash&lt;/code&gt; field in JDK 25, allowing some optimizations by the JVM, like constant folding (detailed article is &lt;a href="https://inside.java/2025/10/20/jdk-25-performance-improvements/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;No, String is &lt;strong&gt;not technically immutable&lt;/strong&gt; in the truest sense.&lt;/p&gt;

&lt;p&gt;But yes, String is still &lt;strong&gt;effectively immutable&lt;/strong&gt;. You can only read its final fields, and you cannot do anything to its non-final ones (Reflection API can do something about it, but don't, just... don't).&lt;/p&gt;

&lt;p&gt;String embodies the exact definition of a value class, but unless its internal design is changed (like frozen arrays and stable value JEPs), the journey to Valhalla will not permit an entry for our beloved &lt;code&gt;String&lt;/code&gt; class. We'll see how the future will unfold, with a lot of effort putting into making integrity in Java a high priority (layman's term: what cannot be change will not be changed).&lt;/p&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%2Fzcaoax5ni4s31jmmctb7.jpg" 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%2Fzcaoax5ni4s31jmmctb7.jpg" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>For the Love of God, Please Use Java Records!</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Fri, 07 Nov 2025 07:47:28 +0000</pubDate>
      <link>https://forem.com/vulinh64/for-the-love-of-god-please-use-java-records-3e81</link>
      <guid>https://forem.com/vulinh64/for-the-love-of-god-please-use-java-records-3e81</guid>
      <description>&lt;p&gt;Remember when creating a simple data class in Java felt like doing some sorts of heavy labor? A handful of fields, 100 lines of code (well, not 100 lines, but is pretty close), and the existential dread of knowing you'd have to do it all again, even with the help of IDE? Yeah, Java 16 finally said "our bad" and gave us Records.&lt;/p&gt;

&lt;p&gt;If you're still writing POJOs like it's 2010, buddy, we are not the same.&lt;/p&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%2Fxytjakjcraklwq9d9anu.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%2Fxytjakjcraklwq9d9anu.png" alt="We are not the same" width="500" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Records Are Like Finding $20 in Your Old Jeans
&lt;/h2&gt;

&lt;p&gt;A real life use case: You want to store a name, age, and email. In the old days, you'd write a class, add fields, generate getters, generate setters (even though you don't want them), generate &lt;code&gt;equals()&lt;/code&gt;, generate &lt;code&gt;hashCode()&lt;/code&gt;, generate &lt;code&gt;toString()&lt;/code&gt;, and then realize you forgot to update &lt;code&gt;equals()&lt;/code&gt; after adding a new field. The reviewers told you to update. You hate yourself.&lt;/p&gt;

&lt;p&gt;Now? You write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. You're done. Enough said!&lt;/p&gt;

&lt;p&gt;Here's what you get for free (and I mean &lt;em&gt;actually&lt;/em&gt; free, not "free trial for 30 days" free, without any credit card tomfoolery):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Auto-generated &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, and &lt;code&gt;toString()&lt;/code&gt; that actually work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Getters named like normal people talk: &lt;code&gt;person.name()&lt;/code&gt; instead of &lt;code&gt;person.getName()&lt;/code&gt; (because JavaBeans Specification, why not?)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Everything's &lt;code&gt;final&lt;/code&gt; by default (no surprise mutations at 3 AM)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can't be extended (no inheritance drama)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Still lets you implement interfaces (because interfaces are the true power behind Java's OOP)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One line. That's all it takes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Immutability Situation
&lt;/h2&gt;

&lt;p&gt;So here's the deal, or a gotcha: Records make your &lt;em&gt;references&lt;/em&gt; &lt;code&gt;final&lt;/code&gt;. Think of it like a GPS coordinate: the location is fixed, but someone can still vandalize the building at that address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;TreasureChest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TreasureChest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ruby"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;span class="n"&gt;chest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;gems&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CURSED_GEM"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Plot twist: nothing stops you&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The field references are locked down, but if you put a mutable collection in there? That collection is doing whatever it wants. It's giving "I didn't hear no bell" energy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The usual suspects:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collections&lt;/strong&gt; - Lists, Sets, Maps that laugh at your immutability dreams&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arrays&lt;/strong&gt; - These will betray you every single time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Any object with setters&lt;/strong&gt; - Self-explanatory chaos&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your JVM is trying to do optimizations, but you keep handing it mutable state like "surprise, guess again!" The JIT compiler wants to inline constants and fold operations, but can't if it thinks your data might mutate. It's like trying to take a family photo when someone won't stop moving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix?&lt;/strong&gt; Just embrace immutability from the start. Making everything immutable is the easiest way to achieve thread safety in our chaotic world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Use Records
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use Records for:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;DTOs that just shuttle data around&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API requests/responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Value objects (coordinates, money amounts, that kind of thing)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configuration classes in Spring Boot. Seriously, it's beautiful:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"app.features"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;FeatureFlags&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;darkMode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;betaAccess&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Wire it up in your main class&lt;/span&gt;
&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;
&lt;span class="nd"&gt;@EnableConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FeatureFlags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring Boot 2.2 introduced this (needed &lt;code&gt;@ConstructorBinding&lt;/code&gt;), then 2.6 was like "nah, we're good" and made it automatic.&lt;/p&gt;

&lt;p&gt;TL;DR: Anything that Records can do, except for the cases like below.&lt;/p&gt;

&lt;h3&gt;
  
  
  DO NOT use Records for:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JPA entities&lt;/strong&gt; - They need no-arg constructors, mutable fields, and proxying via inheritance. Records have none of those, so yeah, they mix and match like water and oil.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;However, since Hibernate 6.2, you can use Records as &lt;strong&gt;composite IDs&lt;/strong&gt; for your JPA entities. It's not much, but it's honest work. Records work great for JPA Projections too.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mutable stuff&lt;/strong&gt; - If you really need to mutate states, then Records cannot help you. You can, however, use "withers".&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom exceptions&lt;/strong&gt; - Records can't extend anything except &lt;code&gt;java.lang.Record&lt;/code&gt;. And if you're using exceptions as data carriers, we have bigger problems to discuss. Why do you ask a programmer to fix the network issues? Why would you do that?&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Oh, and Records are immune to those gnarly deserialization attacks by design, as everyone has to bow to its almighty canonical constructor (read: an all-args constructor). One less CVE to lose sleep over.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data-Oriented Programming
&lt;/h2&gt;

&lt;p&gt;Records aren't just "Ctrl+C, Ctrl+V prevention technology" (though they absolutely are). They're part of Java's whole vibe shift toward data-oriented programming. Combined with pattern matching, sealed classes, and switch expressions that don't make you want to cry, Records let you model your domain with immutable data and transformations.&lt;/p&gt;

&lt;p&gt;It's like "here's some data, here's what we do with it without any ceremonies or red tapes." Honestly? It's kind of refreshing. Like finding out you can just... not have daily standup meetings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Up With Lombok
&lt;/h2&gt;

&lt;p&gt;If you've been using Lombok annotations like they're going out of style (they are), I have news. Most of them and Records go together like oil and water, or recruiters and accurate job descriptions (because why did they want someone to do the job of a whole IT department with intern salary? A.I are no excuses, you pathetic human scums!).&lt;/p&gt;

&lt;p&gt;Most of Lombok's annotations will not work with records. You will get compiler errors or face other problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BUT&lt;/strong&gt; two Lombok annotations still work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Builder&lt;/code&gt; - Because builder patterns are genuinely useful&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@With&lt;/code&gt; - For those wither methods (and the JVM might optimize away the temporary objects, which is neat)&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Builder&lt;/span&gt;
&lt;span class="nd"&gt;@With&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;olderAlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// New instance, old one untouched&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@Builder&lt;/code&gt; helps creating an record instance easier, especially if your records have a lot of fields, and &lt;code&gt;@With&lt;/code&gt; allows you to do some thread-safe data transformation (and pray that JVM will back you up with optimizations).&lt;/p&gt;

&lt;p&gt;If you're stuck on Java 8 or 11, Lombok's &lt;code&gt;@Value&lt;/code&gt; can help with immutable classes. But it's like using a flip phone in 2025: it's technically functional with limited supports, but everyone will be giving you &lt;em&gt;looks&lt;/em&gt; (even Japanese started replacing their old "stupid" phones with more modern ones now).&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade Already
&lt;/h2&gt;

&lt;p&gt;Real talk: If you're still on Java 8 or 11, you're not just missing Records. You're missing pattern matching, better garbage collectors, text blocks, sealed classes, and &lt;strong&gt;security patches that don't require a time machine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're basically that person still using Windows XP because "it works fine" (spoiler alert: You will immediately be &lt;strong&gt;bamboozled&lt;/strong&gt; the moment you boot up a Windows XP machine with active internet connection). Until it doesn't, and suddenly you're scrambling to fix the CVEs like trying to hold an overflowing dam with duct tapes and harsh language.&lt;/p&gt;

&lt;p&gt;Java 17+ isn't just nice to have. It's "do you enjoy your infrastructure being held together with duct tape and prayers?" levels of necessary. It's also a new norm, so embrace it!&lt;/p&gt;

&lt;p&gt;Most frameworks and libraries are already moving on. It is time for you, too! No excuses!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Records are Java admitting that sometimes you just need a dang data container, and 100 lines of boilerplate is ridiculous. They cut the nonsense, play nice with modern Java features, and work with every major framework.&lt;/p&gt;

&lt;p&gt;The age of hand-crafted artisanal POJOs is over. And honestly? Nobody's mourning it.&lt;/p&gt;

&lt;p&gt;Welcome to a future with less boilerplate and more time for problems that actually matter. Like arguing about tabs vs. spaces. (It's spaces, fight me.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create a Smaller Docker Image for Our Spring Boot Application</title>
      <dc:creator>Linh Nguyen</dc:creator>
      <pubDate>Thu, 06 Nov 2025 08:40:29 +0000</pubDate>
      <link>https://forem.com/vulinh64/create-a-smaller-docker-image-for-our-spring-boot-application-2m5i</link>
      <guid>https://forem.com/vulinh64/create-a-smaller-docker-image-for-our-spring-boot-application-2m5i</guid>
      <description>&lt;p&gt;The original article is hosted on my website &lt;a href="https://vulinhjava.io.vn/blog/smaller-spring-boot-docker-image/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, so for my first article, I'll keep it short, with step-by-step explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;You can check the &lt;a href="https://github.com/vulinh64/spring-base" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt;, or here is the full &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;amazoncorretto:25-alpine-full&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/project&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; JAVA_VERSION=25&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APP_NAME=app.jar&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DEPS_FILE=deps.info&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; pom.xml mvnw ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; .mvn/ .mvn/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x mvnw

&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw dependency:go-offline

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ src/&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw clean package &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;jar xf target/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;jdeps  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--ignore-missing-deps&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;--recursive&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--multi-release&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;JAVA_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--print-module-deps&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--class-path&lt;/span&gt; &lt;span class="s1"&gt;'BOOT-INF/lib/*'&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    target/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPS_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;jlink &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--add-modules&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPS_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;,jdk.crypto.ec &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--strip-java-debug-attributes&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--compress&lt;/span&gt; 2  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--no-header-files&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--no-man-pages&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--output&lt;/span&gt; /jre-minimalist

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; JAVA_HOME=/opt/java/jre-minimalist&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=$JAVA_HOME/bin:$JAVA_HOME/lib:$PATH&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; USER=springuser&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GROUP=springgroup&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; WORKDIR=app&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; APP_NAME=app.jar&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /jre-minimalist $JAVA_HOME&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /app &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;WORKDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/src/project/target/${APP_NAME} /${WORKDIR}/&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /${WORKDIR}&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; ${USER}&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", \&lt;/span&gt;
    "-XX:+UseCompactObjectHeaders", \
    "-XX:MaxRAMPercentage=75.0", \
    "-XX:InitialRAMPercentage=50.0", \
    "-XX:MaxMetaspaceSize=512m", \
    "-jar", \
    "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Multi-stage Build
&lt;/h2&gt;

&lt;p&gt;This line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM amazoncorretto:25-alpine-full AS build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM alpine:3.22 AS final
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;indicate that our build uses multiple stages. This is an effective strategy that helps with our build by, for example, caching multiple RUN commands during the build phase, and (most importantly) helping reduce the final image size.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Maven Wrapper
&lt;/h2&gt;

&lt;p&gt;You can see this part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY pom.xml mvnw ./
COPY .mvn/ .mvn/
RUN chmod +x mvnw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both the &lt;code&gt;.mvn&lt;/code&gt; folder and &lt;code&gt;mvnw&lt;/code&gt; file (and possibly &lt;code&gt;mvnw.cmd&lt;/code&gt; if you're using Windows) are from the Maven wrapper, which often accompanies your project if it is created using &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initializr&lt;/a&gt;. We'll be using the Maven wrapper with no need to use a Maven Docker image for our build phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Maven Build
&lt;/h2&gt;

&lt;p&gt;The build stage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw dependency:go-offline

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ src/&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;./mvnw clean package &lt;span class="nt"&gt;-DskipTests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will help with caching: as long as there are no dependency changes, we can speed up subsequent builds with all dependencies downloaded and cached.&lt;/p&gt;

&lt;p&gt;We'll be copying everything from the &lt;code&gt;src&lt;/code&gt; folder and the &lt;code&gt;pom.xml&lt;/code&gt; file (see above) and start our build. We can skip the tests by specifying &lt;code&gt;-DskipTests&lt;/code&gt; (we can defer unit tests to feature branch builds).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Custom JRE Image Creation
&lt;/h2&gt;

&lt;p&gt;This part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;jar xf target/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;jdeps  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--ignore-missing-deps&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;--recursive&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--multi-release&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;JAVA_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--print-module-deps&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--class-path&lt;/span&gt; &lt;span class="s1"&gt;'BOOT-INF/lib/*'&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    target/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPS_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;jlink &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--add-modules&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPS_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;,jdk.crypto.ec &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--strip-java-debug-attributes&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--compress&lt;/span&gt; 2  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--no-header-files&lt;/span&gt;  &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--no-man-pages&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--output&lt;/span&gt; /jre-minimalist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Extract the fat JAR file (in this project, the built JAR file name is &lt;code&gt;app.jar&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;jdeps&lt;/code&gt; to detect the required modules needed to run our Spring Boot application container and export the found module list to a file, in this case, &lt;code&gt;deps.info&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, use &lt;code&gt;jlink&lt;/code&gt; to create our own JRE image. Note that we also include &lt;code&gt;jdk.crypto.ec&lt;/code&gt; here, because my sample project uses HTTPS, and without this module, we cannot make HTTP requests to the application running in the container.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Final Touches
&lt;/h2&gt;

&lt;p&gt;This part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /jre-minimalist $JAVA_HOME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means we are copying our custom JRE image from the build stage to our &lt;code&gt;$JAVA_HOME&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;The rest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /app &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;WORKDIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/src/project/target/${APP_NAME} /${WORKDIR}/&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /${WORKDIR}&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; ${USER}&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", \&lt;/span&gt;
    "-XX:+UseCompactObjectHeaders", \
    "-XX:MaxRAMPercentage=75.0", \
    "-XX:InitialRAMPercentage=50.0", \
    "-XX:MaxMetaspaceSize=512m", \
    "-jar", \
    "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;simply performs some (not so) trivial tasks: creating a non-root user, copying the fat JAR file, specifying some JVM arguments, and voilà, the image is ready to be built!&lt;/p&gt;




&lt;p&gt;For a better explanation of the whole process, please visit &lt;a href="https://vulinhjava.io.vn/blog/smaller-spring-boot-docker-image/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; and leave your comments. I'd be happy to hear from you!&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
