<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arash Ariani</title>
    <description>The latest articles on DEV Community by Arash Ariani (@arashariani).</description>
    <link>https://dev.to/arashariani</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%2F211365%2F1f838045-d93e-4df6-bb5f-76da4d34f27c.jpeg</url>
      <title>DEV Community: Arash Ariani</title>
      <link>https://dev.to/arashariani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arashariani"/>
    <language>en</language>
    <item>
      <title>The Index Problem: When You Need to Know Where You Are in Your Stream</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Sat, 06 Sep 2025 20:07:18 +0000</pubDate>
      <link>https://dev.to/arashariani/the-index-problem-when-you-need-to-know-where-you-are-in-your-stream-4a3a</link>
      <guid>https://dev.to/arashariani/the-index-problem-when-you-need-to-know-where-you-are-in-your-stream-4a3a</guid>
      <description>&lt;h2&gt;
  
  
  The "Simple" Problem
&lt;/h2&gt;

&lt;p&gt;Let me paint the picture. I've got a stream of customer names, and I want to create a numbered list for a report:&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;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;customers&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;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"John Smith"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Jane Doe"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bob Johnson"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// I want: ["1. John Smith", "2. Jane Doe", "3. Bob Johnson"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems straightforward, right? Well, not with standard Java Streams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ugly Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Attempt #1: The AtomicInteger Hack
&lt;/h3&gt;

&lt;p&gt;My first instinct was the classic AtomicInteger approach that every Java developer has probably written at least once:&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;AtomicInteger&lt;/span&gt; &lt;span class="n"&gt;counter&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;AtomicInteger&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="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;numbered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAndIncrement&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="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;". "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works, but... ugh. Look at that thing! I'm creating an external state just to track where I am in my stream. It's not thread-safe if I want to go parallel, it's ugly, and honestly, it makes me feel dirty every time I write it.&lt;br&gt;
Plus, what if I forget to reset the counter? What if I accidentally use the same counter instance somewhere else? This approach is a bug waiting to happen.&lt;/p&gt;
&lt;h3&gt;
  
  
  Attempt #2: The IntStream Workaround
&lt;/h3&gt;

&lt;p&gt;Then I remembered the "clever" IntStream approach:&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;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;numbered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IntStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&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="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mapToObj&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&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="s"&gt;". "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;customers&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This only works if I already have a List (not a Stream), and it completely abandons the stream I was working with. Plus, it requires random access, so goodbye to any lazy evaluation benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt #3: The Custom Collector Nightmare
&lt;/h3&gt;

&lt;p&gt;I won't even show you the custom collector I tried to write. Let's just say it involved way too much mutable state and made me question my life choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Why Is This So Hard?" Moment
&lt;/h2&gt;

&lt;p&gt;I stepped back and thought: &lt;em&gt;"In Kotlin, this would just be list.withIndex().map { (index, value) -&amp;gt; "${index + 1}. $value" }. Why is Java making this so complicated?"&lt;/em&gt;&lt;br&gt;
And that's when it hit me. Java Streams are powerful, but they're missing some of the ergonomic features that other functional programming languages take for granted. The standard library was designed conservatively, which is good for stability, but sometimes frustrating for developer experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Index Problems
&lt;/h2&gt;

&lt;p&gt;This isn't just about numbered lists. Here are real scenarios where I've needed indexed operations:&lt;/p&gt;
&lt;h3&gt;
  
  
  CSV Processing with Error Reporting
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// I need to know which LINE failed parsing&lt;/span&gt;
&lt;span class="k"&gt;try&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;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csvLines&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&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="n"&gt;parseRecord&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// But which line threw the exception?&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ParseException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// "Error parsing CSV" - Thanks, super helpful!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Batch Processing with Progress
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Processing 10,000 records, want to show progress&lt;/span&gt;
&lt;span class="n"&gt;largeDataSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&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="n"&gt;expensiveOperation&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// How do I show "Processing record 3,247 of 10,000"?&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Building a Better Solution: The StreamX Journey
&lt;/h2&gt;

&lt;p&gt;So I decided to solve this correctly. Here's how I approached building withIndex for StreamX, step by step:&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: The Naive First Attempt
&lt;/h3&gt;

&lt;p&gt;My first thought was: "Let me just wrap this in a utility method to hide the ugly AtomicInteger":&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="kd"&gt;static&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;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Stream&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="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BiFunction&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;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt; &lt;span class="n"&gt;counter&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;AtomicInteger&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAndIncrement&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;This cleaned up the calling code, but it still had all the same problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External mutable state&lt;/li&gt;
&lt;li&gt;Not truly parallel-safe&lt;/li&gt;
&lt;li&gt;The AtomicInteger overhead for every element&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: The "What If I Collect First?" Attempt
&lt;/h3&gt;

&lt;p&gt;Then I thought, maybe I should just collect in a list first:&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="kd"&gt;static&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;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Stream&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="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BiFunction&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;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;)&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="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;IntStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;range&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="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mapToObj&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&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="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;i&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;This worked, but it broke the whole point of streams! No more lazy evaluation, everything gets materialized into memory immediately. For a large stream, this could be a performance killer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: The "I Need to Think Differently" Moment
&lt;/h3&gt;

&lt;p&gt;I realized I was thinking about this wrong. The problem wasn't with Java Streams themselves - it was that I needed to think at the Spliterator level. Streams are built on Spliterators, and that's where the real magic happens.&lt;br&gt;
What if I could create a Spliterator that automatically tracks indices as it processes elements?&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Building IndexedValue
&lt;/h3&gt;

&lt;p&gt;First, I needed a clean way to represent an element paired with its index:&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="nc"&gt;IndexedValue&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="n"&gt;value&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;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&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="s"&gt;"IndexedValue{value="&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="s"&gt;", index="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"}"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, immutable, and tells you exactly what it is. No mystery here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: The IndexingSpliterator
&lt;/h3&gt;

&lt;p&gt;This is where it gets interesting. I needed a Spliterator that wraps another Spliterator and adds index tracking:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IndexingSpliterator&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="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Spliterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IndexedValue&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;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Spliterator&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="n"&gt;source&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;index&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="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IndexingSpliterator&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Spliterator&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="n"&gt;source&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;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;tryAdvance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt; &lt;span class="nc"&gt;IndexedValue&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;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;action&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;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryAdvance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
            &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&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;IndexedValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;estimateSize&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;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;estimateSize&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;characteristics&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;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;characteristics&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Spliterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IndexedValue&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;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;trySplit&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// For simplicity, we don't support splitting (no parallel processing)&lt;/span&gt;
        &lt;span class="c1"&gt;// A full implementation would need to handle this properly&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key insight here is &lt;em&gt;tryAdvance()&lt;/em&gt; every time the underlying &lt;em&gt;Spliterator&lt;/em&gt; produces an element, we wrap it with its index and increment our counter. Clean, simple, and the state is encapsulated within the &lt;em&gt;Spliterator&lt;/em&gt; itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Building zipWithIndex
&lt;/h3&gt;

&lt;p&gt;Now I could create the core operation:&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="kd"&gt;static&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="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IndexedValue&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;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;zipWithIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Stream&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="n"&gt;stream&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="nc"&gt;StreamSupport&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&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;IndexingSpliterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spliterator&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isParallel&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Preserve parallel characteristics&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;This gives me a stream where each element is paired with its index. Perfect!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: The Final withIndex Implementation
&lt;/h3&gt;

&lt;p&gt;And finally, the clean API I originally wanted:&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="kd"&gt;static&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;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Stream&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="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BiFunction&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;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&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="nf"&gt;zipWithIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexed&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;indexed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;index&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;Now I can write:&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;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;numbered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StreamX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="s"&gt;". "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Approach Wins
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No External State
&lt;/h3&gt;

&lt;p&gt;The index tracking is encapsulated within the Spliterator. No shared mutable state, no thread safety concerns.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Preserves Stream Characteristics
&lt;/h3&gt;

&lt;p&gt;The operation maintains whether the original stream was parallel, ordered, etc. It's a proper stream citizen.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lazy Evaluation
&lt;/h3&gt;

&lt;p&gt;Elements are only processed when needed. The index calculation happens on demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Composable
&lt;/h3&gt;

&lt;p&gt;You can chain this with other stream operations naturally:&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;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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StreamX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="s"&gt;". "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;// Still a normal stream!&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;String:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Familiar API
&lt;/h3&gt;

&lt;p&gt;If you've used Kotlin's &lt;em&gt;withIndex()&lt;/em&gt; or Scala's &lt;em&gt;zipWithIndex&lt;/em&gt;, this feels completely natural.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  CSV Processing with Error Lines
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&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;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StreamX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csvLines&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;parseRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ParseException&lt;/span&gt; &lt;span class="n"&gt;e&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="s"&gt;"Line "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&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="s"&gt;": "&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;span class="na"&gt;getMessage&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Objects:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nonNull&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Only keep the errors&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Progress Tracking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&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;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StreamX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&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;index&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="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="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing %d of %d (%.1f%%)%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalSize&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;totalSize&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="nf"&gt;processItem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conditional Processing by Position
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&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;htmlRows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StreamX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&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;cssClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&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;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"even-row"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"odd-row"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;tr class='%s'&amp;gt;%s&amp;lt;/tr&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cssClass&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&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="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Building this feature taught me a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sometimes the standard library isn't enough - and that's okay! Java can't include every possible utility operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Good APIs hide complexity - The final withIndex method is simple to use, but the underlying implementation requires understanding Spliterators.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Functional programming patterns are worth stealing - When Kotlin, Scala, and Haskell all have similar operations, there's probably a good reason.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance matters - The Spliterator approach maintains lazy evaluation and stream characteristics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real problems deserve real solutions - This wasn't an academic exercise; it solved actual day-to-day frustrations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check out the full code, documentation, and examples here: &lt;a href="https://github.com/arash691/streamx" rel="noopener noreferrer"&gt;StreamX&lt;/a&gt;&lt;/p&gt;

</description>
      <category>stream</category>
      <category>java</category>
    </item>
    <item>
      <title>Simplify Your Java Business Code by Flow DSL</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Sat, 10 May 2025 17:50:54 +0000</pubDate>
      <link>https://dev.to/arashariani/simplify-your-java-business-code-by-flow-dsl-1lg7</link>
      <guid>https://dev.to/arashariani/simplify-your-java-business-code-by-flow-dsl-1lg7</guid>
      <description>&lt;p&gt;Let’s be honest – writing workflows in Java can feel like a never-ending game of try-catch, nested conditions, and tedious state management. If you’ve ever had to handle retries, error recovery, or compensations, you know how quickly things get out of hand.&lt;/p&gt;

&lt;p&gt;I got tired of that too. That’s why I built Flow DSL, a tiny library that lets you define workflows in a simple, declarative way. It’s all about focusing on what should happen in each step, not how to handle every little detail. Think of it as a storyboard for your business logic – you map out each step, and Flow DSL handles the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the Big Idea Behind Flow DSL?
&lt;/h2&gt;

&lt;p&gt;Traditional Java workflow code is imperative – you’re telling the JVM exactly how to execute each step, which leads to cluttered, repetitive code.&lt;/p&gt;

&lt;p&gt;Flow DSL flips the script. It borrows concepts from functional programming – map(), flatMap(), etc. – so you can focus on defining what needs to happen, step by step. Instead of dealing with nested logic and endless if-else chains, you write a clean, linear flow that’s easy to read and maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built Flow DSL
&lt;/h2&gt;

&lt;p&gt;Every project I worked on had the same pattern – complex workflows with retries, compensations, and error handling sprinkled all over the place. The code became a mess of nested structures and hard-to-track logic.&lt;/p&gt;

&lt;p&gt;I thought, "What if I could just write the flow like a story – this happens, then this, then that – and let a library handle the plumbing?" That’s how Flow DSL was born. It’s all about turning your workflow logic into a series of steps without worrying about implementation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Flow DSL Works – Core Features and Concepts
&lt;/h2&gt;

&lt;p&gt;Let’s dive into the good stuff. Here are some of the key features that make Flow DSL tick:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Defining a Simple Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s a basic flow that transforms a string and logs the result:&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;Flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" World"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;String:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onComplete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Outputs: HELLO WORLD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No nested structures, no clutter. Just a series of steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Error Handling with Retry and Compensation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s say you’re processing a payment and want to handle retries and rollback logic:&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;Flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&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;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withRetry&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="na"&gt;withCompensation&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;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rollbackPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment failed"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three retries and a rollback – all in a few lines of code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Parallel Execution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Need to run multiple tasks concurrently? Easy:&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;Flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parallel&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;inventoryService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkStock&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;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verifyFunds&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;notificationService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareEmail&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="na"&gt;withParallelism&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="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flow DSL takes care of concurrency so you can focus on what’s important.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Context Propagation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Share data between steps without manually passing it around:&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;Flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processPayment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;inventoryService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItems&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onComplete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order processed successfully"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Timeouts and Backpressure:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set execution time limits and manage data throughput without complex threading logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Monitoring and Metrics:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Track the status and duration of each step, making it easy to spot bottlenecks and optimize flows.&lt;/p&gt;

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

&lt;p&gt;Declarative API: Less boilerplate, more clarity.&lt;/p&gt;

&lt;p&gt;Centralized Error Handling: Manage retries and compensations in a consistent way.&lt;/p&gt;

&lt;p&gt;Context Management: Pass data across steps without manual state tracking.&lt;/p&gt;

&lt;p&gt;Scalability: Run parallel tasks effortlessly with built-in concurrency management.&lt;/p&gt;

&lt;p&gt;Extensibility: Easily add new steps or modify the flow without breaking everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  How You Can Help Shape Flow DSL
&lt;/h2&gt;

&lt;p&gt;Flow DSL is still a work in progress, and I’d love to get your feedback. Try it out, break it, and let me know what works and what doesn’t. Here’s how you can get involved:&lt;/p&gt;

&lt;p&gt;Check Out the Code: &lt;a href="https://github.com/arash691/flow-dsl" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; Repo&lt;/p&gt;

&lt;p&gt;Explore the Docs: &lt;a href="https://arash691.github.io/flow-dsl/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Raise Issues: Report bugs, suggest features, or ask questions.&lt;/p&gt;

&lt;p&gt;Contribute: Have a feature in mind? Open a PR and let’s build it together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Make Flow DSL Better – Together!
&lt;/h2&gt;

&lt;p&gt;Flow DSL started as a simple experiment to make workflow management easier, but with your feedback, it can become a powerful tool for Java developers everywhere. Let me know what you think – I’d love to hear your thoughts and ideas. Let’s make Flow DSL the go-to library for declarative workflow management in Java!&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>Understanding JPA Pessimistic Locking vs. Serializable Isolation in Transactions</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Sat, 09 Nov 2024 16:24:51 +0000</pubDate>
      <link>https://dev.to/arashariani/understanding-jpa-pessimistic-locking-vs-serializable-isolation-in-transactions-4khl</link>
      <guid>https://dev.to/arashariani/understanding-jpa-pessimistic-locking-vs-serializable-isolation-in-transactions-4khl</guid>
      <description>&lt;p&gt;Most database applications have to control concurrent access to data in order to prevent issues like data inconsistencies, dirty reads, and phantom reads. The two common ways of achieving data consistency and preventing concurrency issues are JPA Pessimistic Locking and Serializable Isolation Level. Both provide ways to control access to shared data, but they do it differently, and each has different performance and consistency trade-offs. This article explains the differences between these two approaches and when to use which of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is JPA Pessimistic Locking?
&lt;/h2&gt;

&lt;p&gt;In JPA (Java Persistence API), pessimistic locking is used to control access to specific rows in a database when multiple transactions might attempt to modify the same data concurrently. JPA pessimistic locks are scoped at the entity level (the specific rows associated with a JPA entity) and involve explicitly requesting locks within a transaction.&lt;/p&gt;

&lt;h4&gt;
  
  
  How JPA Pessimistic Locking Works
&lt;/h4&gt;

&lt;p&gt;When using JPA's pessimistic locking with a query, the JPA will translate the locking instruction into database-specific SQL. &lt;/p&gt;

&lt;p&gt;Here is how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lock Modes:&lt;/strong&gt; JPA provides three pessimistic lock modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PESSIMISTIC_READ:&lt;/strong&gt; Allows reading data while preventing modifications by other transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PESSIMISTIC_WRITE:&lt;/strong&gt; Prevents both read and write by other transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PESSIMISTIC_FORCE_INCREMENT:&lt;/strong&gt; Forces an increment on a version column in the entity, effectively treating the entity as updated.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;SQL Translation:&lt;/strong&gt; JPA translates these lock modes into SQL statements, such as &lt;em&gt;SELECT... FOR UPDATE&lt;/em&gt;, that are compatible with the underlying database.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example Using JPA Pessimistic Locking
&lt;/h4&gt;

&lt;p&gt;Here is a sample usage of pessimistic locking at the JPA level in a repository 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="nd"&gt;@Lock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LockModeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PESSIMISTIC_WRITE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT e FROM Entity e WHERE e.someCondition = :condition"&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;Entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findWithPessimisticLock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"condition"&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;condition&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that case, &lt;em&gt;PESSIMISTIC_WRITE&lt;/em&gt; will lock the rows returned by the query so that no other transactions can modify it before the transaction finishes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Characteristics of JPA Pessimistic Locking
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;- Scope:&lt;/strong&gt; It locks the rows that match the query criteria, so nobody else can modify those rows.&lt;br&gt;
&lt;strong&gt;- Block:&lt;/strong&gt; It would block any other transaction requesting a lock on the rows in conflict until this one commits or rolls back. &lt;br&gt;
&lt;strong&gt;- Performance:&lt;/strong&gt; Generally lighter on performance, as it only locks specific rows, but does not guarantee the prevention of phantom reads (new rows being added that match the condition after the query has been executed).&lt;/p&gt;
&lt;h2&gt;
  
  
  Serializable Isolation Level
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Serializable isolation&lt;/strong&gt; is the strictest isolation level available in databases, ensuring that transactions appear to execute sequentially, with no interference from each other. Serializable isolation prevents all concurrency issues, including &lt;strong&gt;dirty reads, non-repeatable reads, and phantom reads.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  How Serializable Isolation Works
&lt;/h4&gt;

&lt;p&gt;When a transaction is set to a &lt;strong&gt;Serializable isolation&lt;/strong&gt; level, the database enforces strict ordering among transactions. This prevents other transactions from interacting with rows that might impact the results of the transaction, ensuring strict consistency.&lt;/p&gt;

&lt;p&gt;There are two common implementations of Serializable isolation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Row-Level Locking:&lt;/strong&gt; Databases like MySQL and Oracle use row locks, and sometimes additional range or gap locks, to control access to specific rows and ensure no new rows can interfere.&lt;br&gt;
&lt;strong&gt;- Multi-Version Concurrency Control (MVCC):&lt;/strong&gt; Databases like PostgreSQL use snapshots and track version conflicts to provide Serializable behavior without locking rows directly.&lt;/p&gt;
&lt;h4&gt;
  
  
  Example of Using Serializable Isolation
&lt;/h4&gt;

&lt;p&gt;You can apply the Serializable isolation level at the transaction level in Spring, for 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="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isolation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Isolation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SERIALIZABLE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&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;Entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findWithSerializableIsolation&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;condition&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;entityManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT e FROM Entity e WHERE e.someCondition = :condition"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Entity&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"condition"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResultList&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;In this example, the &lt;strong&gt;Isolation.SERIALIZABLE&lt;/strong&gt; level enforces strict isolation, ensuring the query result is consistent with a fully isolated transaction.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Characteristics of Serializable Isolation
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;- Scope:&lt;/strong&gt; Locks the rows involved and may apply additional range locks to prevent new rows that could impact the transaction’s result.&lt;br&gt;
&lt;strong&gt;- Blocking:&lt;/strong&gt; Other transactions trying to read or write rows impacted by the current transaction will typically be blocked until the transaction completes.&lt;br&gt;
&lt;strong&gt;- Phantom Prevention:&lt;/strong&gt; Prevents phantom reads by locking ranges, ensuring no other transactions can add rows that would affect the current transaction’s result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparing JPA Pessimistic Locking and Serializable Isolation
&lt;/h3&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%2Fdshfmmua1ztunhoidi8u.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%2Fdshfmmua1ztunhoidi8u.png" alt="Image description" width="800" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the Right Approach
&lt;/h3&gt;

&lt;p&gt;When deciding between JPA pessimistic locking and Serializable isolation, consider the specific requirements of your application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use JPA Pessimistic Locking when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to control concurrent access to specific rows without affecting broader queries.&lt;/li&gt;
&lt;li&gt;Performance is a priority, and you want minimal overhead from concurrency control.&lt;/li&gt;
&lt;li&gt;Phantom reads are not an issue for your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Serializable Isolation when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strict consistency is required, with no room for concurrency anomalies (including phantom reads).&lt;/li&gt;
&lt;li&gt;You can tolerate higher performance costs due to the strict concurrency control.&lt;/li&gt;
&lt;li&gt;You are running a critical section of code where any data anomaly could be costly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both &lt;strong&gt;JPA pessimistic locking&lt;/strong&gt; and &lt;strong&gt;Serializable isolation&lt;/strong&gt; provide robust ways to manage concurrent access to data, but they serve different needs. Pessimistic locking in JPA gives fine-grained control over specific rows, allowing for better performance but with limited consistency guarantees. In contrast, Serializable isolation enforces strict isolation, treating transactions as if they run sequentially, which provides full consistency but may reduce concurrency.&lt;/p&gt;

</description>
      <category>jpa</category>
      <category>transaction</category>
    </item>
    <item>
      <title>Handling Asynchronous Execution with Transactions in Spring: A Common Pitfall and How to Solve It</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Wed, 06 Nov 2024 17:06:58 +0000</pubDate>
      <link>https://dev.to/arashariani/handling-asynchronous-execution-with-transactions-in-spring-a-common-pitfall-and-how-to-solve-it-5ah4</link>
      <guid>https://dev.to/arashariani/handling-asynchronous-execution-with-transactions-in-spring-a-common-pitfall-and-how-to-solve-it-5ah4</guid>
      <description>&lt;p&gt;In modern Spring applications, it is common to combine asynchronous execution with transactional behavior. However, annotating a method with &lt;em&gt;@Async&lt;/em&gt; and &lt;em&gt;@Transactional(propagation = Propagation.REQUIRES_NEW)&lt;/em&gt; might result in unexpected behavior because Spring manages asynchronous tasks and transactions. &lt;/p&gt;

&lt;p&gt;In this article, we’ll explore the issue in detail and demonstrate a solution to handle both asynchronous execution and transaction management correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: @Async and @Transactional(propagation = Propagation.REQUIRES_NEW)
&lt;/h3&gt;

&lt;p&gt;Consider the following code snippet:&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="nd"&gt;@Async&lt;/span&gt;
&lt;span class="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propagation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REQUIRES_NEW&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveSomething&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// save-point one&lt;/span&gt;
    &lt;span class="c1"&gt;// save-point two&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, it might seem that everything is working as expected. However, there are some key problems with this configuration that can lead to unintended behavior.&lt;/p&gt;

&lt;h4&gt;
  
  
  What Happens Behind the Scenes?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;@Async Annotation:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;@Async&lt;/strong&gt; annotation tells Spring to run the method asynchronously in a separate thread. This means the method will not run in the original thread that called it but will be offloaded to a different thread in a thread pool.&lt;br&gt;
Spring uses proxies to manage asynchronous methods. When you call a method annotated with &lt;strong&gt;@Async&lt;/strong&gt;, Spring delegates the execution to an internal Executor that runs the method in a different thread.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Transactional(propagation = Propagation.REQUIRES_NEW) Annotation:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;@Transactional(propagation = Propagation.REQUIRES_NEW)&lt;/strong&gt; annotation ensures that a new transaction is started for the method, regardless of any existing transaction. It suspends any active transaction in the calling thread and begins a new transaction for the method.&lt;/p&gt;

&lt;p&gt;Transaction management in Spring is generally thread-bound, meaning that the transaction context is tied to the current thread.&lt;/p&gt;
&lt;h4&gt;
  
  
  The Conflict
&lt;/h4&gt;

&lt;p&gt;The issue arises because &lt;strong&gt;@Async&lt;/strong&gt; runs the method in a different thread, and Spring’s transaction management relies on the thread to bind the transaction. When the method is executed asynchronously, the transaction context from the calling thread does not propagate to the new thread, which leads to the following problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;@Transactional&lt;/strong&gt; annotation will not create a new transaction in the async thread, and any transactional behavior (like rollbacks, commits, etc.) will not be handled correctly.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;REQUIRES_NEW&lt;/strong&gt; propagation setting won’t apply because the asynchronous method is running outside the original transaction context.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Solution: Decoupling Async Execution and Transactions
&lt;/h3&gt;

&lt;p&gt;To solve this problem, you can decouple the asynchronous execution from the transactional logic by handling the transaction in a separate service method. Here’s how you can do it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Step 1: Create a New Synchronous Service for Transactional Logic&lt;br&gt;
Create a new service that handles the transactional logic. This method will be executed synchronously (without &lt;strong&gt;@Async&lt;/strong&gt;) to ensure that the transaction management works as expected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Step 2: Call the Synchronous Method Asynchronously&lt;br&gt;
You can then call the synchronous transactional method asynchronously using &lt;strong&gt;@Async&lt;/strong&gt;. This ensures that the transactional logic is handled correctly in the main thread, and the asynchronous behavior is still maintained.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how the refactored code looks:&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="nd"&gt;@Service&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;MyService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TransactionalService&lt;/span&gt; &lt;span class="n"&gt;transactionalService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TransactionalService&lt;/span&gt; &lt;span class="n"&gt;transactionalService&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;transactionalService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transactionalService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Async&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveSomethingAsync&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;transactionalService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveSomething&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Call the synchronous transactional method asynchronously&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&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;TransactionalService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propagation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;REQUIRES_NEW&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveSomething&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// save-point one&lt;/span&gt;
        &lt;span class="c1"&gt;// save-point two&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;h4&gt;
  
  
  How does it work?
&lt;/h4&gt;

&lt;p&gt;In the refactored solution, asynchronous execution is achieved by annotating the &lt;em&gt;saveSomethingAsync()&lt;/em&gt; method with &lt;strong&gt;@Async&lt;/strong&gt;. This means that when &lt;em&gt;saveSomethingAsync()&lt;/em&gt; is called, it will run in a separate thread managed by Spring’s asynchronous task executor. Running this in a different thread allows the main thread to continue its execution without waiting for &lt;em&gt;saveSomethingAsync()&lt;/em&gt; to complete. This approach is beneficial for scenarios where you want to offload long-running tasks, improve responsiveness, or handle independent operations concurrently.&lt;/p&gt;

&lt;p&gt;For transactional behavior, the &lt;em&gt;saveSomething()&lt;/em&gt; method in &lt;em&gt;TransactionalService&lt;/em&gt; is annotated with &lt;strong&gt;@Transactional(propagation = Propagation.REQUIRES_NEW)&lt;/strong&gt;. This ensures that each call to &lt;em&gt;saveSomething()&lt;/em&gt; creates a new transaction independent of any existing transaction in the calling method. The &lt;strong&gt;REQUIRES_NEW&lt;/strong&gt; propagation starts a fresh transaction and suspends any existing one, allowing &lt;em&gt;saveSomething()&lt;/em&gt; to operate in an isolated transaction context. This means that even if the original calling method has a transaction, &lt;em&gt;saveSomething()&lt;/em&gt; will work within its own separate transaction, enabling controlled commits and rollbacks for just this operation.&lt;/p&gt;

&lt;p&gt;By decoupling the asynchronous execution from the transactional logic, we ensure that transaction management works as expected. In this setup, the transaction context remains correctly handled within the &lt;em&gt;saveSomething()&lt;/em&gt; method, while the &lt;em&gt;saveSomethingAsync()&lt;/em&gt; method continues to execute in a separate thread. This separation of concerns allows both the benefits of asynchronous processing and reliable transaction management, enabling independent and safe data operations even when processing concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Use This Approach?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;When Transaction Isolation Is Critical:&lt;/strong&gt; If you need to ensure that certain operations are carried out in a separate transaction (i.e., REQUIRES_NEW), this approach works well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asynchronous Operations:&lt;/strong&gt; If you have long-running, independent tasks that need to be executed asynchronously but also require their own transaction boundaries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Alternative: Using a Message Queue for Complete Decoupling
&lt;/h3&gt;

&lt;p&gt;If you need more advanced decoupling or wish to handle retries, error handling, and long-running processes, consider offloading the task to a message queue like Kafka or RabbitMQ. By using a message queue, you can ensure that each task runs in its own context, and the transaction can be managed independently.&lt;/p&gt;

</description>
      <category>springdata</category>
      <category>java</category>
      <category>transactional</category>
    </item>
    <item>
      <title>Understanding JVM Lock Optimizations</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Mon, 23 Sep 2024 07:24:45 +0000</pubDate>
      <link>https://dev.to/arashariani/understanding-jvm-lock-optimizations-4l5i</link>
      <guid>https://dev.to/arashariani/understanding-jvm-lock-optimizations-4l5i</guid>
      <description>&lt;p&gt;Concurrency is very critical to the development of robust, scalable applications that can perform several concurrent operations. However, a price needs to be paid for this in terms of synchronization. It incurs performance costs due to the attendant overheads of acquiring and releasing locks. To alleviate these performance costs, several optimizations have been incorporated into the JVM, in several flavors, such as biased locking, lock elimination, lock coarsening, and the notion of lightweight and heavyweight locks.&lt;/p&gt;

&lt;p&gt;In this article, we see these optimizations in greater detail, going over how they improve synchronization in multi-threaded Java applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java Locking Basics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Java, the synchronization of blocks or methods ensures that only one thread can execute a critical section of code at a time. This matters in particular when considering the sharing of resources within the multithreaded environment. Java implements this by relying on intrinsic locks- or sometimes, they are called monitors associated with objects or classes that help manage access to the threads by using the synchronized blocks.&lt;/p&gt;

&lt;p&gt;Although synchronization is a necessity for thread safety, it might be quite expensive when contention is low or completely absent. Which is where JVM optimizations step into the frame. Thus, that reduces the cost of locking and will enhance overall performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Biased Locking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Biased Locking?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Biased locking is an optimization targeted at the reduction of the overhead of lock acquisition. It is optimized to reduce the cost of lock acquisition, which is dominated by a single thread or most largely accessed by a single thread. Such programs often acquire and release locks by the same thread with no contention from other threads. The JVM can recognize this pattern and biases the lock to that particular thread; following lock acquisition comes almost for free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Does Biased Locking Work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If biased locking is enabled, then the first time a thread acquires a lock, it makes that lock biased toward that thread. The identity of the thread is recorded in the header of the lock object, and subsequent lock acquisitions by that thread involve no synchronization whatsoever-they just check if the lock is biased toward the current thread, which is a very fast, non-blocking operation.&lt;/p&gt;

&lt;p&gt;If another thread tries to acquire the lock, then bias is canceled and JVM falls back to a standard unbiased locking mechanism. At this stage, it is now a standard lock, and the second thread will have to acquire it through a standard locking process.&lt;br&gt;
Benefits of Biased Locking &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Acquisition of the same thread on a biased lock is almost a free lock acquisition.&lt;/p&gt;

&lt;p&gt;Hence, contention handling is not needed because other threads have no chance to be involved in acquiring the lock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lower Overhead:&lt;/strong&gt; The state of the lock need not change or synchronization-related metadata be modified except in the event of contention. &lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When is Biased Locking Used?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Biased locking is useful in applications where locks are mainly accessed by the same thread, such as single-threaded applications or an application that has low lock contention under multi-threading. It's enabled by default in most JVMs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Disable Biased Locking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Biased locking is enabled by default but can also be disabled with the JVM flag like below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-XX:-UseBiasedLocking&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Lock Elimination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Lock Elimination?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lock elimination is a very powerful optimization in which the JVM eliminates some unnecessary synchronization (locks) completely. It will inspect the code for any opportunities during its JIT compilation wherein it finds out that synchronization is not necessary. This usually occurs when the lock has been accessed by just one thread, or the object that the JVM will be used to synchronize doesn't share the same object within different threads. Once the JVM deems that it is no longer required, then it does eliminate the lock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Does Lock Elimination Work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the escape analysis phase of JIT compilation, JVM checks whether the object is confined to a single thread or is used only in a local context. If synchronization on that object can be removed because an object doesn't escape the scope of the thread that created it, then it will be so.&lt;/p&gt;

&lt;p&gt;For example, if an object is created and used entirely within a method (and not shared across threads) the JVM realizes no other thread can possibly access the object, and thus that all synchronization is redundant. In such a case, the JIT compiler simply eliminates the lock altogether.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero Locking Overhead:&lt;/strong&gt; Eliminating unnecessary synchronization will also prevent the JVM from paying the cost of acquiring and releasing locks in the first place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Higher Throughput:&lt;/strong&gt; Dead synch can sometimes lead to a higher throughput of the application, especially if the code contains many synchronized blocks.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void someMethod() {
    StringBuilder sb = new StringBuilder();
    synchronized (sb) {
        sb.append("Hello");
        sb.append("World");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, synchronization on &lt;em&gt;sb&lt;/em&gt; is not necessary since the &lt;em&gt;StringBuilder&lt;/em&gt; is used only within the &lt;em&gt;someMethod&lt;/em&gt; and is not shared between other threads. By looking at this, the JVM can perform an escape analysis to remove the lock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Lock Coarsening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Lock Coarsening?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lock coarsening is an optimization wherein the JVM expands the scope of a lock to cover more chunks of code instead of continuously acquiring and releasing the lock in loops or small sections of code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lock Coarsening Work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the JVM finds that a tight loop or multiple adjacent code blocks acquire and release a lock too frequently, it can coarsen the lock by taking the lock outside the loop or across several blocks of code. This makes repeated acquisition and release of the lockless expensive and enables a thread to hold the lock for more iterations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Example: Lock Coarsening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for (int i = 0; i &amp;lt; 1000; i++) {
    synchronized (lock) {
        // Do something
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lock coarsening pushes the lock acquisition outside the loop, so the thread acquires the lock only once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;synchronized (lock) {
  for (int i = 0; i &amp;lt; 1000; i++) {
    // Do something
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JVM can dramatically improve performance by avoiding more acquires and releases of the lock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lock Coarsening Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less Freedom of Locking Overheads:&lt;/strong&gt; Coarsening avoids lock acquisitions and releases, especially in hotspot code, such as loops that have been iterated thousands of times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improved Performance:&lt;/strong&gt;&lt;br&gt;
Locking for a longer period improves performance when compared to the scenario in which, without locking, such a lock would be acquired and released multiple times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Light Weight and Heavy Weight Locks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The JVM uses two different locking techniques based on the degree of contention among the threads. Such techniques include lightweight locks and heavyweight locks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Light Weight Locking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lightweight locking takes place in the absence of a contention lock, meaning only one thread is trying to acquire that lock. In such scenarios, the JVM optimizes the acquisition using a CAS operation when trying to acquire the lock, which can happen without heavyweight synchronization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heavyweight Locking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In case multiple threads want to obtain the same lock; that is, there is contention, the JVM escalates this to heavyweight locking. This would involve blocking threads at the OS level and managing them using OS-level synchronization primitives. Heavyweight locks are slower because they actually require the OS to perform context switching, as well as to manage threads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lock Escalation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If contention arises at a lightweight lock, the JVM may escalate it to a heavyweight lock. Escalation here means switching from the fast, user-level lock to a more expensive, OS-level lock which includes thread blocking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Lightweight Locks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rapid acquisition of a lock:&lt;/strong&gt; When there is no contention, lightweight locks are far quicker than heavyweight locks because they avoid OS-level synchronization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced blocking:&lt;/strong&gt; With no contentions, threads do not block and increase linearly with lower latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages of Heavyweight Locks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Performance Overhead: Heavyweight locks incur the cost of thread blocking, context switching, and waking up threads with performance degradation at very high contention regimes.&lt;/p&gt;

&lt;p&gt;All these optimizations help the JVM improve performance in multi-threaded applications, so developers can now write safe, concurrent code without sacrificing much in the way of synchronization overhead. Understanding these optimizations can help developers design more efficient systems, especially in cases that have a high-performance penalty for locking.&lt;/p&gt;

</description>
      <category>java</category>
      <category>jvm</category>
    </item>
    <item>
      <title>Optimizing Database Performance with Concatenated Indexes</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Sat, 23 Dec 2023 19:55:09 +0000</pubDate>
      <link>https://dev.to/arashariani/optimizing-database-performance-with-concatenated-indexes-1bk4</link>
      <guid>https://dev.to/arashariani/optimizing-database-performance-with-concatenated-indexes-1bk4</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In the world of database management, the efficiency of queries is paramount. Indexing is a powerful technique to enhance query performance, and one versatile option is the concatenated index. This index type allows for the combination of multiple columns into a single index, providing a unique set of advantages and considerations for database administrators and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Concatenated Indexes
&lt;/h2&gt;

&lt;p&gt;A concatenated index, also known as a composite or compound index, is created by combining the values of multiple columns into a single index structure. The order in which columns are specified in the index definition is crucial, as it determines how the data is physically organized within the index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Concatenated index on (Column1, Column2)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_Column1_Column2&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;YourTable&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Column1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Column2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Query Performance Impact
&lt;/h2&gt;

&lt;p&gt;The impact of a concatenated index on query performance is significant and depends on the specific queries executed on the database. Let's explore this impact with a practical example.&lt;/p&gt;

&lt;p&gt;Consider a scenario where we have a concatenated index on columns &lt;em&gt;CustomerID&lt;/em&gt; and &lt;em&gt;ProductID&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- With concatenated index on (CustomerID, ProductID)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_CustomerProduct&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's examine a query filtering only on &lt;em&gt;CustomerID&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Query with concatenated index&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the concatenated index can still be beneficial for this query, it might not be as efficient as a dedicated index on CustomerID alone. The database engine must traverse the index entries for &lt;em&gt;ProductID&lt;/em&gt; as well, even though it's not part of the &lt;em&gt;WHERE&lt;/em&gt; clause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Column Order Matters
&lt;/h2&gt;

&lt;p&gt;The order of columns in a concatenated index is crucial to its effectiveness. &lt;strong&gt;The leftmost prefix of the index is crucial for optimizing queries&lt;/strong&gt;. For instance, if we reverse the order of columns in the previous index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Concatenated index on (ProductID, CustomerID)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_ProductCustomer&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This new index might not be as efficient for queries filtering only on &lt;em&gt;CustomerID&lt;/em&gt; because the leftmost prefix does not match the query condition.&lt;/p&gt;

&lt;p&gt;the statement &lt;strong&gt;&lt;em&gt;"The leftmost prefix of the index is crucial for optimizing queries"&lt;/em&gt;&lt;/strong&gt; is indeed related to the structure of &lt;strong&gt;B-tree&lt;/strong&gt; indexes commonly used in databases.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;B-tree&lt;/strong&gt; (Balanced Tree) is a data structure that organizes keys in a sorted order for efficient search, insertion, and deletion operations. In the context of a concatenated index, the B-tree structure is constructed based on the order of columns specified in the index definition.&lt;/p&gt;

&lt;p&gt;When a query is executed, the database engine aims to use the index efficiently to locate the desired rows. The leftmost prefix of the index refers to the initial columns specified in the concatenated index. This leftmost portion is crucial because the B-tree structure allows for quick search and retrieval of data based on the sorted order of these leftmost columns.&lt;/p&gt;

&lt;p&gt;Consider a concatenated index on columns (A, B, C). The B-tree structure organizes the data first by column A, then by column B, and finally by column C. If you have a query that filters based on A and B (e.g., WHERE A = 1 AND B = 2), the leftmost prefix of the index (A) is used efficiently for locating the rows, benefitting from the sorted order of values in column A. However, if you only filter based on column C, the index might not be as efficient for that specific query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing for Query Patterns
&lt;/h2&gt;

&lt;p&gt;When deciding on concatenated indexes, it's essential to analyze the most common query patterns in your application. The order of columns in the index should align with these patterns to maximize efficiency. If queries frequently involve specific combinations of columns, a concatenated index on those columns in the right order can significantly enhance performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations and Trade-offs
&lt;/h2&gt;

&lt;p&gt;While concatenated indexes can boost performance for certain queries, they may not be optimal for all scenarios. Considerations should be made based on the overall workload of the database and the variety of queries executed.&lt;/p&gt;

</description>
      <category>index</category>
      <category>sql</category>
      <category>database</category>
      <category>performance</category>
    </item>
    <item>
      <title>A Guide to Sargable Queries</title>
      <dc:creator>Arash Ariani</dc:creator>
      <pubDate>Fri, 22 Dec 2023 19:47:45 +0000</pubDate>
      <link>https://dev.to/arashariani/a-guide-to-sargable-queries-4k1f</link>
      <guid>https://dev.to/arashariani/a-guide-to-sargable-queries-4k1f</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In the vast realm of relational databases, query performance is a critical factor that can make or break the efficiency of applications. One essential concept in the pursuit of optimized queries is "sargability." Sargable, short for "Search ARGument ABLE," refers to the ability of a query to make efficient use of indexes, ultimately leading to faster and more scalable database operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Sargability
&lt;/h2&gt;

&lt;p&gt;Sargability revolves around the idea of crafting queries in a way that allows the database engine to leverage indexes effectively. The key lies in constructing queries that can take advantage of index structures, enabling the database to quickly locate and retrieve relevant data. Let's delve into the characteristics that define sargable queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct Column References
&lt;/h2&gt;

&lt;p&gt;Sargable queries often involve direct column references in the &lt;em&gt;WHERE&lt;/em&gt; clause. When a query directly references a column without applying functions or manipulations, the database engine can efficiently utilize indexes associated with that column. For instance:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Employees WHERE Salary &amp;gt; 50000;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this example, the query is sargable because it directly references the &lt;em&gt;Salary&lt;/em&gt; column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Index-Friendly Functions
&lt;/h2&gt;

&lt;p&gt;While using functions in queries is common, not all functions are &lt;strong&gt;index-friendly&lt;/strong&gt;. Sargable queries use functions that still allow the database engine to take advantage of indexes. Consider the following example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Orders WHERE DATE(OrderDate) = '2023-01-01';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The sargability of this query depends on the database's ability to optimize the use of an index on the &lt;em&gt;OrderDate&lt;/em&gt; column despite the presence of the &lt;em&gt;DATE&lt;/em&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding Function on Columns
&lt;/h2&gt;

&lt;p&gt;To maintain sargability, it's advisable to avoid applying functions directly to columns in the &lt;em&gt;WHERE&lt;/em&gt; clause whenever possible. Instead of using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Customers WHERE UPPER(CustomerName) = 'ABC COMPANY';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Customers WHERE CustomerName = 'ABC Company';&lt;/code&gt;&lt;br&gt;
This adjustment enhances the likelihood of the query being sargable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Range Queries
&lt;/h2&gt;

&lt;p&gt;Sargable queries often involve range conditions, which can efficiently use indexes. For instance:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Products WHERE Price BETWEEN 10 AND 50;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This type of query can leverage an index on the &lt;em&gt;Price&lt;/em&gt; column for optimal performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conjunctions of Sargable Expressions
&lt;/h2&gt;

&lt;p&gt;Combining multiple sargable expressions using AND typically results in a sargable query. Consider the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Employees WHERE Salary &amp;gt; 50000 AND DepartmentID = 3;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This query efficiently uses indexes on both the &lt;em&gt;Salary&lt;/em&gt; and &lt;em&gt;DepartmentID&lt;/em&gt; columns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complex Expressions
&lt;/h2&gt;

&lt;p&gt;Queries with complex expressions that involve multiple operations or calculations may not be sargable. For instance:&lt;br&gt;
&lt;code&gt;SELECT * FROM Sales WHERE Quantity * Price &amp;gt; 1000;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The multiplication of &lt;em&gt;Quantity&lt;/em&gt; and &lt;em&gt;Price&lt;/em&gt; might prevent efficient index usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using LIKE Pattern
&lt;/h2&gt;

&lt;p&gt;Queries using &lt;em&gt;LIKE&lt;/em&gt; patterns with wildcards at the beginning &lt;strong&gt;(%prefix)&lt;/strong&gt; can be non-sargable, as they require scanning the entire column. For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT * FROM Customers WHERE CustomerName LIKE '%Corp';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This query might not efficiently use an index on &lt;em&gt;CustomerName&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sargability is not just a theoretical concept; it directly influences the speed and responsiveness of applications. &lt;strong&gt;The practice of using direct column references, employing index-friendly functions, and steering clear of unnecessary manipulations on columns enables databases to harness the power of indexes effectively&lt;/strong&gt;. This, in turn, translates to faster data retrieval and enhanced overall system performance.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>index</category>
      <category>sargable</category>
      <category>query</category>
    </item>
  </channel>
</rss>
