<?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: Vishnu B</title>
    <description>The latest articles on DEV Community by Vishnu B (@vishnub33527201).</description>
    <link>https://dev.to/vishnub33527201</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F345228%2F99946c2e-f59d-4ca7-bf62-fd3ee3f2ac70.jpg</url>
      <title>DEV Community: Vishnu B</title>
      <link>https://dev.to/vishnub33527201</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vishnub33527201"/>
    <language>en</language>
    <item>
      <title>How Java Garbage Collection Works: A Quick Walkthrough</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Mon, 09 Nov 2026 12:30:16 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-java-garbage-collection-works-a-quick-walkthrough-3fa7</link>
      <guid>https://dev.to/vishnub33527201/how-java-garbage-collection-works-a-quick-walkthrough-3fa7</guid>
      <description>&lt;p&gt;Java has no &lt;code&gt;free()&lt;/code&gt; and no &lt;code&gt;delete&lt;/code&gt;. You stop referencing an object, and at some point its memory quietly comes back. Someone is doing that work: the garbage collector. Let's pin down the rule it uses, watch a real JVM collect live, and then be honest about where the JVM ends and the operating system begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule: reachability
&lt;/h2&gt;

&lt;p&gt;The collector does not count references or guess. It starts from a fixed set of entry points called &lt;strong&gt;GC roots&lt;/strong&gt; - local variables on every live thread's stack, static fields, and a few JVM internals - and walks the object graph from there. Anything it can reach stays. Everything else is garbage, even if two unreachable objects still point at each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmybt6lglu5qf7weu6ds.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmybt6lglu5qf7weu6ds.gif" alt="Animated walkthrough of mark and sweep: GC roots, reachable objects marked live, unreachable objects swept" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That animation is the classic &lt;strong&gt;mark-and-sweep&lt;/strong&gt; idea, and it is a mental model, not a literal description of any one collector: mark everything reachable from the roots, sweep away the rest. Real collectors add generations, regions, threads and concurrency on top, but reachability is the law underneath all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch a real JVM collect
&lt;/h2&gt;

&lt;p&gt;Theory is nice; logs are better. This program allocates 20 objects of ~100 KB each per round, then drops them - 6000 objects, roughly 600 MB of garbage in total, inside a heap capped at 64 MB. It also parks one object behind a &lt;code&gt;WeakReference&lt;/code&gt; so we can watch a single object die:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.ref.WeakReference&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GCDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1024&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="o"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// ~100 KB each&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;allocated&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;for&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;round&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;round&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;round&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="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;live&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&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="n"&gt;live&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;   &lt;span class="c1"&gt;// alive only inside this round&lt;/span&gt;
                &lt;span class="n"&gt;allocated&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// 'live' goes out of scope here -&amp;gt; all 20 pages become garbage&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"allocated "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;allocated&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" short-lived Page objects"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="n"&gt;p&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;Page&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;WeakReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;watcher&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;WeakReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;            &lt;span class="c1"&gt;// the only strong reference is gone&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;gc&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;         &lt;span class="c1"&gt;// a REQUEST, not a command - more below&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"after System.gc() in THIS run: watcher.get() == null -&amp;gt; "&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="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;Compiled and run on JDK 21 (Temurin 21.0.13) with GC logging on (&lt;code&gt;-Xmx64m -Xlog:gc&lt;/code&gt;). Real output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0.001s][info][gc] Using Serial
[0.034s][info][gc] GC(0) Pause Young (Allocation Failure) 9M-&amp;gt;2M(30M) 1.122ms
[0.035s][info][gc] GC(1) Pause Young (Allocation Failure) 11M-&amp;gt;2M(30M) 0.518ms
...
allocated 6000 short-lived Page objects (~600 MB total)
after System.gc() in THIS run: watcher.get() == null -&amp;gt; true
[0.067s][info][gc] GC(69) Pause Full (System.gc()) 26M-&amp;gt;2M(31M) 2.068ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read a log line like &lt;code&gt;9M-&amp;gt;2M(30M) 1.122ms&lt;/code&gt; as: heap used went from 9 MB down to 2 MB (of 30 MB currently committed), and the pause lasted about a millisecond. &lt;code&gt;(Allocation Failure)&lt;/code&gt; is the trigger's name, not an error - it means a &lt;code&gt;new&lt;/code&gt; didn't fit, so the JVM collected and then continued. The headline result: &lt;strong&gt;600 MB of objects flowed through a 64 MB heap and nothing ran out of memory.&lt;/strong&gt; The collector reclaimed each round's dead pages before the next round needed the space. That is the entire promise of GC, in one number pair.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Most objects die young" - and who collects them
&lt;/h2&gt;

&lt;p&gt;Notice the pattern in the demo: every Page is dead by the end of its loop iteration. This turns out to be the normal case in most programs, and collectors exploit it with the &lt;strong&gt;generational hypothesis&lt;/strong&gt;: collect the young part of the heap often and cheaply, because most of it is already garbage; examine long-lived objects rarely.&lt;/p&gt;

&lt;p&gt;Treat generations as a strategy, not a JVM law - how it is implemented is collector-specific. JDK 21 ships several collectors, and the &lt;a href="https://docs.oracle.com/en/java/javase/21/gctuning/available-collectors.html" rel="noopener noreferrer"&gt;official tuning guide&lt;/a&gt; says the &lt;strong&gt;serial&lt;/strong&gt; collector "uses a single thread to perform all garbage collection work" and is "selected by default on certain hardware and operating system configurations", while &lt;strong&gt;G1&lt;/strong&gt; "is selected by default on most hardware and operating system configurations". That is exactly what happened here: this small sandbox VM picked Serial (&lt;code&gt;Using Serial&lt;/code&gt; in the log), while most server-class machines get G1.&lt;/p&gt;

&lt;p&gt;Same program, one flag different (&lt;code&gt;-XX:+UseG1GC&lt;/code&gt;), real output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0.001s][info][gc] Using G1
[0.036s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 3M-&amp;gt;2M(34M) 1.013ms
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serial ran 69 young collections over the run; G1 ran 26 evacuation pauses for the same workload. Two honest caveats: these numbers are one machine, one run, one toy workload - not a benchmark and not a ranking - and G1's "evacuation" works differently inside (it copies live objects out of chosen heap regions rather than sweeping in place). The tuning guide's actual selection advice: serial for small data sets (up to ~100 MB) or single processors; G1 when "response time is more important than overall throughput and garbage collection pauses must be kept shorter"; ZGC when response time is a high priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reclaiming objects is not returning memory to the OS
&lt;/h2&gt;

&lt;p&gt;One distinction worth keeping straight: when the collector reclaims a dead object, that space returns to the &lt;strong&gt;Java heap&lt;/strong&gt;, which the JVM already owns. Whether the JVM later hands memory &lt;em&gt;back to the operating system&lt;/em&gt; is a separate decision - it depends on the collector and its flags, and the JVM is allowed to keep the memory for future allocations. So "GC freed my objects" and "my process shrank in Task Manager" are different events, and the first does not imply the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the kernel fits
&lt;/h2&gt;

&lt;p&gt;The collector itself is ordinary JVM code running in user space - marking, sweeping, and copying are memory operations inside the process, no system calls needed. But it does not float above the OS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory mapping and commit.&lt;/strong&gt; The heap sits in address space the JVM obtained from the kernel (via &lt;code&gt;mmap&lt;/code&gt; on Linux - "creates a new mapping in the virtual address space of the calling process", per the &lt;a href="https://man7.org/linux/man-pages/man2/mmap.2.html" rel="noopener noreferrer"&gt;man page&lt;/a&gt;). Growing or committing heap, and any return of memory to the OS, crosses that boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page faults.&lt;/strong&gt; Touching freshly mapped pages traps into the kernel to back them with physical memory - during allocation, inside your code and the collector's alike.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread scheduling and wakeups.&lt;/strong&gt; GC work runs on threads (dedicated GC threads, and yours during stop-the-world pauses). The OS schedules them; parking and waking threads is kernel-assisted synchronization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How much of this you feel depends on the collector and platform - a single-threaded Serial pause and G1's concurrent phases interact with the OS very differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  System.gc(), WeakReference, and why nothing here is a promise
&lt;/h2&gt;

&lt;p&gt;Two things in the demo deserve skepticism, and the docs back the skepticism. The &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/System.html#gc()" rel="noopener noreferrer"&gt;JavaDoc for System.gc()&lt;/a&gt; says calling it "suggests that the Java Virtual Machine expend effort toward recycling unused objects" and warns: "There is no guarantee that this effort will recycle any particular number of unused objects ... or complete at any particular time, if at all." A &lt;code&gt;WeakReference&lt;/code&gt; simply lets you observe the outcome: &lt;code&gt;get()&lt;/code&gt; returns the object while it lives and &lt;code&gt;null&lt;/code&gt; after the collector clears it.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;this&lt;/em&gt; run the request was honored - you can see &lt;code&gt;Pause Full (System.gc())&lt;/code&gt; in the log and the watcher went null. In another JVM, another run, or with &lt;code&gt;-XX:+DisableExplicitGC&lt;/code&gt;, neither has to happen. Treat &lt;code&gt;System.gc()&lt;/code&gt; as a hint you almost never need in production code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to take away
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reachability decides life and death&lt;/strong&gt; - from GC roots, not reference counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You almost never manage memory manually&lt;/strong&gt; - but allocation rate is real cost; every &lt;code&gt;new&lt;/code&gt; is future GC work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read your collector's log first.&lt;/strong&gt; &lt;code&gt;-Xlog:gc&lt;/code&gt; is one flag and tells you trigger, sizes, and pause time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick the collector for the workload&lt;/strong&gt; with the official guide's rules of thumb, and distrust single-run numbers - including the ones in this article, quoted as one machine's experiment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/gctuning/available-collectors.html" rel="noopener noreferrer"&gt;Java 21 GC Tuning Guide: Available Collectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.5.3" rel="noopener noreferrer"&gt;JVM Specification, 2.5.3: Heap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/System.html#gc()" rel="noopener noreferrer"&gt;Java 21 API: System.gc()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/WeakReference.html" rel="noopener noreferrer"&gt;Java 21 API: java.lang.ref.WeakReference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/mmap.2.html" rel="noopener noreferrer"&gt;Linux man-pages: mmap(2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; every code example and GC log above comes from real runs on JDK 21 (Temurin 21.0.13), and the collector counts and timings are one machine's results, not benchmarks. The animation is an illustration of mark-and-sweep as a mental model, not a trace of any specific collector.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>jvm</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How a Stack Works: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Sat, 07 Nov 2026 12:30:23 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-a-stack-works-a-quick-walkthrough-with-java-4m8i</link>
      <guid>https://dev.to/vishnub33527201/how-a-stack-works-a-quick-walkthrough-with-java-4m8i</guid>
      <description>&lt;p&gt;A browser's Back button, an undo feature, and the JVM's own method call stack all share one idea: the last thing added is the first thing removed. That structure is a stack, and it earns its name honestly - it behaves like a stack of plates. You add a plate to the top, you take a plate from the top, and you never slide one out from the middle.&lt;/p&gt;

&lt;p&gt;Let's build the browser-history version in Java, watch it run, and then go under the hood: where the stack's memory actually comes from, what the JVM's own stack does on every call, and whether the operating system's kernel is involved at all. (Spoiler: mostly not.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Just three moves
&lt;/h2&gt;

&lt;p&gt;A stack only needs three operations, all at the top:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;push&lt;/strong&gt; - put an item on top&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pop&lt;/strong&gt; - take the top item off&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;peek&lt;/strong&gt; - look at the top item without removing it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That restriction is the whole point. Because you can only touch the top, "last in, first out" (LIFO) is guaranteed - no indexing, no searching, no surprises. Here is the full life of a small browser-history stack, animated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9ohpymmpdwjoshlfvoh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9ohpymmpdwjoshlfvoh.gif" alt="Animated walkthrough of push and pop on a stack of browser pages, last in first out"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Java has a legacy &lt;code&gt;Stack&lt;/code&gt; class, but you should not use it in new code. The &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Stack.html" rel="noopener noreferrer"&gt;official JavaDoc for java.util.Stack&lt;/a&gt; says it directly: "A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class." Their own example is &lt;code&gt;Deque&amp;lt;Integer&amp;gt; stack = new ArrayDeque&amp;lt;Integer&amp;gt;();&lt;/code&gt; - and that is what we will use.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Deque&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StackDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The JDK's recommended stack: ArrayDeque used through the Deque interface&lt;/span&gt;
        &lt;span class="nc"&gt;Deque&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;history&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;ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// push: visit three pages&lt;/span&gt;
        &lt;span class="k"&gt;for&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;page&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;String&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"search"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"product"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[push] visited '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'   -&amp;gt; stack now: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// peek: look at the top without removing it&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[peek] current page is '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;peek&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'   (stack unchanged: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;history&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="c1"&gt;// pop: press the browser Back button until history is gone&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&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;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pop&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[pop]  pressed Back, left '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'   -&amp;gt; stack now: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;history&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[done] stack empty? "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" - no more pages to go back to"&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;I compiled and ran this on JDK 21 (Temurin 21.0.13) before publishing. This is the real, unedited output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[push] visited 'home'   -&amp;gt; stack now: [home]
[push] visited 'search'   -&amp;gt; stack now: [search, home]
[push] visited 'product'   -&amp;gt; stack now: [product, search, home]
[peek] current page is 'product'   (stack unchanged: [product, search, home])
[pop]  pressed Back, left 'product'   -&amp;gt; stack now: [search, home]
[pop]  pressed Back, left 'search'   -&amp;gt; stack now: [home]
[pop]  pressed Back, left 'home'   -&amp;gt; stack now: []
[done] stack empty? true - no more pages to go back to
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order flipped on the way out.&lt;/strong&gt; We pushed home, search, product - we popped product, search, home. That reversal is LIFO, and it is exactly why a stack models Back buttons and undo: the most recent action is the first one you reverse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;peek changed nothing.&lt;/strong&gt; The stack printed identically before and after. Use &lt;code&gt;peek&lt;/code&gt; when you need the current page; use &lt;code&gt;pop&lt;/code&gt; when you are leaving it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ArrayDeque&lt;/code&gt;'s &lt;code&gt;toString&lt;/code&gt; prints the top first.&lt;/strong&gt; &lt;code&gt;[product, search, home]&lt;/code&gt; reads top-to-bottom, which is handy for quick debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where the stack actually lives: the heap
&lt;/h2&gt;

&lt;p&gt;So where do those pushed strings go? The &lt;a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.5" rel="noopener noreferrer"&gt;JVM specification&lt;/a&gt; says the heap is "the run-time data area from which memory for all class instances and arrays is allocated" - one big shared region, cleaned up by the garbage collector.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ArrayDeque&lt;/code&gt; has no node objects or pointers. It keeps one plain &lt;code&gt;Object[]&lt;/code&gt; and two ints, &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt;. A &lt;code&gt;push&lt;/code&gt; (which is &lt;code&gt;addFirst&lt;/code&gt; underneath) moves &lt;code&gt;head&lt;/code&gt; one slot backward and writes your reference into that slot. That is the entire memory cost of a push: one array slot.&lt;/p&gt;

&lt;p&gt;This is private implementation detail, so I verified it with reflection instead of trusting the docs - a small program that reads the actual backing array out of a live &lt;code&gt;ArrayDeque&lt;/code&gt; (run with &lt;code&gt;--add-opens java.base/java.util=ALL-UNNAMED&lt;/code&gt;, since the module system hides these fields). Real output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new ArrayDeque&amp;lt;&amp;gt;(): one Object[] allocated on the heap, id=1528902577, length=17
push("home"):   head=16 tail=0 -&amp;gt; elements[16]=home
push x3:         head=14 tail=0 -&amp;gt; elements[head..]=product, search, home (push writes BEFORE head; same array, no new allocation)
pop():           head=15 -&amp;gt; old slot elements[14]=null (nulled so the GC can collect the string)
after 22 pushes: array id=1528902577 -&amp;gt; id=2046562095, length 17 -&amp;gt; 36
same array object? false - full array means: allocate a bigger one, copy across, drop the old one for the GC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four real behaviors, straight from the running JVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Construction allocates the deque object plus one array&lt;/strong&gt; on the heap - the object's own fields (&lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, the array reference), the array's header and 17 slots, and later whatever elements you store in it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A push is one write&lt;/strong&gt; into an existing slot - no allocation, no copying, &lt;em&gt;as long as the array has spare capacity&lt;/em&gt;. (It writes &lt;em&gt;before&lt;/em&gt; &lt;code&gt;head&lt;/code&gt;, which is why &lt;code&gt;head&lt;/code&gt; walks backward: 16, then 14. What happens when capacity runs out is the last bullet.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A pop nulls the slot it freed.&lt;/strong&gt; ArrayDeque deliberately overwrites the removed reference with &lt;code&gt;null&lt;/code&gt; so the garbage collector can reclaim the popped object even though the array still exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Growth means reallocation.&lt;/strong&gt; When the array fills, ArrayDeque allocates a bigger array, copies everything across, and abandons the old one for the GC. The definitive check in the output is &lt;code&gt;same array object? false&lt;/code&gt; - plain Java reference inequality. The identity hash change (&lt;code&gt;1528902577&lt;/code&gt; -&amp;gt; &lt;code&gt;2046562095&lt;/code&gt;) corroborates that: an object's identity hash stays constant for its lifetime, so differing hashes mean different objects (equal hashes, by contrast, would prove nothing). Either way, identity hashes are identifiers, not memory addresses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The other stack: the JVM call stack
&lt;/h2&gt;

&lt;p&gt;Your program's stack is a data structure you control. The JVM also keeps a stack of its own for every thread, and you never touch it directly. The spec: "Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames." A frame holds one method call: its local variables, its return address, and - satisfyingly - "a last-in-first-out (LIFO) stack known as its operand stack". Every Java method runs on top of a tiny private stack of its own.&lt;/p&gt;

&lt;p&gt;You can watch this without any tools beyond &lt;code&gt;javap&lt;/code&gt;. Here is the real bytecode the compiler produced for the first push in the demo above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 8: aload_1
 9: ldc           #10                 // String home
11: invokeinterface #12,  2           // InterfaceMethod java/util/Deque.push:(Ljava/lang/Object;)V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it as three moves: &lt;code&gt;aload_1&lt;/code&gt; pushes the deque reference onto main's operand stack, &lt;code&gt;ldc&lt;/code&gt; pushes the constant &lt;code&gt;"home"&lt;/code&gt; on top of it, and &lt;code&gt;invokeinterface&lt;/code&gt; consumes both to make the call - conceptually, a fresh frame for &lt;code&gt;push()&lt;/code&gt; goes onto this thread's JVM stack, and when &lt;code&gt;push&lt;/code&gt; returns, its frame pops off. Call, push frame; return, pop frame. LIFO all the way down, animated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ss4m5goij56rev3xj6x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ss4m5goij56rev3xj6x.gif" alt="Animated walkthrough of what happens inside the JVM when you call push: operand stack, a new frame on the JVM stack, and one write into the heap array"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One honest caveat: frames and operand stacks are the JVM &lt;em&gt;specification's&lt;/em&gt; conceptual model - a contract for how execution must behave, not a description of the silicon. HotSpot's JIT compiler routinely inlines small calls like this one, so at full speed there may be no separate physical frame for &lt;code&gt;push()&lt;/code&gt; at all, and operand-stack values may sit in CPU registers instead of real stack slots. The JVM only has to behave &lt;em&gt;as if&lt;/em&gt; the spec's stack exists; the optimized machine code underneath is free to cheat, invisibly. The animation above shows the spec's model, which is exactly what the bytecode means.&lt;/p&gt;

&lt;p&gt;How deep can the call stack go? The spec is blunt: "If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError." The stack size is a real, settable quantity - the &lt;code&gt;-Xss&lt;/code&gt; flag. A quick recursion experiment on this machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java StackDepth
&lt;span class="go"&gt;StackOverflowError after 10731 nested calls
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java &lt;span class="nt"&gt;-Xss256k&lt;/span&gt; StackDepth
&lt;span class="go"&gt;StackOverflowError after 3471 nested calls
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the exact counts as one machine's experiment, not a promise - they shift between runs because JIT inlining changes how much stack each frame consumes. But the pattern is the lesson: shrink the per-thread stack to 256 KB and the same recursion dies roughly three times sooner. Every frame costs real memory, and the budget is finite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the kernel get involved?
&lt;/h2&gt;

&lt;p&gt;Almost never, and it is worth being precise about this rather than vaguely saying "it goes to the OS."&lt;/p&gt;

&lt;p&gt;Everything above happens inside the JVM process, in ordinary user-space memory. A &lt;code&gt;push&lt;/code&gt; is a few writes to an array the process already owns. Creating a frame is bookkeeping inside memory the thread already has. No system call is made, so the kernel - the privileged core of the OS that manages hardware, processes, and memory - never enters the story for these operations.&lt;/p&gt;

&lt;p&gt;The kernel does appear at a few boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reserving memory.&lt;/strong&gt; When the JVM starts (or grows the heap), it asks the kernel for address space with &lt;code&gt;mmap&lt;/code&gt;, which the &lt;a href="https://man7.org/linux/man-pages/man2/mmap.2.html" rel="noopener noreferrer"&gt;Linux man page&lt;/a&gt; defines as creating "a new mapping in the virtual address space of the calling process". After that, the JVM manages that memory itself - that's why pushes don't need the kernel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page faults.&lt;/strong&gt; The first time a thread touches a freshly reserved page, the CPU traps into the kernel to actually back it with physical memory. This is invisible and automatic, not something your code requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threads and I/O.&lt;/strong&gt; Scheduling your thread onto a CPU, and any real file or network I/O, is kernel work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the kernel has its own stack, separate from everything here: when a thread &lt;em&gt;does&lt;/em&gt; enter the kernel through a system call or interrupt, the CPU switches to a small per-thread kernel stack, used only for that visit. So there are really three stacks in this story - the &lt;code&gt;ArrayDeque&lt;/code&gt; data structure on the heap, the JVM call stack of your thread, and the kernel's own stack - and a Java &lt;code&gt;push&lt;/code&gt; only ever touches the first two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two habits that save real bugs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Check before you pop.&lt;/strong&gt; Calling &lt;code&gt;pop()&lt;/code&gt; on an empty stack throws &lt;code&gt;NoSuchElementException&lt;/code&gt;. The &lt;code&gt;while (!history.isEmpty())&lt;/code&gt; guard in the demo is not decoration - it is the standard pattern. If you would rather get a signal than an exception, &lt;code&gt;poll()&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt; on an empty stack instead of throwing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Declare the type as the interface.&lt;/strong&gt; Writing &lt;code&gt;Deque&amp;lt;String&amp;gt; history = new ArrayDeque&amp;lt;&amp;gt;();&lt;/code&gt; instead of &lt;code&gt;ArrayDeque&amp;lt;String&amp;gt; history = ...&lt;/code&gt; means the rest of your code only depends on the stack operations, and you could swap the implementation later without touching it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where stacks show up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Undo/redo and browser history&lt;/strong&gt; - reverse the most recent action first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every running Java program&lt;/strong&gt; - the JVM call stack above, plus the operand stack inside each frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matching and parsing&lt;/strong&gt; - balanced brackets, HTML tags, and nested expressions are classic stack problems: push an opener, pop when you meet its closer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depth-first search&lt;/strong&gt; - DFS is a loop with a stack; &lt;a href="https://dev.to/vishnub33527201/how-binary-search-works-a-quick-walkthrough-with-java-idj"&gt;binary search&lt;/a&gt; halves a range, DFS dives down a stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three operations are O(1) - constant time, however big the stack grows. Now you also know why: each one is a pointer move plus, at most, one memory write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.5" rel="noopener noreferrer"&gt;JVM Specification, 2.5: Run-Time Data Areas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html#jvms-2.6" rel="noopener noreferrer"&gt;JVM Specification, 2.6: Frames&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Stack.html" rel="noopener noreferrer"&gt;Java 21 API: java.util.Stack (and why to prefer Deque)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ArrayDeque.html" rel="noopener noreferrer"&gt;Java 21 API: java.util.ArrayDeque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/mmap.2.html" rel="noopener noreferrer"&gt;Linux man-pages: mmap(2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; every code example above, including the reflection probe and the bytecode and recursion experiments, was compiled and run on JDK 21 (Temurin 21.0.13) before publishing, and the outputs quoted are real. Both animations are illustrations of JVM behavior, not screen recordings; the frame counts in the recursion experiment are one machine's results and will vary.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>dsa</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Kafka Works: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Fri, 06 Nov 2026 06:14:11 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-kafka-works-a-quick-walkthrough-with-java-1lai</link>
      <guid>https://dev.to/vishnub33527201/how-kafka-works-a-quick-walkthrough-with-java-1lai</guid>
      <description>&lt;p&gt;Your order service needs to tell the invoice service, the email service, and the analytics pipeline that an order happened. You could wire them together directly - but every new consumer means changing the producer, and if a consumer is down, messages get lost.&lt;/p&gt;

&lt;p&gt;Kafka takes a different approach: the producer drops the message into a durable log, and each consumer reads that log whenever it is ready, at its own pace, without the producer even knowing who they are. Let's see the whole flow working, with a real Kafka broker and a real Java client.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five pieces that matter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Topic:&lt;/strong&gt; a named stream of messages, like &lt;code&gt;greetings&lt;/code&gt;. Producers write to it, consumers read from it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition:&lt;/strong&gt; a topic is split into partitions. Each partition is an ordered, append-only log. Partitions are how Kafka scales: different consumers can read different partitions in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offset:&lt;/strong&gt; a message's position in its partition - 0, 1, 2, ... Once written, a message never changes; consumers just move forward through the offsets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Producer:&lt;/strong&gt; the app that appends messages. If you give the message a &lt;strong&gt;key&lt;/strong&gt;, the key's hash decides which partition it lands in, so all messages with the same key stay in order in the same partition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer group:&lt;/strong&gt; consumers with the same group id share the partitions between them and Kafka tracks how far each group has read.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the whole journey, animated - three messages go in, and a consumer pulls them back out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuq4sgpywj0cr393vyw3m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuq4sgpywj0cr393vyw3m.gif" alt="Animated walkthrough of a Kafka producer writing messages into a topic's partition and a consumer group reading them back by offset" width="759" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a real broker
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://kafka.apache.org/quickstart" rel="noopener noreferrer"&gt;official Kafka quickstart&lt;/a&gt; runs a single-node broker without ZooKeeper (KRaft mode) in three commands, which is exactly what I did - this article's output is from Apache Kafka 4.4.0 on JDK 21:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. generate a cluster id&lt;/span&gt;
&lt;span class="nv"&gt;KAFKA_CLUSTER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;bin/kafka-storage.sh random-uuid&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 2. format the log directories&lt;/span&gt;
bin/kafka-storage.sh format &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$KAFKA_CLUSTER_ID&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; config/server.properties

&lt;span class="c"&gt;# 3. start the broker&lt;/span&gt;
bin/kafka-server-start.sh config/server.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Startup logged &lt;code&gt;Kafka Server started (kafka.server.KafkaRaftServer)&lt;/code&gt;, and the broker was ready on &lt;code&gt;localhost:9092&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Java producer and consumer in one file
&lt;/h2&gt;

&lt;p&gt;This complete program creates a topic with 3 partitions, produces 3 keyed messages, and reads them back. It uses only the &lt;code&gt;kafka-clients&lt;/code&gt; jar that ships in the Kafka download's &lt;code&gt;libs&lt;/code&gt; folder - no extra dependencies:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.admin.AdminClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.admin.NewTopic&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.consumer.ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.consumer.ConsumerRecords&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.consumer.KafkaConsumer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.producer.KafkaProducer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.producer.ProducerConfig&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.clients.producer.ProducerRecord&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.kafka.common.serialization.StringSerializer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Properties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaWalkthrough&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;TOPIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"greetings"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;createTopic&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;produce&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;consume&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createTopic&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;p&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;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bootstrap.servers"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:9092"&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="nc"&gt;AdminClient&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AdminClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTopics&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NewTopic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TOPIC&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="kt"&gt;short&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="na"&gt;all&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="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[setup] created topic '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;TOPIC&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' with 3 partitions"&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="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;produce&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;p&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;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProducerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BOOTSTRAP_SERVERS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProducerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;KEY_SERIALIZER_CLASS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringSerializer&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="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProducerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VALUE_SERIALIZER_CLASS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringSerializer&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="na"&gt;getName&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="nc"&gt;KafkaProducer&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;,&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;producer&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;KafkaProducer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[][]&lt;/span&gt; &lt;span class="n"&gt;msgs&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="s"&gt;"vishnu"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hello kafka"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"asha"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"kafka is a log"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"ravi"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"partitions scale reads"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
            &lt;span class="o"&gt;};&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msgs&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&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;ProducerRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="no"&gt;TOPIC&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&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;m&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="na"&gt;get&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;"[producer] sent key=%s value='%s' -&amp;gt; partition=%d offset=%d%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;m&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;m&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;partition&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offset&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="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;p&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;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BOOTSTRAP_SERVERS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GROUP_ID_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"walkthrough-group"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;KEY_DESERIALIZER_CLASS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringDeserializer&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="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VALUE_DESERIALIZER_CLASS_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringDeserializer&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="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTO_OFFSET_RESET_CONFIG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"earliest"&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="nc"&gt;KafkaConsumer&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;,&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;consumer&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;KafkaConsumer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subscribe&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="no"&gt;TOPIC&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;got&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="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;deadline&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;ConsumerRecords&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;,&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;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;poll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMillis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
                &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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;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;"[consumer] read key=%s value='%s' from partition=%d offset=%d%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;partition&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="o"&gt;});&lt;/span&gt;
                &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I compiled it with &lt;code&gt;javac -cp "libs/*" KafkaWalkthrough.java&lt;/code&gt; and ran it against the live broker. This is the real, unedited output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[setup] created topic 'greetings' with 3 partitions
[producer] sent key=vishnu value='hello kafka' -&amp;gt; partition=0 offset=0
[producer] sent key=asha value='kafka is a log' -&amp;gt; partition=0 offset=1
[producer] sent key=ravi value='partitions scale reads' -&amp;gt; partition=0 offset=2
[consumer] read key=vishnu value='hello kafka' from partition=0 offset=0
[consumer] read key=asha value='kafka is a log' from partition=0 offset=1
[consumer] read key=ravi value='partitions scale reads' from partition=0 offset=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four honest observations from that output:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;All three keys hashed to partition 0.&lt;/strong&gt; With only three partitions and three keys, that is chance, not a rule - other keys land in partitions 1 and 2. The guarantee is narrower: the &lt;em&gt;same&lt;/em&gt; key always goes to the &lt;em&gt;same&lt;/em&gt; partition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offsets count up within a partition.&lt;/strong&gt; 0, 1, 2 - the append-only log in action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The consumer replayed history.&lt;/strong&gt; The producer had already finished and exited when the consumer started. Nothing was lost, because the topic &lt;em&gt;stores&lt;/em&gt; messages; &lt;code&gt;AUTO_OFFSET_RESET_CONFIG = "earliest"&lt;/code&gt; told the new consumer group to start from offset 0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order is per-partition.&lt;/strong&gt; The consumer got the messages in offset order. Across partitions there is no global order - another reason keys matter when order matters.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When Kafka is the right tool
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling services:&lt;/strong&gt; the producer does not know or care who consumes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buffering bursts:&lt;/strong&gt; consumers catch up after a spike or an outage instead of dropping work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple independent readers:&lt;/strong&gt; analytics, email, and search can each have their own consumer group over the same topic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay:&lt;/strong&gt; because messages persist, a new service can rebuild its state by reading from offset 0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is more machinery than a plain queue, so for one producer talking to one consumer with no replay needs, a simpler tool can be the better call. Kafka earns its keep when the log itself - durable, ordered per partition, readable by many groups - is what you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kafka.apache.org/intro" rel="noopener noreferrer"&gt;Apache Kafka documentation: introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kafka.apache.org/quickstart" rel="noopener noreferrer"&gt;Apache Kafka quickstart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run against a real single-node Kafka 4.4.0 broker on JDK 21 before publishing. The animation is an illustration of the message flow, not a screen recording.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>kafka</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How a Spring Boot Request Travels: A Quick Walkthrough</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Thu, 05 Nov 2026 12:30:26 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-a-spring-boot-request-travels-a-quick-walkthrough-b94</link>
      <guid>https://dev.to/vishnub33527201/how-a-spring-boot-request-travels-a-quick-walkthrough-b94</guid>
      <description>&lt;p&gt;You type a URL, hit enter, and JSON comes back. Between those two moments, your Spring Boot app runs a small relay race: the request passes through an embedded web server, a front controller, and a few helpers before your code ever runs. Once you can picture that path, debugging gets much easier - a 404, a missing parameter, and a broken interceptor all fail at &lt;em&gt;different stops&lt;/em&gt; on the same road.&lt;/p&gt;

&lt;p&gt;Let's follow one GET request end to end, with a real app you can run yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five stops
&lt;/h2&gt;

&lt;p&gt;Here is the whole journey, animated. Watch the request packet travel from the client to the controller and the response come back:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3a2fv4rblvgofurzjisr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3a2fv4rblvgofurzjisr.gif" alt="Animated walkthrough of an HTTP request traveling through embedded Tomcat, the DispatcherServlet, an interceptor and the controller, then back as JSON" width="759" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In plain words:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The client sends the request.&lt;/strong&gt; A browser, curl, or another service sends &lt;code&gt;GET /api/greet?name=Vishnu&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The embedded server accepts it.&lt;/strong&gt; Spring Boot runs its own web server inside the app. Per the &lt;a href="https://docs.spring.io/spring-boot/reference/web/servlet.html" rel="noopener noreferrer"&gt;Spring Boot reference&lt;/a&gt;, "Spring Boot includes support for embedded Tomcat and Jetty servers", and by default it "listens for HTTP requests on port 8080". No separate server install - &lt;code&gt;main()&lt;/code&gt; starts everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The DispatcherServlet takes over.&lt;/strong&gt; Spring MVC is "designed around the front controller pattern where a central Servlet, the DispatcherServlet, provides a shared algorithm for request processing, while actual work is performed by configurable delegate components" (&lt;a href="https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet.html" rel="noopener noreferrer"&gt;Spring Framework docs&lt;/a&gt;). In practice: one servlet receives everything, then looks up which &lt;code&gt;@GetMapping&lt;/code&gt; matches the path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interceptors get a look.&lt;/strong&gt; Before and after your controller, interceptors can inspect or reject the request - good for logging, auth checks, and timing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your controller runs.&lt;/strong&gt; The method returns data, Spring converts it to JSON, and the response travels back out the way it came.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A real app that shows its own journey
&lt;/h2&gt;

&lt;p&gt;This is a complete Spring Boot app. The interceptor and controller print a line at each stop, so the server's own log narrates the relay:&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.reqdemo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.servlet.http.HttpServletRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.servlet.http.HttpServletResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.SpringApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.autoconfigure.SpringBootApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.GetMapping&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RequestParam&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RestController&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.servlet.HandlerInterceptor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.servlet.config.annotation.InterceptorRegistry&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.servlet.config.annotation.WebMvcConfigurer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

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

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReqDemoApplication&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="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@RestController&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/greet"&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;Map&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;,&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="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"world"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller] DispatcherServlet handed me GET /api/greet, name="&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="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Map&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;"message"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, "&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="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;span class="nd"&gt;@Component&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlowInterceptor&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HandlerInterceptor&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;preHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;handler&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[interceptor] request passed the servlet and filters: "&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethod&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;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequestURI&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;true&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;void&lt;/span&gt; &lt;span class="nf"&gt;afterCompletion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[interceptor] response written, status="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" - request journey complete"&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="nd"&gt;@Component&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebConfig&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;WebMvcConfigurer&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;FlowInterceptor&lt;/span&gt; &lt;span class="n"&gt;interceptor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;WebConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FlowInterceptor&lt;/span&gt; &lt;span class="n"&gt;interceptor&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;interceptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;interceptor&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;void&lt;/span&gt; &lt;span class="nf"&gt;addInterceptors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterceptorRegistry&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInterceptor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interceptor&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I compiled and ran this on JDK 21 (Temurin 21.0.13) with Spring Boot 3.5.7 before publishing. Here is the real, unedited output.&lt;/p&gt;

&lt;p&gt;Startup - the embedded Tomcat coming up inside the app (port 8090 here, because 8080 was already in use in the run environment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tomcat initialized with port 8090 (http)
Tomcat started on port 8090 (http) with context path '/'
Started ReqDemoApplication in 1.054 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;curl http://localhost:8090/api/greet?name=Vishnu&lt;/code&gt; returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Hello, Vishnu!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the app's own log narrated the journey, exactly in the order of the animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[interceptor] request passed the servlet and filters: GET /api/greet
[controller] DispatcherServlet handed me GET /api/greet, name=Vishnu
[interceptor] response written, status=200 - request journey complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The interceptor's &lt;code&gt;preHandle&lt;/code&gt; runs &lt;strong&gt;before&lt;/strong&gt; the controller, and &lt;code&gt;afterCompletion&lt;/code&gt; runs &lt;strong&gt;after&lt;/strong&gt; the response is written. Your controller is the middle of the sandwich, not the start.&lt;/li&gt;
&lt;li&gt;Returning a &lt;code&gt;Map&lt;/code&gt; was enough to get JSON. Spring Boot auto-configures an HTTP message converter that serializes the return value - you never wrote JSON yourself.&lt;/li&gt;
&lt;li&gt;The journey back through the server is mostly invisible to your code, which is why the interceptor's completion callback is a handy place to log it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A 404 travels the same road
&lt;/h2&gt;

&lt;p&gt;One detail that surprises people: an unknown path goes through the same pipeline. Calling &lt;code&gt;curl http://localhost:8090/api/nope&lt;/code&gt; produced this log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[interceptor] request passed the servlet and filters: GET /api/nope
[interceptor] response written, status=404 - request journey complete
[interceptor] request passed the servlet and filters: GET /error
[interceptor] response written, status=404 - request journey complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two journeys for one request. The DispatcherServlet found no mapping for &lt;code&gt;/api/nope&lt;/code&gt;, so it raised an error, and the servlet container then dispatched the request &lt;em&gt;again&lt;/em&gt;, this time to Spring Boot's built-in &lt;code&gt;/error&lt;/code&gt; endpoint - which is what generated the JSON error body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2026-11-05T10:56:56.906+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Not Found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/api/nope"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when you debug a 404, the first question is: did the request reach the DispatcherServlet at all? If your interceptor logged it, the server side is fine and the path or mapping is wrong. If it did not, the problem is earlier - wrong port, wrong context path, or something in front of the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this mental model pays off
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debugging 404s and 405s:&lt;/strong&gt; find out which stop rejected the request instead of guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Placing cross-cutting logic:&lt;/strong&gt; auth checks, request IDs, and timing belong in interceptors or filters, not copied into every controller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading startup logs:&lt;/strong&gt; &lt;code&gt;Tomcat started on port ...&lt;/code&gt; tells you the embedded server is the entry point, and it is part of your app's process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If &lt;a href="https://dev.to/vishnub33527201/how-dependency-injection-works-in-spring-boot-a-quick-walkthrough-1lhg"&gt;dependency injection&lt;/a&gt; is how your beans find each other, the DispatcherServlet is how the outside world finds your beans. Both are quiet machinery that runs before your code does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet.html" rel="noopener noreferrer"&gt;Spring Framework reference: DispatcherServlet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/reference/web/servlet.html" rel="noopener noreferrer"&gt;Spring Boot reference: Embedded web servers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing. The animation is an illustration of the request flow, not a screen recording.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Binary Search Works: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Tue, 03 Nov 2026 12:30:27 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-binary-search-works-a-quick-walkthrough-with-java-idj</link>
      <guid>https://dev.to/vishnub33527201/how-binary-search-works-a-quick-walkthrough-with-java-idj</guid>
      <description>&lt;p&gt;Imagine you are looking for a word in a paper dictionary. You would not start at page 1 and flip one page at a time. You open it near the middle, see whether your word comes before or after that page, and throw away the half that cannot contain it. A few more halvings and you are on the right page.&lt;/p&gt;

&lt;p&gt;That is binary search. It is one of the most useful algorithms to know, and Java ships it built in. Let's walk through exactly how it works, step by step, with real code and real output.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule: the data must be sorted
&lt;/h2&gt;

&lt;p&gt;Binary search only works on a &lt;strong&gt;sorted&lt;/strong&gt; collection. Sorting is what makes the "throw away half" trick safe: if the middle value is smaller than your target, every value to the left of it is also smaller, so none of them can be the target.&lt;/p&gt;

&lt;p&gt;On a sorted array, the algorithm is three simple steps, repeated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look at the &lt;strong&gt;middle&lt;/strong&gt; element of the current range.&lt;/li&gt;
&lt;li&gt;If it equals the target, you are done.&lt;/li&gt;
&lt;li&gt;If it is smaller, the target must be in the &lt;strong&gt;right half&lt;/strong&gt;. If it is larger, the target must be in the &lt;strong&gt;left half&lt;/strong&gt;. Repeat on that half only.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the whole search for the value &lt;code&gt;61&lt;/code&gt; in a 12-element sorted array, animated. Watch the &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; markers close in as each probe eliminates half of what is left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flyubr88iet5sl7ihbjic.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flyubr88iet5sl7ihbjic.gif" alt="Animated walkthrough of binary search halving a sorted array until it finds the target" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four probes found the answer. A plain left-to-right scan could have taken up to twelve.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same search in Java
&lt;/h2&gt;

&lt;p&gt;Here is a complete, runnable version. It prints every probe so you can see the range shrink:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Arrays&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BinarySearchDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;binarySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;low&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;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&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="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// middle index, overflow-safe&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;"step %d: low=%d high=%d mid=%d -&amp;gt; a[%d]=%d%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&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;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"found "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" at index "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mid&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;mid&lt;/span&gt;&lt;span class="o"&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;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// target is in the right half&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;// target is in the left half&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;step&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" is not in the array"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="o"&gt;};&lt;/span&gt;
        &lt;span class="n"&gt;binarySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;binarySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="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;I compiled and ran this on JDK 21 (Temurin 21.0.13) before publishing. This is the real, unedited output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;step 1: low=0 high=11 mid=5 -&amp;gt; a[5]=42
step 2: low=6 high=11 mid=8 -&amp;gt; a[8]=78
step 3: low=6 high=7 mid=6 -&amp;gt; a[6]=55
step 4: low=7 high=7 mid=7 -&amp;gt; a[7]=61
found 61 at index 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for a value that is not in the array, &lt;code&gt;30&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;step 1: low=0 high=11 mid=5 -&amp;gt; a[5]=42
step 2: low=0 high=4 mid=2 -&amp;gt; a[2]=15
step 3: low=3 high=4 mid=3 -&amp;gt; a[3]=21
step 4: low=4 high=4 mid=4 -&amp;gt; a[4]=34
30 is not in the array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few small things in the code are worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(low + high) &amp;gt;&amp;gt;&amp;gt; 1&lt;/code&gt; is the average of &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt;, computed in a way that avoids integer overflow on very large arrays. &lt;code&gt;(low + high) / 2&lt;/code&gt; works for small arrays too.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;while (low &amp;lt;= high)&lt;/code&gt; keeps going while the range still has elements. When &lt;code&gt;low&lt;/code&gt; passes &lt;code&gt;high&lt;/code&gt;, the range is empty and the target is not there.&lt;/li&gt;
&lt;li&gt;After each probe we move one marker &lt;strong&gt;past&lt;/strong&gt; the middle (&lt;code&gt;mid + 1&lt;/code&gt; or &lt;code&gt;mid - 1&lt;/code&gt;), because we just checked &lt;code&gt;mid&lt;/code&gt; itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  You usually do not write this by hand
&lt;/h2&gt;

&lt;p&gt;The JDK already ships binary search: &lt;code&gt;Arrays.binarySearch&lt;/code&gt; for arrays and &lt;code&gt;Collections.binarySearch&lt;/code&gt; for lists. The &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Arrays.html" rel="noopener noreferrer"&gt;official Java 21 documentation&lt;/a&gt; states the two rules that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"The array must be sorted ... prior to making this call. If it is not sorted, the results are undefined."&lt;/strong&gt; Undefined means the method will not throw an error to warn you; it can simply return a wrong answer.&lt;/li&gt;
&lt;li&gt;The return value is &lt;strong&gt;"index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1)"&lt;/strong&gt;. So a negative result means "not found", and the exact negative number tells you where the value &lt;em&gt;would&lt;/em&gt; sit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running the built-in against the same array confirms both rules:&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;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;binarySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;binarySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-5&lt;/code&gt; decodes like this: insertion point is &lt;code&gt;4&lt;/code&gt; (30 would belong at index 4), and the documented formula gives &lt;code&gt;-(4) - 1 = -5&lt;/code&gt;. A negative result is never a valid index, so checking &lt;code&gt;result &amp;gt;= 0&lt;/code&gt; is all you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it is fast
&lt;/h2&gt;

&lt;p&gt;Every probe discards half of what remains, so the number of steps grows with the &lt;strong&gt;logarithm&lt;/strong&gt; of the size, not the size itself:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;elements&lt;/th&gt;
&lt;th&gt;worst-case probes (binary)&lt;/th&gt;
&lt;th&gt;worst-case checks (linear)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000,000&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;1,000,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is why binary search is described as &lt;strong&gt;O(log n)&lt;/strong&gt; time and why sorting your data once can pay off when you search it many times. It needs O(1) extra space when written iteratively, as above.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to reach for it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The data is &lt;strong&gt;already sorted&lt;/strong&gt;, or sorted once and searched often.&lt;/li&gt;
&lt;li&gt;You need a plain value lookup in an array or list.&lt;/li&gt;
&lt;li&gt;The data is unsorted and searched rarely: just do a linear scan, or sort first if you can.&lt;/li&gt;
&lt;li&gt;You need frequent inserts and lookups together: a &lt;code&gt;HashMap&lt;/code&gt; (covered in &lt;a href="https://dev.to/vishnub33527201/how-a-hashmap-works-a-quick-walkthrough-with-java-1323"&gt;an earlier walkthrough&lt;/a&gt;) or a &lt;code&gt;TreeSet&lt;/code&gt; is usually a better fit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Arrays.html" rel="noopener noreferrer"&gt;Java 21 API: Arrays.binarySearch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collections.html" rel="noopener noreferrer"&gt;Java 21 API: Collections.binarySearch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing. The animation is an illustration of the algorithm's flow, not a screen recording.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>dsa</category>
      <category>algorithms</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Dependency Injection Works in Spring Boot: A Quick Walkthrough</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:32:27 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-dependency-injection-works-in-spring-boot-a-quick-walkthrough-1lhg</link>
      <guid>https://dev.to/vishnub33527201/how-dependency-injection-works-in-spring-boot-a-quick-walkthrough-1lhg</guid>
      <description>&lt;p&gt;If you have written any Spring Boot code, you have seen this: a class asks for another class in its constructor, and somehow the right object is just there. Nobody called &lt;code&gt;new&lt;/code&gt;. Nobody looked anything up. Let's see who does that work, with plain words and a tiny Spring Boot app you can run yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea in one minute
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You mark classes with annotations like &lt;code&gt;@Service&lt;/code&gt; or &lt;code&gt;@Component&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When the app starts, Spring Boot scans your code and creates an object of each one. These managed objects are called &lt;strong&gt;beans&lt;/strong&gt;, and they live in the &lt;strong&gt;Spring container&lt;/strong&gt; (the &lt;code&gt;ApplicationContext&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;When a bean's constructor asks for another bean, the container passes it in. That passing-in is &lt;strong&gt;dependency injection&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Spring documentation calls this Inversion of Control: instead of your object building or finding its own helpers, the container creates them and hands them over. Your class just declares what it needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch the flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frksdnq1mfs874mh3sgjl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frksdnq1mfs874mh3sgjl.gif" alt="Animation: Spring Boot scans the classes, creates the beans, injects GreetingService into WelcomeRunner, and run() uses it" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The animation follows the real program below: &lt;code&gt;main()&lt;/code&gt; hands control to Spring Boot, the scan finds the two annotated classes, the container creates the &lt;code&gt;GreetingService&lt;/code&gt; bean, creates &lt;code&gt;WelcomeRunner&lt;/code&gt; while injecting &lt;code&gt;GreetingService&lt;/code&gt; into its constructor, and &lt;code&gt;run()&lt;/code&gt; uses the injected bean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it yourself
&lt;/h2&gt;

&lt;p&gt;A complete Spring Boot app in one file (run with &lt;code&gt;mvn compile exec:java -Dexec.mainClass=com.example.di.DiDemoApplication&lt;/code&gt; in a project with the &lt;code&gt;spring-boot-starter&lt;/code&gt; dependency, Spring Boot 3.5.7):&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.di&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.CommandLineRunner&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.SpringApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.autoconfigure.SpringBootApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.stereotype.Service&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

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

    &lt;span class="c1"&gt;// 1. A bean the container will create and manage&lt;/span&gt;
    &lt;span class="nd"&gt;@Service&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;GreetingService&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[container] created bean: GreetingService"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello, "&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="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;span class="c1"&gt;// 2. A bean that NEEDS a GreetingService: constructor injection&lt;/span&gt;
    &lt;span class="nd"&gt;@Component&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WelcomeRunner&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;CommandLineRunner&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;GreetingService&lt;/span&gt; &lt;span class="n"&gt;greetingService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;WelcomeRunner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GreetingService&lt;/span&gt; &lt;span class="n"&gt;greetingService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// container injects it here&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;greetingService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;greetingService&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[container] injected GreetingService into WelcomeRunner"&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;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;args&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[app] WelcomeRunner.run() called with the injected bean"&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[app] "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;greetingService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Spring Boot"&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[you] main(): handing control to SpringApplication.run()"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DiDemoApplication&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="n"&gt;args&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[you] main(): container shut down"&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;h2&gt;
  
  
  What it actually printed (Spring Boot 3.5.7, Java 21)
&lt;/h2&gt;

&lt;p&gt;Real run, startup banner and framework log lines trimmed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[you] main(): handing control to SpringApplication.run()
:: Spring Boot ::                (v3.5.7)
... Starting DiDemoApplication using Java 21.0.13 ...
[container] created bean: GreetingService
[container] injected GreetingService into WelcomeRunner
... Started DiDemoApplication in 0.774 seconds ...
[app] WelcomeRunner.run() called with the injected bean
[app] Hello, Spring Boot!
[you] main(): container shut down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it in order and you can see the handoff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your &lt;code&gt;main()&lt;/code&gt; does exactly one thing: start the container.&lt;/li&gt;
&lt;li&gt;The container's log lines come &lt;strong&gt;before&lt;/strong&gt; the app's: it creates &lt;code&gt;GreetingService&lt;/code&gt;, then builds &lt;code&gt;WelcomeRunner&lt;/code&gt; and passes the service into the constructor. All before "Started DiDemoApplication".&lt;/li&gt;
&lt;li&gt;Only then does &lt;code&gt;run()&lt;/code&gt; execute, already holding a ready-to-use bean. &lt;code&gt;CommandLineRunner&lt;/code&gt; is just Spring Boot's way of saying "call this once everything is wired up".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the docs add
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two ways to inject.&lt;/strong&gt; The Spring Framework docs describe constructor-based and setter-based DI. The rule of thumb they give: constructors for mandatory dependencies, setters for optional ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructor injection is the recommended style.&lt;/strong&gt; The Spring team advocates it because components stay immutable, required dependencies can never be &lt;code&gt;null&lt;/code&gt;, and the object is always fully initialized when you get it. The Spring Boot docs give the same advice: use constructor injection plus &lt;code&gt;@ComponentScan&lt;/code&gt;, which &lt;code&gt;@SpringBootApplication&lt;/code&gt; already includes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It pays off in tests.&lt;/strong&gt; Because your class receives its helpers instead of building them, a test can hand it a stub or mock instead of the real thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest caveat: the container does much more than this tiny demo shows (scopes, lazy init, configuration properties, proxies). But the core loop you saw above - scan, create, inject, use - is the part everything else builds on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html" rel="noopener noreferrer"&gt;Dependency Injection - Spring Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/reference/using/spring-beans-and-dependency-injection.html" rel="noopener noreferrer"&gt;Spring Beans and Dependency Injection - Spring Boot Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on Spring Boot 3.5.7 with JDK 21 before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How a HashMap Works: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Fri, 30 Oct 2026 12:31:05 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/how-a-hashmap-works-a-quick-walkthrough-with-java-1323</link>
      <guid>https://dev.to/vishnub33527201/how-a-hashmap-works-a-quick-walkthrough-with-java-1323</guid>
      <description>&lt;p&gt;You probably used a HashMap today without thinking about it. But what actually happens when you call &lt;code&gt;map.put("apple", 3)&lt;/code&gt;? Let's open the box, with plain words and a small Java program you can run yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea in one minute
&lt;/h2&gt;

&lt;p&gt;A HashMap is an array of buckets. When you store something:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The key goes through &lt;code&gt;hashCode()&lt;/code&gt;, which turns it into a number.&lt;/li&gt;
&lt;li&gt;That number is reduced to a bucket index (in our model: &lt;code&gt;hash % 8&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The key and value are stored in that bucket.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two different keys can land on the same bucket. That is a &lt;strong&gt;collision&lt;/strong&gt;, and the bucket simply keeps them as a small chain. Finding a value means: hash the key, jump to the bucket, walk the short chain comparing keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch the flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcur4oyo1khff50phagi0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcur4oyo1khff50phagi0.gif" alt="Animation: a key is hashed to a bucket, a colliding key joins the bucket chain, and a lookup walks the chain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The animation walks three moments: storing &lt;code&gt;apple&lt;/code&gt; in an empty bucket, storing &lt;code&gt;mango&lt;/code&gt; which collides with &lt;code&gt;apple&lt;/code&gt; and joins its chain, then finding &lt;code&gt;apple&lt;/code&gt; again by walking that chain. (It shows a simplified 8-bucket teaching model - the same one the code below runs.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it yourself
&lt;/h2&gt;

&lt;p&gt;This tiny hash map prints every step, so you can see the hashing, the bucket choice, the collision and the chain walk:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.HashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HashMapDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// A tiny hand-rolled hash map so we can watch every step&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleHashMap&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;BUCKETS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&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;key&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;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;Node&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;k&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;v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&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="n"&gt;v&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="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;table&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;Node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="no"&gt;BUCKETS&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;bucketIndex&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;key&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="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7fffffff&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="no"&gt;BUCKETS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;put&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;key&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;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bucketIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&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;n&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&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;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"put("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&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;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") -&amp;gt; bucket "&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="s"&gt;": key exists, value overwritten"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;n&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;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;return&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="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;n&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;Node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&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;table&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="n"&gt;n&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"put("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&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;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") -&amp;gt; hash "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7fffffff&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" -&amp;gt; bucket "&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="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;" (collision: added to chain)"&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="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;get&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;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bucketIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;steps&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;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&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;n&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;steps&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;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") -&amp;gt; bucket "&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="s"&gt;", found after "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" step(s): "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&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="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") -&amp;gt; bucket "&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="s"&gt;": not in chain, returns null"&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printTable&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\nFinal table ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;BUCKETS&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" buckets):"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;BUCKETS&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="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;sb&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;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bucket "&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="s"&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;table&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="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"(empty)"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&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;n&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&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="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&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;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;endsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" -&amp;gt; "&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLength&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sb&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SimpleHashMap&lt;/span&gt; &lt;span class="n"&gt;map&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;SimpleHashMap&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dog"&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="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&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="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"banana"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mango"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// same key again: overwrite&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printTable&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;println&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;map&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="s"&gt;"dog"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;map&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="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;map&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="s"&gt;"zebra"&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n-- The real java.util.HashMap --"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;HashMap&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;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;real&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;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dog"&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="n"&gt;real&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&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="n"&gt;real&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// null key is allowed&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"real.get(\"cat\") = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;real&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="s"&gt;"cat"&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"real.get(null) = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;real&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="kc"&gt;null&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iteration order: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keySet&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"  (not guaranteed, do not rely on it)"&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;h2&gt;
  
  
  What it actually printed (JDK 21)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;put(cat, 1) -&amp;gt; hash 98262 -&amp;gt; bucket 6
put(dog, 2) -&amp;gt; hash 99644 -&amp;gt; bucket 4
put(apple, 3) -&amp;gt; hash 93029210 -&amp;gt; bucket 2
put(banana, 4) -&amp;gt; hash 751128421 -&amp;gt; bucket 5
put(mango, 5) -&amp;gt; hash 103662530 -&amp;gt; bucket 2 (collision: added to chain)
put(cat, 9) -&amp;gt; bucket 6: key exists, value overwritten

Final table (8 buckets):
bucket 0: (empty)
bucket 1: (empty)
bucket 2: mango=5 -&amp;gt; apple=3
bucket 3: (empty)
bucket 4: dog=2
bucket 5: banana=4
bucket 6: cat=9
bucket 7: (empty)

get(dog) -&amp;gt; bucket 4, found after 1 step(s): 2
get(apple) -&amp;gt; bucket 2, found after 2 step(s): 3
get(zebra) -&amp;gt; bucket 6: not in chain, returns null

-- The real java.util.HashMap --
real.get("cat") = 1
real.get(null) = 99
iteration order: [null, apple, cat, dog]  (not guaranteed, do not rely on it)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mango&lt;/code&gt; and &lt;code&gt;apple&lt;/code&gt; both hash to bucket 2, so they sit in one chain. &lt;code&gt;get("apple")&lt;/code&gt; checks &lt;code&gt;mango&lt;/code&gt; first, then finds &lt;code&gt;apple&lt;/code&gt; on step 2.&lt;/li&gt;
&lt;li&gt;Storing &lt;code&gt;cat&lt;/code&gt; again does not add a second entry; it overwrites the value (1 becomes 9).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zebra&lt;/code&gt; hashes to bucket 6, which holds &lt;code&gt;cat&lt;/code&gt;. The map walks that chain, finds no match, and returns &lt;code&gt;null&lt;/code&gt; - a wrong bucket is never even looked at.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real HashMap adds a few upgrades
&lt;/h2&gt;

&lt;p&gt;Our 8-bucket model keeps the moving parts visible. Per the &lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/HashMap.html" rel="noopener noreferrer"&gt;Java 21 HashMap documentation&lt;/a&gt;, the real one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gives &lt;strong&gt;constant-time&lt;/strong&gt; &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;put&lt;/code&gt;, assuming the hash function spreads keys well across buckets.&lt;/li&gt;
&lt;li&gt;Grows automatically: when entries exceed &lt;strong&gt;capacity x load factor&lt;/strong&gt; (default 0.75), it rehashes to roughly twice the buckets.&lt;/li&gt;
&lt;li&gt;Permits one &lt;code&gt;null&lt;/code&gt; key and any number of &lt;code&gt;null&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;Makes &lt;strong&gt;no order guarantees&lt;/strong&gt; - do not rely on iteration order.&lt;/li&gt;
&lt;li&gt;Is &lt;strong&gt;not synchronized&lt;/strong&gt;; for concurrent access wrap it with &lt;code&gt;Collections.synchronizedMap&lt;/code&gt; (or use a concurrent map).&lt;/li&gt;
&lt;li&gt;Can use comparison order to break ties when many keys share a hash code (in practice, very long chains are turned into trees to keep lookups fast).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/HashMap.html" rel="noopener noreferrer"&gt;HashMap (Java SE 21 &amp;amp; JDK 21)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Object.html#hashCode()" rel="noopener noreferrer"&gt;Object.hashCode() (Java SE 21 &amp;amp; JDK 21)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>dsa</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>AWS IAM Policy Evaluation: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Wed, 28 Oct 2026 12:30:16 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/aws-iam-policy-evaluation-a-quick-walkthrough-with-java-1gap</link>
      <guid>https://dev.to/vishnub33527201/aws-iam-policy-evaluation-a-quick-walkthrough-with-java-1gap</guid>
      <description>&lt;h1&gt;
  
  
  AWS IAM Policy Evaluation: A Quick Walkthrough with Java
&lt;/h1&gt;

&lt;p&gt;"Why is my S3 request denied? I literally have an Allow for it." If you have worked with AWS for more than a week, you have hit this. Getting unstuck starts with how IAM evaluates policies - and while the full evaluation has several layers, the core rules are simpler than they feel once you see them in code.&lt;/p&gt;

&lt;p&gt;In this walkthrough we will look at three rules at the core of identity-based policy evaluation inside a single AWS account, then simulate them in a small Java program you can run yourself. This is a simplified identity-policy example, not the full IAM evaluation: the real engine also layers in resource-based policies, permissions boundaries, Organizations SCPs/RCPs, session policies, and conditions, which this demo intentionally leaves out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three rules (single account)
&lt;/h2&gt;

&lt;p&gt;Per the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html" rel="noopener noreferrer"&gt;AWS policy evaluation logic docs&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;By default, everything is denied (implicit deny).&lt;/strong&gt; If no statement matches your request with an &lt;code&gt;Allow&lt;/code&gt;, the answer is no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An explicit &lt;code&gt;Allow&lt;/code&gt; overrides the default.&lt;/strong&gt; Match a statement with &lt;code&gt;Effect: Allow&lt;/code&gt; and the request goes through...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;...unless an explicit &lt;code&gt;Deny&lt;/code&gt; matches.&lt;/strong&gt; An explicit deny in any applicable policy overrides any allow. Always.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For an IAM user or role inside one account, AWS takes the union of identity-based policies and resource-based policies: if either allows the action and nothing explicitly denies it, the request is allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A policy is just JSON
&lt;/h2&gt;

&lt;p&gt;From the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html" rel="noopener noreferrer"&gt;IAM JSON policy element reference&lt;/a&gt;, the pieces that matter for evaluation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Effect&lt;/code&gt; - &lt;code&gt;Allow&lt;/code&gt; or &lt;code&gt;Deny&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Action&lt;/code&gt; - what is being requested, e.g. &lt;code&gt;s3:GetObject&lt;/code&gt;. Wildcards like &lt;code&gt;s3:Get*&lt;/code&gt; are allowed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Resource&lt;/code&gt; - the ARN the action applies to, also wildcard-friendly, e.g. &lt;code&gt;arn:aws:s3:::photos/*&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Simulating the evaluator in Java
&lt;/h2&gt;

&lt;p&gt;Here is a minimal evaluator that follows the three rules. It is a &lt;strong&gt;simplified simulation&lt;/strong&gt; of the single-account, identity-based flow - the real AWS engine also considers resource-based policies, permissions boundaries, Organizations SCPs/RCPs, session policies, and conditions, which this demo intentionally leaves out.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IamPolicyDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="no"&gt;ALLOW&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DENY&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Effect&lt;/span&gt; &lt;span class="n"&gt;effect&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;actions&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;resources&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Request&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;principal&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;action&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;resource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;// IAM-style wildcard match: '*' matches any sequence of characters&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;wildcardMatch&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;pattern&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;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&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="s"&gt;"\\."&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;replace&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="s"&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;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;actionOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actions&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="na"&gt;anyMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wildcardMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;resourceOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resources&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="na"&gt;anyMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wildcardMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resource&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;actionOk&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;resourceOk&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Simplified single-account flow: explicit deny &amp;gt; allow &amp;gt; implicit deny&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;evaluate&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;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;r&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="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;matching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policy&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="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;explicitDeny&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matching&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="na"&gt;anyMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DENY&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;explicitDeny&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;"DENIED  (explicit deny)"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matching&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="na"&gt;anyMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALLOW&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;allow&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;"ALLOWED"&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;"DENIED  (implicit deny - no statement matched Allow)"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&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="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;alicePolicy&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALLOW&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;"s3:GetObject"&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;"arn:aws:s3:::photos/*"&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="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bobPolicy&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALLOW&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;"s3:*"&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;"arn:aws:s3:::photos"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"arn:aws:s3:::photos/*"&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DENY&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;"s3:DeleteObject"&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;"arn:aws:s3:::photos/*"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alice"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;      &lt;span class="s"&gt;"arn:aws:s3:::photos/cat.jpg"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alice"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="s"&gt;"arn:aws:s3:::photos/cat.jpg"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bob"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="s"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;      &lt;span class="s"&gt;"arn:aws:s3:::photos/dog.jpg"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bob"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="s"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="s"&gt;"arn:aws:s3:::photos/dog.jpg"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;requests&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="nc"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alice"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;alicePolicy&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bobPolicy&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;"%-5s %-16s %-30s -&amp;gt; %s%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;evaluate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Wildcard in Action: "s3:Get*" covers every read action&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;Statement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readOnly&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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Statement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALLOW&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;"s3:Get*"&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;"*"&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;println&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wildcard policy: Allow s3:Get* on *"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&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;action&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;"s3:GetObject"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s3:GetBucketLocation"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"carol"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"arn:aws:s3:::photos/cat.jpg"&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;"%-5s %-20s -&amp;gt; %s%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"carol"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evaluate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running it (real output)
&lt;/h2&gt;

&lt;p&gt;Compiled and run locally on Temurin JDK 21:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alice s3:GetObject     arn:aws:s3:::photos/cat.jpg    -&amp;gt; ALLOWED
alice s3:DeleteObject  arn:aws:s3:::photos/cat.jpg    -&amp;gt; DENIED  (implicit deny - no statement matched Allow)
bob   s3:PutObject     arn:aws:s3:::photos/dog.jpg    -&amp;gt; ALLOWED
bob   s3:DeleteObject  arn:aws:s3:::photos/dog.jpg    -&amp;gt; DENIED  (explicit deny)

Wildcard policy: Allow s3:Get* on *
carol s3:GetObject         -&amp;gt; ALLOWED
carol s3:GetBucketLocation -&amp;gt; ALLOWED
carol s3:PutObject         -&amp;gt; DENIED  (implicit deny - no statement matched Allow)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Walk through it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;alice / GetObject&lt;/strong&gt; matches her &lt;code&gt;Allow&lt;/code&gt; - allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;alice / DeleteObject&lt;/strong&gt; matches nothing, so the default kicks in: implicit deny. This is the rule that surprises people most; missing permission looks exactly like an explicit block from the client side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bob / PutObject&lt;/strong&gt; is covered by &lt;code&gt;s3:*&lt;/code&gt; - allowed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bob / DeleteObject&lt;/strong&gt; is covered by &lt;code&gt;s3:*&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; by the explicit &lt;code&gt;Deny&lt;/code&gt;. Deny wins. This is why one deny statement can lock down an action even when a broad admin-style policy is attached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;carol&lt;/strong&gt; shows the &lt;code&gt;Action&lt;/code&gt; wildcard: &lt;code&gt;s3:Get*&lt;/code&gt; covers both &lt;code&gt;GetObject&lt;/code&gt; and &lt;code&gt;GetBucketLocation&lt;/code&gt;, but not &lt;code&gt;PutObject&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  See the decision flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo62a8fjyfq54lsj9ryah.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo62a8fjyfq54lsj9ryah.gif" alt="IAM evaluation decision flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The animation walks the same three scenarios through the decision tree: check for an explicit Deny first, then look for an Allow, and fall back to the implicit deny when nothing matches.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this leaves out
&lt;/h2&gt;

&lt;p&gt;This is a teaching model of the within-account, identity-based path. Real AWS evaluation additionally layers in resource-based policies (union within an account), permissions boundaries (intersection with identity policies), Organizations SCPs/RCPs (intersection again), session policies, and &lt;code&gt;Condition&lt;/code&gt; elements. The explicit-deny-wins rule holds across all of them, which is why it is the one rule worth memorizing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html" rel="noopener noreferrer"&gt;Policy evaluation logic - AWS IAM documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html" rel="noopener noreferrer"&gt;IAM JSON policy element reference - AWS IAM documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iam</category>
      <category>java</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Embeddings Explained: A Quick Walkthrough with Java</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Tue, 27 Oct 2026 12:30:20 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/embeddings-explained-a-quick-walkthrough-with-java-2450</link>
      <guid>https://dev.to/vishnub33527201/embeddings-explained-a-quick-walkthrough-with-java-2450</guid>
      <description>&lt;p&gt;If you have used semantic search, a recommendation engine, or any "chat with your documents" feature, you have used &lt;strong&gt;embeddings&lt;/strong&gt;. They are the way modern AI systems represent meaning as numbers, and the idea is simpler than the name suggests.&lt;/p&gt;

&lt;p&gt;In this walkthrough we will cover what an embedding actually is, then run a small Java program that shows the two things that make embeddings useful: measuring similarity and doing arithmetic on meaning. The code was compiled and run on JDK 21 (Temurin 21.0.13), and the outputs shown are real runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An embedding is just a vector.&lt;/strong&gt; A list of floating point numbers, like &lt;code&gt;[0.12, -0.44, 0.87, ...]&lt;/code&gt;. An embedding model turns a piece of text (a word, a sentence, a whole document) into one of these vectors. The numbers are not chosen by hand; the model &lt;em&gt;learns&lt;/em&gt; them from large amounts of text, so that the position of each vector captures something about the meaning of the text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distance means relatedness.&lt;/strong&gt; As the &lt;a href="https://platform.openai.com/docs/guides/embeddings" rel="noopener noreferrer"&gt;OpenAI embeddings guide&lt;/a&gt; puts it: the distance between two vectors measures their relatedness. Texts with similar meaning end up close together; unrelated texts end up far apart. The usual way to measure this is &lt;strong&gt;cosine similarity&lt;/strong&gt;, which looks at the angle between two vectors: 1.0 means pointing the same way, 0 means unrelated, -1 means opposite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real embeddings are big.&lt;/strong&gt; Our demo below uses 4 numbers per word so we can see what is happening. A production model like &lt;code&gt;text-embedding-3-small&lt;/code&gt; returns 1,536 numbers per input, and &lt;code&gt;text-embedding-3-large&lt;/code&gt; returns 3,072.&lt;/p&gt;

&lt;p&gt;This animation sums up the whole idea:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftf4i1m1eyycaman6v9df.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftf4i1m1eyycaman6v9df.gif" alt="Words become vectors: meaning becomes geometry" width="759" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why should you care? Because with a decent embedding model, "close in vector space" is often a good proxy for "similar meaning", and that powers a lot of features: search ranked by relevance instead of keyword, clustering documents by topic, recommendations, anomaly detection, and classification by nearest label. It is a proxy, not a guarantee: how well similarity tracks meaning depends on the model, the data it was trained on, and the similarity metric you choose, and it can break down on text that is very different from that training data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough: embeddings from first principles in Java
&lt;/h2&gt;

&lt;p&gt;We will hand-build tiny 4D "embeddings" for six words. Each dimension pretends to be one learned feature: royalty, humanness, masculinity, fruitiness. A real model discovers these features on its own; we pick them so the mechanics are visible. One honest limitation up front: because we choose the numbers ourselves, this demo shows the mechanics of similarity and vector arithmetic, not learned semantic behavior. It does not independently reproduce what trained models do; it makes their math visible.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmbeddingsDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hand-built 4D "embeddings". Real models learn these from data;&lt;/span&gt;
    &lt;span class="c1"&gt;// ours are chosen by hand so we can see the mechanics.&lt;/span&gt;
    &lt;span class="c1"&gt;// dimensions: [royalty, humanness, masculinity, fruitiness]&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Map&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;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;VECTORS&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;LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;   &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"queen"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"man"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"woman"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
        &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"orange"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;cosineSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;dot&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;normA&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;normB&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;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&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="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;normA&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;normB&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="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="n"&gt;b&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sqrt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normA&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sqrt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normB&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printSimilarity&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;a&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;b&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;"cos(%s, %s) = %.3f%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;cosineSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;VECTORS&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;a&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="no"&gt;VECTORS&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;b&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;nearest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="o"&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;best&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;bestSim&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;VECTORS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entrySet&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&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;x&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;exclude&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;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKey&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;sim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cosineSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&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;getValue&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;sim&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bestSim&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;bestSim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sim&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;best&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;getKey&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;best&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" (similarity "&lt;/span&gt; &lt;span class="o"&gt;+&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;"%.3f"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bestSim&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="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--- Cosine similarity between word vectors ---"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"queen"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"man"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"woman"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printSimilarity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apple"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"orange"&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;println&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--- Vector arithmetic: king - man + woman ---"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;king&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;VECTORS&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="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;man&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;VECTORS&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="s"&gt;"man"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;woman&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;VECTORS&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="s"&gt;"woman"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;double&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="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&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;result&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="n"&gt;king&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="n"&gt;man&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="n"&gt;woman&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="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"result vector: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nearest word: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nearest&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="s"&gt;"king"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"man"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"woman"&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;Real output from my run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- Cosine similarity between word vectors ---
cos(king, queen) = 0.906
cos(king, man) = 0.707
cos(king, woman) = 0.566
cos(king, apple) = 0.000
cos(apple, orange) = 0.994

--- Vector arithmetic: king - man + woman ---
result vector: [1.0, 0.8, 0.0, 0.0]
nearest word: queen (similarity 1.000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to notice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Similarity matches intuition.&lt;/strong&gt; &lt;code&gt;king&lt;/code&gt; is closest to &lt;code&gt;queen&lt;/code&gt; (0.906), less close to &lt;code&gt;man&lt;/code&gt; and &lt;code&gt;woman&lt;/code&gt;, and completely unrelated to &lt;code&gt;apple&lt;/code&gt; (0.000). Meanwhile &lt;code&gt;apple&lt;/code&gt; and &lt;code&gt;orange&lt;/code&gt; sit on top of each other (0.994). No string comparison anywhere; it all falls out of the geometry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arithmetic works on meaning.&lt;/strong&gt; &lt;code&gt;king - man + woman&lt;/code&gt; produces exactly the vector &lt;code&gt;[1.0, 0.8, 0.0, 0.0]&lt;/code&gt;, which &lt;em&gt;is&lt;/em&gt; our &lt;code&gt;queen&lt;/code&gt; vector, and a nearest-neighbor search finds &lt;code&gt;queen&lt;/code&gt; with similarity 1.000. This mirrors the famous finding of the original &lt;a href="https://arxiv.org/abs/1301.3781" rel="noopener noreferrer"&gt;word2vec paper&lt;/a&gt; (Mikolov et al., 2013), which showed that vectors learned from a large corpus exhibit this kind of regularity. The difference matters: our queen match is exact because we built the vectors to make it so, while word2vec's result was empirical, emerging from vectors learned from data. The demo illustrates the arithmetic; it does not prove the learned behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That nearest-neighbor search at the end is not a toy detail: it is the core of semantic search and RAG. You store the embedding of every document, embed the query, and return the documents with the highest cosine similarity, exactly the retrieval step described in the OpenAI guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do real embeddings come from?
&lt;/h2&gt;

&lt;p&gt;You do not hand-pick the numbers like we did. An embedding model is trained on a large text corpus so that words and documents used in similar contexts get similar vectors. Today you typically get embeddings by sending text to a model: an API such as OpenAI's embeddings endpoint (&lt;code&gt;text-embedding-3-small&lt;/code&gt; returns 1,536 dimensions) or an open model you run yourself. The input is text, the output is the float vector, and from that point on everything is the math we just ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where you will use them
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search:&lt;/strong&gt; rank documents by cosine similarity to the query embedding, not by keyword overlap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG (retrieval augmented generation):&lt;/strong&gt; fetch the most similar document chunks and hand them to the LLM as context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommendations and clustering:&lt;/strong&gt; group or suggest items whose embeddings are close.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classification and anomaly detection:&lt;/strong&gt; nearest label wins; outliers are the vectors far from everything else.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;An embedding is a learned vector of floats where distance encodes meaning. Cosine similarity gives you "how related are these two texts" as one number, nearest-neighbor search over stored embeddings gives you semantic search and RAG, and vector arithmetic can even solve analogies. The whole mechanism fits in the small Java program above; the only thing a real model adds is learning the numbers instead of choosing them.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/guides/embeddings" rel="noopener noreferrer"&gt;OpenAI documentation: Vector embeddings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/1301.3781" rel="noopener noreferrer"&gt;Mikolov et al., 2013: Efficient Estimation of Word Representations in Vector Space (word2vec)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>java</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Java Virtual Threads: A Quick Walkthrough</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Mon, 26 Oct 2026 12:30:21 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/java-virtual-threads-a-quick-walkthrough-3fme</link>
      <guid>https://dev.to/vishnub33527201/java-virtual-threads-a-quick-walkthrough-3fme</guid>
      <description>&lt;p&gt;Java 21 shipped one of the biggest changes to Java concurrency in years: &lt;strong&gt;virtual threads&lt;/strong&gt; (&lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;JEP 444&lt;/a&gt;). They let you write plain, blocking-style code that scales to thousands of concurrent tasks, without reactive programming or careful thread-pool tuning.&lt;/p&gt;

&lt;p&gt;In this walkthrough we will look at what virtual threads are, run three small programs you can copy and run yourself, and finish with how to switch them on in a Spring Boot app. Every example was compiled and run on JDK 21 (Temurin 21.0.13), and the outputs shown are real runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Platform threads vs virtual threads.&lt;/strong&gt; A platform thread is a thin wrapper around an operating system thread, and it keeps that OS thread for its whole lifetime. OS threads are expensive, so an application can only have a limited number of them. A virtual thread is also a &lt;code&gt;java.lang.Thread&lt;/code&gt;, but it is not tied to one OS thread. The JVM maps a large number of virtual threads onto a small number of platform threads, called &lt;strong&gt;carrier threads&lt;/strong&gt;, in the same spirit as an OS mapping a large virtual address space onto limited RAM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mount, unmount, repeat.&lt;/strong&gt; When code running in a virtual thread makes a blocking I/O call (a database query, an HTTP request, &lt;code&gt;Thread.sleep&lt;/code&gt;), the Java runtime suspends the virtual thread and unmounts it from its carrier. The carrier is immediately free to run another virtual thread. When the I/O finishes, the virtual thread mounts again on whichever carrier is free and resumes. This animation shows the cycle:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fth17dqewcqidf31jyz3k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fth17dqewcqidf31jyz3k.gif" alt="How the JVM schedules virtual threads" width="760" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scale, not speed.&lt;/strong&gt; Virtual threads are not faster threads; they do not run your code any faster than platform threads. They exist to provide scale (higher throughput), not speed (lower latency). They shine when tasks spend most of their time waiting on I/O, which is exactly what server applications do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One caveat: pinning.&lt;/strong&gt; A virtual thread cannot unmount while it is running inside a &lt;code&gt;synchronized&lt;/code&gt; block or method, or inside a native call. That is called &lt;em&gt;pinning&lt;/em&gt;. It does not break correctness, but it can hurt scalability if it happens often or for long stretches. The usual fix is to guard long I/O operations with &lt;code&gt;java.util.concurrent.locks.ReentrantLock&lt;/code&gt; instead of &lt;code&gt;synchronized&lt;/code&gt;. From Java 24, &lt;a href="https://openjdk.org/jeps/491" rel="noopener noreferrer"&gt;JEP 491&lt;/a&gt; removes nearly all pinning caused by &lt;code&gt;synchronized&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough 1: Your first virtual thread
&lt;/h2&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;HelloVirtualThread&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Quickest way: create and start in one call&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from a virtual thread"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Builder: gives you names and other thread properties&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofVirtual&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"worker-"&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;Runnable&lt;/span&gt; &lt;span class="n"&gt;task&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="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running in "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&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;Save it as &lt;code&gt;HelloVirtualThread.java&lt;/code&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac HelloVirtualThread.java
java HelloVirtualThread
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output from my run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from a virtual thread
Running in VirtualThread[#16,worker-0]/runnable@ForkJoinPool-1-worker-2
Running in VirtualThread[#17,worker-1]/runnable@ForkJoinPool-1-worker-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the thread names: &lt;code&gt;VirtualThread[#16,worker-0]&lt;/code&gt; is the virtual thread, and the part after &lt;code&gt;@&lt;/code&gt; (&lt;code&gt;ForkJoinPool-1-worker-2&lt;/code&gt;) is the carrier platform thread it happened to be mounted on. Same API as any thread, but the JVM is doing the carrier juggling for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough 2: An executor that starts a virtual thread per task
&lt;/h2&gt;

&lt;p&gt;For real code, use &lt;code&gt;Executors.newVirtualThreadPerTaskExecutor()&lt;/code&gt;. Every submitted task gets its own fresh virtual thread:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.ExecutorService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.Executors&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.Future&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExecutorDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// A new virtual thread is started for every submitted task&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;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Future&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;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&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="c1"&gt;// simulates a blocking I/O call&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Fetched order #42 on "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;future&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="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;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Task completed"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fetched order #42 on VirtualThread[#13]/runnable@ForkJoinPool-1-worker-1
Task completed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth noticing. The &lt;code&gt;ExecutorService&lt;/code&gt; is AutoCloseable, so try-with-resources shuts it down and waits for running tasks. And there is no pool size to tune: one task, one virtual thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough 3: The scale test
&lt;/h2&gt;

&lt;p&gt;Here is where it clicks. Take 2,000 tasks that each simulate 100 ms of blocking I/O with Thread.sleep, and run them two ways: a classic fixed pool of 8 platform threads, and a virtual thread per task.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.time.Instant&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.ExecutorService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.Executors&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.stream.IntStream&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScaleDemo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&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;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;pool&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;tasks&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&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;pool&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// close() shuts down and waits for all tasks&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;tasks&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;forEach&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;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&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;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&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="c1"&gt;// simulates 100 ms of blocking I/O&lt;/span&gt;
                &lt;span class="k"&gt;return&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="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;"%s: %,d tasks finished in %,d ms%n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2_000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fixed pool of 8 platform threads"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Virtual thread per task          "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;tasks&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;Real output from my run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fixed pool of 8 platform threads: 2,000 tasks finished in 25,062 ms
Virtual thread per task          : 2,000 tasks finished in 141 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The platform pool can only work on 8 tasks at a time, so 2,000 tasks x 100 ms takes about 25 seconds. With virtual threads, all 2,000 tasks start at once; when they block on the sleep they unmount, and the whole batch finishes in about one sleep's worth of time. This animation uses the real measured times:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29039f86z86t5xoexq1h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29039f86z86t5xoexq1h.gif" alt="Fixed pool vs virtual threads: measured wall-clock time on simulated blocking I/O" width="720" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your numbers will vary by machine, but the shape of the result will not. Note that the tasks got &lt;em&gt;throughput&lt;/em&gt;, not speed: each task still takes 100 ms of waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using virtual threads in Spring Boot
&lt;/h2&gt;

&lt;p&gt;If your app is on Spring Boot and Java 21 or later, switching to virtual threads is one property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.threads.virtual.enabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this on, the embedded web server handles each request on a virtual thread, so your controllers can stay simple blocking code. Two things from the &lt;a href="https://docs.spring.io/spring-boot/3.5/reference/features/spring-application.html" rel="noopener noreferrer"&gt;Spring Boot reference&lt;/a&gt; to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring recommends Java 24 or later for the best experience, partly because of the &lt;code&gt;synchronized&lt;/code&gt; pinning improvements mentioned above.&lt;/li&gt;
&lt;li&gt;Virtual threads are daemon threads, so they will not keep the JVM alive. If you rely on something like a &lt;code&gt;@Scheduled&lt;/code&gt; bean to keep the app running, also set &lt;code&gt;spring.main.keep-alive=true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Once virtual threads are enabled, properties that configure thread pools no longer have an effect, because virtual threads are scheduled on a JVM-wide carrier pool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to use (and when not)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good fit:&lt;/strong&gt; I/O-bound work with lots of concurrent tasks: web requests, database calls, calling other services. This is most server-side Java.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not a fit:&lt;/strong&gt; CPU-bound work. Virtual threads do not create more CPU capacity; a task that burns CPU still occupies a carrier the whole time. For those workloads, sizing a platform pool to your cores is still the right tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Virtual threads let you keep the simple, one-thread-per-request programming model and throw away the thread-pool sizing gymnastics for I/O-bound services. The API is just &lt;code&gt;Thread&lt;/code&gt; and &lt;code&gt;ExecutorService&lt;/code&gt;, the mental model is "one virtual thread per task", and on JDK 21+ you can try it today with the three programs above.&lt;/p&gt;

&lt;p&gt;If you try the scale demo yourself, I would be curious what numbers you get on your machine.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html" rel="noopener noreferrer"&gt;Oracle Java 21 documentation: Virtual Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/444" rel="noopener noreferrer"&gt;JEP 444: Virtual Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/491" rel="noopener noreferrer"&gt;JEP 491: Synchronize Virtual Threads without Pinning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/3.5/reference/features/spring-application.html" rel="noopener noreferrer"&gt;Spring Boot reference: Virtual threads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Written with AI assistance; code examples were compiled and run on JDK 21 before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>concurrency</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>AWS Lambda Basics: A Quick Walkthrough with Spring Boot</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Mon, 26 Oct 2026 06:21:38 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/aws-lambda-basics-a-quick-walkthrough-with-spring-boot-pg3</link>
      <guid>https://dev.to/vishnub33527201/aws-lambda-basics-a-quick-walkthrough-with-spring-boot-pg3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you have ever deployed an application the traditional way - provision an EC2 instance, install a runtime, keep it patched, watch it sit idle most of the day - AWS Lambda feels almost unfair. Lambda is AWS's serverless compute service: you upload your code, and AWS runs it for you in response to events. No servers to provision, no operating system to patch, and no paying for idle time. You are charged per request and for the exact duration your code runs, down to the millisecond.&lt;/p&gt;

&lt;p&gt;This post is for Java and Spring Boot developers. We go through the basic concepts of Lambda - handlers, events, triggers, and limits - and then do two quick hands-on implementations with Spring Boot and Spring Cloud Function: a function you build locally with Maven, deploy through the AWS console and test, and the same idea exposed as an HTTP endpoint you can call with curl. We finish with how to clean everything up, because even small experiments can cost money if you leave them running or expose them publicly.&lt;/p&gt;

&lt;p&gt;Everything below is verified against the official AWS and Spring documentation as of October 2026, and every code listing was compiled and executed locally while writing. Both ecosystems update regularly, so check the linked docs pages if something looks different for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What exactly is AWS Lambda?
&lt;/h2&gt;

&lt;p&gt;Lambda is a Function-as-a-Service (FaaS). The mental model is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You write a &lt;strong&gt;function&lt;/strong&gt; - a small piece of code with a defined entry point.&lt;/li&gt;
&lt;li&gt;You configure a &lt;strong&gt;trigger&lt;/strong&gt; - what should invoke the function. This can be a manual test, an HTTP request, a file landing in S3, a message in SQS, a schedule, and many more.&lt;/li&gt;
&lt;li&gt;Lambda runs your function when the trigger fires, scaling out to as many parallel copies as needed - up to your account's concurrency quota (1,000 concurrent executions per region by default, which you can raise or lower). Environments are kept warm and reused between invocations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because there is no always-on server, you pay nothing while nothing runs. The free tier includes &lt;strong&gt;1 million requests and 400,000 GB-seconds of compute per month&lt;/strong&gt;, and the experiments in this post are tiny next to that. Two honest caveats: the free tier is shared across everything in your account, and services around Lambda (like CloudWatch log storage) can bill separately. A billing alarm in AWS Budgets can help you spot spend, but alerts can be delayed and they do not stop charges - AWS has no hard spend cap. Deleting what you created when you are done (cleanup below) stops future charges from those resources - it does not erase anything already accrued, and anything else in the account bills as usual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core concepts in five minutes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The handler.&lt;/strong&gt; The handler is the entry point - the method Lambda calls when your function is invoked. For plain Java it is a method reference like &lt;code&gt;example.Handler::handleRequest&lt;/code&gt;. In this post we use Spring Cloud Function, so we never write a handler class ourselves: we set the handler to Spring's built-in &lt;code&gt;org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest&lt;/code&gt;, and it routes each invocation to a &lt;code&gt;@Bean&lt;/code&gt; of type &lt;code&gt;Function&amp;lt;I, O&amp;gt;&lt;/code&gt;. Whatever you choose must match the handler setting on the function, or Lambda will not find your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The event object.&lt;/strong&gt; The first argument to your handler is the event - a JSON document with the input for this invocation. Its shape depends on the trigger: an S3 trigger delivers bucket and object details, an HTTP trigger delivers the request method, headers and body, and a console test event is whatever JSON you type in. Spring Cloud Function converts that JSON into your function's declared input type automatically - a small record you define, or an AWS event type such as &lt;code&gt;APIGatewayV2HTTPEvent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The context object.&lt;/strong&gt; The second argument is provided by Lambda itself and describes the invocation: the request ID, the CloudWatch log group name, and how much time remains before the timeout. Useful for logging and monitoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The execution role.&lt;/strong&gt; Your function runs with an IAM role that decides what AWS resources it is allowed to touch. When you create a function in the console, Lambda creates a basic role that only permits writing logs to CloudWatch. If your function needs to read from S3 or write to DynamoDB, you add those permissions to this role - following least privilege, grant only what the function actually needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cold starts.&lt;/strong&gt; The first time a function is invoked (or after it has been idle), Lambda provisions a fresh execution environment - this adds a delay called a cold start, visible as &lt;code&gt;Init Duration&lt;/code&gt; in the logs. Later invocations reuse the warm environment and skip it. For Spring Boot functions the JVM plus Spring context startup makes cold starts more noticeable than for a small Node.js or Python script. AWS Lambda SnapStart (available for the Java runtimes) and giving the function more memory both help - in Walkthrough 1 we raise the memory and timeout from the console defaults so the first cold start fits comfortably.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fchonicwoefmy9c2o3czu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fchonicwoefmy9c2o3czu.gif" alt="What happens when Lambda is triggered - a fresh environment pays the cold start (runtime and Spring init, billed since Aug 2025); when a warm environment is reused, that init is not repeated, though later invocations are not guaranteed to be warm" width="760" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtimes.&lt;/strong&gt; Lambda offers managed runtimes for Java, Node.js, Python, .NET and Ruby, plus custom runtimes. For Java, prefer &lt;code&gt;java21&lt;/code&gt; or &lt;code&gt;java25&lt;/code&gt; - both are Amazon Linux 2023 based, while the older Amazon Linux 2 based runtimes are on a deprecation path. One practical difference from the scripted languages: the console's inline code editor does not work for Java, so the workflow is always build locally, upload the JAR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits worth memorising
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;15 minutes&lt;/strong&gt; maximum per invocation - Lambda is for short tasks, not long-running jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;128 MB to 10,240 MB&lt;/strong&gt; of memory per function. CPU power scales proportionally with memory, so more memory can actually make a function finish faster (and sometimes cheaper).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;512 MB to 10,240 MB&lt;/strong&gt; of temporary storage in &lt;code&gt;/tmp&lt;/code&gt;, wiped between environments - never rely on it for persistence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 MB&lt;/strong&gt; payload for synchronous invocations, &lt;strong&gt;1 MB&lt;/strong&gt; for asynchronous ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;50 MB&lt;/strong&gt; zipped deployment package on direct upload - larger zips go through S3, but the &lt;strong&gt;250 MB&lt;/strong&gt; unzipped limit applies either way. The shaded Spring Boot JAR we build below is about 38 MB, so it still fits a direct upload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Walkthrough 1 - your first Lambda function with Spring Boot
&lt;/h2&gt;

&lt;p&gt;You need a JDK 21 and Maven installed locally, plus an AWS account. The function receives a &lt;code&gt;length&lt;/code&gt; and a &lt;code&gt;width&lt;/code&gt;, multiplies them, and returns the area - deliberately tiny, so the moving parts stay visible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi8vvqmjwfy0759p19r4h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi8vvqmjwfy0759p19r4h.gif" alt="The Java on Lambda workflow - write the code, build the shaded JAR, upload it, configure, invoke" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 - Create the Maven project.&lt;/strong&gt; Make a folder &lt;code&gt;lambda-area&lt;/code&gt; with this &lt;code&gt;pom.xml&lt;/code&gt;, and put the Java files under &lt;code&gt;src/main/java/example&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
         &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
         &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;example&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lambda-area&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.1.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;relativePath/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;java.version&amp;gt;&lt;/span&gt;21&lt;span class="nt"&gt;&amp;lt;/java.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;spring-cloud-function.version&amp;gt;&lt;/span&gt;5.0.5&lt;span class="nt"&gt;&amp;lt;/spring-cloud-function.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;aws-lambda-events.version&amp;gt;&lt;/span&gt;3.16.1&lt;span class="nt"&gt;&amp;lt;/aws-lambda-events.version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-function-adapter-aws&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;tools.jackson.core&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jackson-databind&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.amazonaws&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;aws-lambda-java-events&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${aws-lambda-events.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.amazonaws&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;aws-lambda-java-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-function-dependencies&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring-cloud-function.version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot.experimental&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-thin-layout&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.31.RELEASE&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-shade-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;createDependencyReducedPom&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/createDependencyReducedPom&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;shadedArtifactAttached&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/shadedArtifactAttached&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;shadedClassifierName&amp;gt;&lt;/span&gt;aws&lt;span class="nt"&gt;&amp;lt;/shadedClassifierName&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each piece does: &lt;code&gt;spring-cloud-function-adapter-aws&lt;/code&gt; is the bridge between a Spring Boot app and Lambda. &lt;code&gt;aws-lambda-java-events&lt;/code&gt; gives us typed AWS events (used in Walkthrough 2). &lt;code&gt;aws-lambda-java-core&lt;/code&gt; is marked &lt;code&gt;provided&lt;/code&gt; because the Lambda runtime already has it. &lt;code&gt;jackson-databind&lt;/code&gt; here is Jackson 3 (the &lt;code&gt;tools.jackson&lt;/code&gt; group) - the JSON library Spring Boot 4 uses; we need it directly in Walkthrough 2. The Spring Boot plugin with the thin layout plus the shade plugin builds a single deployable JAR with the &lt;code&gt;aws&lt;/code&gt; classifier - the same build setup as the official Spring Cloud Function AWS sample. All versions were current on Maven Central when this was written.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 - The application and the function bean.&lt;/strong&gt; &lt;code&gt;src/main/java/example/AreaApplication.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.SpringApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.autoconfigure.SpringBootApplication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.function.Function&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

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

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AreaApplication&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="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AreaInput&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AreaResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;area&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;input&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;AreaResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;width&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;And the two records, &lt;code&gt;AreaInput.java&lt;/code&gt; and &lt;code&gt;AreaResult.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;AreaInput&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;width&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;example&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;AreaResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;area&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 is an ordinary Spring Boot application. The Lambda-specific idea is the bean: a &lt;code&gt;Function&amp;lt;AreaInput, AreaResult&amp;gt;&lt;/code&gt; named &lt;code&gt;area&lt;/code&gt;. Spring Cloud Function collects every &lt;code&gt;Function&lt;/code&gt;/&lt;code&gt;Consumer&lt;/code&gt;/&lt;code&gt;Supplier&lt;/code&gt; bean into a function catalogue, converts the incoming event JSON into &lt;code&gt;AreaInput&lt;/code&gt;, and serialises the returned &lt;code&gt;AreaResult&lt;/code&gt; back to JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 - Build the deployment package.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn clean package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces &lt;code&gt;target/lambda-area-0.0.1-SNAPSHOT-aws.jar&lt;/code&gt; - the one with the &lt;code&gt;-aws&lt;/code&gt; classifier is the shaded, deployable JAR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 - Create the function.&lt;/strong&gt; Open the Lambda console, go to the Functions page, and choose &lt;strong&gt;Create function&lt;/strong&gt;. Select &lt;strong&gt;Author from scratch&lt;/strong&gt;, enter &lt;code&gt;myLambdaFunction&lt;/code&gt; as the name, pick &lt;strong&gt;Java 21&lt;/strong&gt; as the runtime, leave the architecture at x86_64, and create. Lambda also creates the basic execution role automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 - Upload the JAR and set the handler.&lt;/strong&gt; In the Code tab, choose &lt;strong&gt;Upload from&lt;/strong&gt;, then &lt;strong&gt;.zip or .jar file&lt;/strong&gt;, and upload &lt;code&gt;target/lambda-area-0.0.1-SNAPSHOT-aws.jar&lt;/code&gt;. Then open &lt;strong&gt;Runtime settings&lt;/strong&gt;, choose &lt;strong&gt;Edit&lt;/strong&gt;, set the handler to &lt;code&gt;org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest&lt;/code&gt;, and save. Since the project currently has exactly one function bean, the invoker routes to it automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 - Set memory and timeout for the demo.&lt;/strong&gt; A new console function starts with Lambda's defaults: &lt;strong&gt;128 MB of memory&lt;/strong&gt; and a &lt;strong&gt;3-second timeout&lt;/strong&gt;. A Spring Boot cold start (JVM start plus Spring context initialisation) can exceed 3 seconds at 128 MB, so the first test could time out before your code ever runs. On the function's Configuration tab, open &lt;strong&gt;General configuration&lt;/strong&gt;, choose &lt;strong&gt;Edit&lt;/strong&gt;, set &lt;strong&gt;Memory&lt;/strong&gt; to 512 MB (the same value Spring's own Lambda sample uses) and &lt;strong&gt;Timeout&lt;/strong&gt; to 30 seconds, and save. Treat these as demo settings, not production sizing: CPU scales with memory, and the bill is configured memory x billed duration, so once things run, right-size from the &lt;code&gt;REPORT&lt;/code&gt; lines or with AWS Lambda Power Tuning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7 - Test it.&lt;/strong&gt; In the Test section, create a test event named &lt;code&gt;myTestEvent&lt;/code&gt; with this JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click Test. You should see the response &lt;code&gt;{"area":42.0}&lt;/code&gt; along with the function logs. Every invocation ends with a &lt;code&gt;REPORT&lt;/code&gt; line showing &lt;code&gt;Duration&lt;/code&gt;, &lt;code&gt;Billed Duration&lt;/code&gt;, &lt;code&gt;Memory Size&lt;/code&gt;, &lt;code&gt;Max Memory Used&lt;/code&gt;, and on cold starts &lt;code&gt;Init Duration&lt;/code&gt;. The bill itself is computed from the billed duration and the memory you configured - &lt;code&gt;Max Memory Used&lt;/code&gt; is not billed, but it tells you whether you can right-size the function down to a cheaper memory setting. When you invoke the function from outside the console, output goes to CloudWatch Logs under the log group &lt;code&gt;/aws/lambda/myLambdaFunction&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough 2 - expose it over HTTP with a Function URL
&lt;/h2&gt;

&lt;p&gt;A test button is nice, but usually you want to call your function from somewhere else. The simplest way is a &lt;strong&gt;function URL&lt;/strong&gt; - a dedicated HTTPS endpoint for one function, no API Gateway required. (For a full API with routes, stages and API keys, API Gateway is the right tool; for a webhook or a quick endpoint, a function URL is enough.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 - Add an HTTP function bean.&lt;/strong&gt; A function URL wraps the incoming HTTP request into an event with the same shape as an API Gateway HTTP API (v2) event, so we write a function from &lt;code&gt;APIGatewayV2HTTPEvent&lt;/code&gt; to &lt;code&gt;APIGatewayV2HTTPResponse&lt;/code&gt;. The JSON body arrives as a string in &lt;code&gt;event.getBody()&lt;/code&gt;, so we parse it, validate the input, and return a proper 400 instead of an unhandled 500 on bad input. Add this to &lt;code&gt;AreaApplication&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&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;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;APIGatewayV2HTTPEvent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;APIGatewayV2HTTPResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;areaHttp&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;event&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="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TRUE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIsBase64Encoded&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;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Send JSON as plain text"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="nc"&gt;Map&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;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;body&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;body&lt;/span&gt; &lt;span class="o"&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;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&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;TypeReference&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Map&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;,&lt;/span&gt; &lt;span class="nc"&gt;Object&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="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;MismatchedInputException&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="nf"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body must be a JSON object"&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;Exception&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="nf"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body must be valid JSON"&lt;/span&gt;&lt;span class="o"&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;body&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body must be a JSON object"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&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="s"&gt;"length"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&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="s"&gt;"width"&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;length&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Number&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="n"&gt;width&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Number&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;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Provide non-negative numeric length and width"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;doubleValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;doubleValue&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="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFinite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&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="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFinite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;w&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Provide non-negative numeric length and width"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&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="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFinite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&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;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dimensions too large"&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;APIGatewayV2HTTPResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withStatusCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withHeaders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&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;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{\"area\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;area&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="na"&gt;build&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="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;APIGatewayV2HTTPResponse&lt;/span&gt; &lt;span class="nf"&gt;error&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;message&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;APIGatewayV2HTTPResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withStatusCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withHeaders&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&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;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{\"error\":\""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;message&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="na"&gt;build&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;with these imports at the top:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tools.jackson.core.type.TypeReference&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tools.jackson.databind.ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tools.jackson.databind.exc.MismatchedInputException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&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;Step 2 - Rebuild, re-upload, and route.&lt;/strong&gt; Run &lt;code&gt;mvn clean package&lt;/code&gt; again and upload the new &lt;code&gt;-aws.jar&lt;/code&gt; the same way as before. The project now has two function beans, so tell the invoker which one this Lambda should use: on the function's &lt;strong&gt;Configuration&lt;/strong&gt; tab, open &lt;strong&gt;Environment variables&lt;/strong&gt; and add &lt;code&gt;spring_cloud_function_definition&lt;/code&gt; = &lt;code&gt;areaHttp&lt;/code&gt;. Lambda environment variable names cannot contain dots, so the usual Spring property &lt;code&gt;spring.cloud.function.definition&lt;/code&gt; is written with underscores - Spring maps it back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 - Create the URL.&lt;/strong&gt; On the Configuration tab, choose &lt;strong&gt;Function URL&lt;/strong&gt;, then &lt;strong&gt;Create function URL&lt;/strong&gt;. For the auth type, choose &lt;code&gt;NONE&lt;/code&gt; for this experiment, save, and Lambda gives you an endpoint like &lt;code&gt;https://&amp;lt;url-id&amp;gt;.lambda-url.&amp;lt;region&amp;gt;.on.aws/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A word of caution on &lt;code&gt;NONE&lt;/code&gt;:&lt;/strong&gt; it makes the endpoint public - anyone who has the URL can invoke your function, and every invocation runs on your account. Treat it as a temporary experiment: delete it right after testing (cleanup steps below), and for anything real use the &lt;code&gt;AWS_IAM&lt;/code&gt; auth type (callers must present valid AWS credentials) or put proper authentication behind it. If you call the URL from browser JavaScript, you will also need to configure CORS on the function URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 - Call it.&lt;/strong&gt; From any terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://&amp;lt;url-id&amp;gt;.lambda-url.&amp;lt;region&amp;gt;.on.aws/'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"length": 6, "width": 7}'&lt;/span&gt;

&lt;span class="c"&gt;# {"area":42.0}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a working serverless HTTP endpoint written as a Spring Boot function: no server, no framework to manage, no load balancer - and it scales on its own. If you want a safety brake while experimenting, set &lt;strong&gt;reserved concurrency&lt;/strong&gt; on the function (Configuration, then Concurrency) to a small number like 5 - it hard-limits how many copies can run at once. It caps concurrency, not rupees: there is no setting that stops all spending, so treat it as a brake, not a wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning up afterwards
&lt;/h2&gt;

&lt;p&gt;A few clicks keeps the account tidy and stops new charges from the resources you created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Delete the function URL&lt;/strong&gt; (Configuration, Function URL, Delete). If the auth type was &lt;code&gt;NONE&lt;/code&gt;, also check the resource-based policy on the Permissions tab - the docs note that deleting the URL does not remove that policy automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete the function&lt;/strong&gt; itself if you are done with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete the CloudWatch log group&lt;/strong&gt; &lt;code&gt;/aws/lambda/myLambdaFunction&lt;/code&gt; if you do not need the logs - stored logs are one of the small charges that can outlive the experiment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When Lambda fits - and when it doesn't
&lt;/h2&gt;

&lt;p&gt;Lambda shines for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event-driven work&lt;/strong&gt; - react to an S3 upload, an SQS message, a DynamoDB stream update.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled jobs&lt;/strong&gt; - cron-style tasks with EventBridge, without keeping a server alive for them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhooks and lightweight APIs&lt;/strong&gt; - function URLs or API Gateway in front.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glue between services&lt;/strong&gt; - small pieces of logic that connect AWS services together.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is the wrong tool for jobs longer than 15 minutes, workloads that need state kept in memory between invocations, or sustained high-throughput services where containers or EC2 can be more economical.&lt;/p&gt;

&lt;p&gt;One last pointer: Spring Cloud Function (what we used here) fits small, single-purpose functions. If you instead want to take an existing Spring Boot REST API with its &lt;code&gt;@RestController&lt;/code&gt; classes and run it on Lambda as-is, look at the AWS Serverless Java Container project - Spring's own documentation presents both options side by side. Either way, measure the cold start before putting latency-sensitive traffic on it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Lambda runs your code in response to events - no servers to manage, billed per request plus milliseconds of runtime.&lt;/li&gt;
&lt;li&gt;The handler is the entry point, the event is the input JSON, the context carries invocation metadata, and the execution role controls AWS permissions.&lt;/li&gt;
&lt;li&gt;With Spring Cloud Function, your Lambda code is a plain &lt;code&gt;@Bean&lt;/code&gt; of type &lt;code&gt;Function&amp;lt;I, O&amp;gt;&lt;/code&gt;; the handler is always &lt;code&gt;FunctionInvoker::handleRequest&lt;/code&gt;, and &lt;code&gt;spring_cloud_function_definition&lt;/code&gt; picks the bean when there are several.&lt;/li&gt;
&lt;li&gt;Key limits: 15 minutes per run, up to 10 GB memory, 6 MB sync payload, 50 MB direct-upload JAR.&lt;/li&gt;
&lt;li&gt;Java means build locally and upload the shaded &lt;code&gt;-aws.jar&lt;/code&gt; - the console editor only works for scripted languages.&lt;/li&gt;
&lt;li&gt;A function URL turns the function into a public HTTPS endpoint - use auth type &lt;code&gt;NONE&lt;/code&gt; only briefly, and delete it when done.&lt;/li&gt;
&lt;li&gt;Clean up when you finish: delete the function URL, the function, and the CloudWatch log group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding, and stay tuned for the next post!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was drafted with the help of AI and reviewed by me before publishing.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Create your first Lambda function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Supported runtimes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/java-package.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Deploy Java functions with .zip or JAR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Function URLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Quotas and limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html" rel="noopener noreferrer"&gt;AWS Lambda docs - Function timeout (3-second default)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/lambda/pricing/" rel="noopener noreferrer"&gt;AWS - Lambda pricing and free tier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-cloud-function/reference/adapters/aws-intro.html" rel="noopener noreferrer"&gt;Spring Cloud Function - AWS adapter reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>java</category>
      <category>springboot</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Tips for Token Optimisation in Claude Code</title>
      <dc:creator>Vishnu B</dc:creator>
      <pubDate>Mon, 26 Oct 2026 05:07:54 +0000</pubDate>
      <link>https://dev.to/vishnub33527201/tips-for-token-optimisation-in-claude-code-1kn5</link>
      <guid>https://dev.to/vishnub33527201/tips-for-token-optimisation-in-claude-code-1kn5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you use Claude Code daily, you have already paid the context-window tax: every file Claude reads, every command output, and every message in the conversation sits in the context window and is sent to the model again on every turn. If you are on API billing, that repeated input is a direct per-token cost; on a Pro or Max subscription, the same usage counts against your plan's usage limits. A debugging session or a codebase exploration can consume tens of thousands of tokens on its own. The docs also warn that Claude's performance tends to degrade as the context fills - it can start "forgetting" earlier instructions and making more mistakes. So trimming context waste is worth doing for focus as much as for usage.&lt;/p&gt;

&lt;p&gt;The good news: most token waste comes from a few habits, and Claude Code ships with built-in commands to find and fix it. In this post, we will see nine practical tips to reduce token usage in Claude Code - measuring usage, clearing and compacting context, keeping CLAUDE.md lean, delegating to subagents, taming MCP servers, and preprocessing with hooks.&lt;/p&gt;

&lt;p&gt;Everything below is verified against the official Claude Code documentation as of October 2026. Claude Code changes fast, so check the linked docs pages if a command behaves differently for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 1 - Measure first: /usage and /context
&lt;/h2&gt;

&lt;p&gt;You cannot optimize what you cannot see. Claude Code has two built-in commands for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/usage&lt;/code&gt;&lt;/strong&gt; shows the Session block with token usage and an estimated cost for the current session (the dollar figure is computed locally at list price and is meant for API users; Pro/Max subscribers see plan usage bars instead). After the first API response, it also shows a &lt;strong&gt;Prompt cache&lt;/strong&gt; line, for example &lt;code&gt;14 requests · 91% of input tokens from cache&lt;/code&gt; - more on caching in Tip 9.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/context&lt;/code&gt;&lt;/strong&gt; shows a live breakdown of what is filling your context right now, by category, with optimization suggestions - including which CLAUDE.md and memory files were loaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a subscription plan, &lt;code&gt;/usage&lt;/code&gt; also shows an attribution breakdown - what share of your recent usage went to skills, subagents, plugins, and individual MCP servers - plus recommendations, one per row, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25% Trim ~/code/api/CLAUDE.md · 49k tokens per request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the footer shows a hint like &lt;code&gt;f to fix 2 of 3&lt;/code&gt;, pressing &lt;code&gt;f&lt;/code&gt; makes Claude Code apply the recommendations it can (this shortcut requires Claude Code v2.1.305 or later).&lt;/p&gt;

&lt;p&gt;There is also &lt;code&gt;/insights&lt;/code&gt;, which writes an HTML report on how you work - friction points, misunderstood requests, and suggestions - based on your recent sessions on that machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 2 - Clear between tasks: /clear
&lt;/h2&gt;

&lt;p&gt;This is the cheapest token saver there is. Stale context wastes tokens on every subsequent message, so run &lt;strong&gt;&lt;code&gt;/clear&lt;/code&gt;&lt;/strong&gt; whenever you switch to unrelated work.&lt;/p&gt;

&lt;p&gt;Two habits that make clearing painless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;strong&gt;&lt;code&gt;/rename&lt;/code&gt;&lt;/strong&gt; before clearing so you can find the session later, and &lt;strong&gt;&lt;code&gt;/resume&lt;/code&gt;&lt;/strong&gt; to return to it.&lt;/li&gt;
&lt;li&gt;If you have corrected Claude more than twice on the same issue in one session, the context is cluttered with failed approaches. The docs' advice: run &lt;code&gt;/clear&lt;/code&gt; and start fresh with a more specific prompt that includes what you learned. A clean session with a better prompt almost always outperforms a long session full of accumulated corrections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that &lt;code&gt;/clear&lt;/code&gt; also resets the session cost counters in &lt;code&gt;/usage&lt;/code&gt;, so the next session's total starts at $0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 3 - Compact with a focus: /compact
&lt;/h2&gt;

&lt;p&gt;When a session grows long, Claude Code compacts automatically as you approach the context limit: it summarizes the conversation history and keeps working. You can do better than the automatic pass by compacting on your own terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/compact Focus on the auth bug fix and the list of modified files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With instructions, the summary keeps what &lt;strong&gt;you&lt;/strong&gt; choose instead of what the automatic pass guesses is important.&lt;/p&gt;

&lt;p&gt;You can also set standing compaction instructions in your project's CLAUDE.md:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Compact instructions&lt;/span&gt;

When you are using compact, please focus on test output and code changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More options from the current docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/rewind&lt;/code&gt;&lt;/strong&gt; lets you select a message checkpoint and choose &lt;strong&gt;Summarize from here&lt;/strong&gt; (condenses everything after that point) or &lt;strong&gt;Summarize up to here&lt;/strong&gt; (condenses earlier messages, keeping recent ones in full).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/autocompact&lt;/code&gt;&lt;/strong&gt; with a token count (for example &lt;code&gt;/autocompact 500k&lt;/code&gt;) sets how full the context window gets before the automatic pass runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tip 4 - Keep CLAUDE.md lean
&lt;/h2&gt;

&lt;p&gt;CLAUDE.md is loaded at the start of &lt;strong&gt;every&lt;/strong&gt; conversation, so every line in it costs tokens on every message you send - forever, until you remove it. The docs' test for each line is simple: "Would removing this cause Claude to make mistakes?" If not, cut it. Bloated CLAUDE.md files are doubly expensive: they burn tokens AND cause Claude to ignore your actual instructions.&lt;/p&gt;

&lt;p&gt;Practical ways to slim it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;strong&gt;&lt;code&gt;/doctor&lt;/code&gt;&lt;/strong&gt; - its checkup proposes trims for a checked-in CLAUDE.md, cutting content Claude can derive from the codebase itself (directory layouts, dependency lists, architecture overviews) and keeping the parts it cannot (pitfalls, rationale, conventions that differ from tool defaults).&lt;/li&gt;
&lt;li&gt;Move knowledge that is only relevant sometimes into &lt;strong&gt;skills&lt;/strong&gt; (&lt;code&gt;.claude/skills/&lt;/code&gt;). Skill descriptions load at startup, but the full body loads only when the skill is invoked - domain knowledge on demand instead of in every conversation.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;path-scoped rules&lt;/strong&gt; for instructions that apply only to certain files; they load on demand alongside matching files.&lt;/li&gt;
&lt;li&gt;If you use the auto-memory file &lt;code&gt;MEMORY.md&lt;/code&gt;, note that only its first 200 lines (or 25KB) load at startup - keep the index concise and move detail into topic files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more detail worth knowing: &lt;code&gt;@path&lt;/code&gt; imports in CLAUDE.md help organization but do NOT reduce context, because imported files load together with the file that imports them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 5 - Send heavy reading to subagents
&lt;/h2&gt;

&lt;p&gt;Subagents run in their own context window with their own system prompt and return only a summary to your main conversation. That makes them the right tool whenever a side task would flood your context with search results, logs, or file contents you will never reference again - codebase exploration and research are the classic cases. Claude Code's built-in &lt;strong&gt;Explore&lt;/strong&gt; subagent exists exactly for this: Claude delegates searching and understanding the codebase to it, and the large file reads stay out of your main conversation.&lt;/p&gt;

&lt;p&gt;Two cost controls for subagents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For simple subagent tasks, set &lt;code&gt;model: haiku&lt;/code&gt; in the subagent configuration to run it on a lower-cost model. Defining a user or project subagent named &lt;code&gt;Explore&lt;/code&gt; overrides the built-in one while keeping its &lt;code&gt;model&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;Keep subagent &lt;code&gt;description&lt;/code&gt; fields short. All descriptions load into context so Claude can decide when to delegate, and Claude Code warns at startup when the combined custom descriptions exceed 15,000 tokens. Move detail into the subagent's system prompt, which loads only when that subagent runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest caveat: a subagent sends its own API requests, which count toward the same usage limits as your main conversation. Subagents save main-context tokens (the ones you repay on every turn); they do not make the work itself free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 6 - Tame your MCP servers
&lt;/h2&gt;

&lt;p&gt;MCP servers are the quiet token leak in many setups. The good news first: in current Claude Code, MCP tool definitions are &lt;strong&gt;deferred by default&lt;/strong&gt; - only tool names and server instructions enter your context until Claude actually uses a specific tool. Still, every connected server adds overhead, and the docs recommend two moves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefer CLI tools where they exist.&lt;/strong&gt; Tools like &lt;code&gt;gh&lt;/code&gt;, &lt;code&gt;aws&lt;/code&gt;, &lt;code&gt;gcloud&lt;/code&gt;, and &lt;code&gt;sentry-cli&lt;/code&gt; are more context-efficient than MCP servers because they add no per-tool listing at all - Claude just runs the CLI commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable servers you are not actively using.&lt;/strong&gt; Run &lt;strong&gt;&lt;code&gt;/mcp&lt;/code&gt;&lt;/strong&gt; to see the configured servers and toggle them off per project; the configuration is kept for when you need them back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To find out whether a server earns its keep, check the per-server attribution in &lt;code&gt;/usage&lt;/code&gt; (Tip 1) - an MCP server's share counts only the requests that actually consumed one of its tool results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 7 - Pick the right model for the job
&lt;/h2&gt;

&lt;p&gt;Model choice is the biggest per-token lever you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sonnet&lt;/strong&gt; handles most coding tasks well and costs less than Opus. Reserve &lt;strong&gt;Opus&lt;/strong&gt; for complex architectural decisions or multi-step reasoning.&lt;/li&gt;
&lt;li&gt;Switch mid-session with &lt;strong&gt;&lt;code&gt;/model&lt;/code&gt;&lt;/strong&gt;, or set a default in &lt;strong&gt;&lt;code&gt;/config&lt;/code&gt;&lt;/strong&gt;. Note that switching to Opus also applies to subagents that inherit your session's model.&lt;/li&gt;
&lt;li&gt;For simple subagent work, specify &lt;code&gt;model: haiku&lt;/code&gt; in the subagent configuration (Tip 5).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you routinely hit context limits on big tasks, the docs also list models with a 1 million token context window (Sonnet 4.6 and later, Haiku 5.5, Opus 4.6 and later), selectable as &lt;code&gt;[1m]&lt;/code&gt; variants. A bigger window raises the ceiling; the tips above lower the bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 8 - Preprocess with hooks
&lt;/h2&gt;

&lt;p&gt;Hooks run scripts automatically at points in Claude's workflow, and unlike CLAUDE.md instructions they are deterministic - the action always happens. A &lt;strong&gt;PreToolUse&lt;/strong&gt; hook can filter command output before it ever reaches the context. The docs' example: instead of Claude reading a 10,000-line log to find errors, a hook greps for &lt;code&gt;ERROR&lt;/code&gt; and returns only matching lines - tens of thousands of tokens become a few hundred.&lt;/p&gt;

&lt;p&gt;Here is the docs' pattern, adapted to also catch Maven and Gradle test runs. Add the hook to your &lt;code&gt;settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PreToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.claude/hooks/filter-test-output.sh"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then save this as &lt;code&gt;~/.claude/hooks/filter-test-output.sh&lt;/code&gt; and make it executable (&lt;code&gt;chmod +x&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# If running tests, filter to show only failures&lt;/span&gt;
&lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'^(npm test|pytest|go test|mvn test|./mvnw test|./gradlew test)( [^;&amp;amp;|&amp;lt;&amp;gt;`$#\\[:cntrl:]]*)?$'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="nv"&gt;$pattern&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;filtered_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"f=&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;(mktemp); &lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;f&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; 2&amp;gt;&amp;amp;1; s=&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;?; grep -A 5 -E '(FAIL|ERROR|error:)' &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;f&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | head -100; echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;[exit &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;s - full output at &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;f]&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;; exit &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;s"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;--arg&lt;/span&gt; filtered &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filtered_cmd&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s1"&gt;'{hookSpecificOutput: {hookEventName: "PreToolUse", updatedInput: (.tool_input + {command: $filtered})}}'&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"{}"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the command is a test run, the hook rewrites it so Claude sees only the failure lines; anything else passes through unchanged.&lt;/p&gt;

&lt;p&gt;A word on doing this safely, because the naive version of this idea can mislead Claude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preserve the exit status.&lt;/strong&gt; A pipeline's exit code is its last command's, so &lt;code&gt;cmd | grep | head&lt;/code&gt; would report success whenever &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;head&lt;/code&gt; succeed - even when the tests themselves failed. That is how Claude ends up believing broken tests are green. The script above saves the original exit code (&lt;code&gt;s=$?&lt;/code&gt;) and exits with it, so a failing run still looks like a failure. (Verified locally: failing tests exit 1, a crash with no matching output still exits 134.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the full output reachable.&lt;/strong&gt; &lt;code&gt;grep -A 5&lt;/code&gt; and &lt;code&gt;head -100&lt;/code&gt; can cut a stack trace's root cause, and merging stderr into the filter (&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt;) drops any error text that does not match the pattern - compiler errors in an unusual format, OOM crashes, "Aborted". The script writes the complete output to a temp file and prints its path, so Claude can read the full log when the filtered view is not enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only simple commands get filtered.&lt;/strong&gt; The pattern's argument part rejects &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, backticks and other shell metacharacters, so anything complex (pipelines, command substitution) runs exactly as written instead of being mangled by the rewrite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtering is lossy by design.&lt;/strong&gt; Treat the filtered view as a first look. For security-sensitive output (dependency audits, secret scanners), do not filter at all - a hidden warning is worse than a big context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same pattern works for build logs or any chatty, non-sensitive command you run often - apply the safety points above each time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 9 - Small habits that add up
&lt;/h2&gt;

&lt;p&gt;A few one-liners from the docs that are easy to adopt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;/btw&lt;/code&gt; for side questions.&lt;/strong&gt; The answer never enters the conversation history, so you can check a detail without growing (and paying for) the context on every following turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be specific in prompts.&lt;/strong&gt; "fix the login bug" sends Claude exploring; "login fails after session timeout - check the auth flow in src/auth/, especially token refresh, and write a failing test first" goes straight to the files that matter. Specific prompts mean fewer exploratory file reads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install code intelligence plugins for typed languages.&lt;/strong&gt; A single "go to definition" call replaces a grep plus reading multiple candidate files, and the language server reports type errors after edits without a compiler run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let prompt caching work for you.&lt;/strong&gt; Claude Code automatically caches repeated content like the system prompt, and the &lt;code&gt;Prompt cache (main)&lt;/code&gt; line in &lt;code&gt;/usage&lt;/code&gt; tells you the share of input tokens served from cache - in the docs' example session, 91% - so you can see it working.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Measure first: &lt;code&gt;/usage&lt;/code&gt; for cost and attribution, &lt;code&gt;/context&lt;/code&gt; for what is filling the window, &lt;code&gt;/insights&lt;/code&gt; for patterns.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/clear&lt;/code&gt; between unrelated tasks (&lt;code&gt;/rename&lt;/code&gt; first, &lt;code&gt;/resume&lt;/code&gt; to return); compact long sessions with focused instructions.&lt;/li&gt;
&lt;li&gt;Keep CLAUDE.md lean - every line rides along on every message. Move on-demand knowledge to skills and path-scoped rules.&lt;/li&gt;
&lt;li&gt;Delegate heavy reading to subagents, run simple ones on &lt;code&gt;haiku&lt;/code&gt;, and keep their descriptions short.&lt;/li&gt;
&lt;li&gt;Prefer CLI tools over MCP servers, and disable servers you are not using.&lt;/li&gt;
&lt;li&gt;Match the model to the task: Sonnet by default, Opus for the hard parts, Haiku for simple subagents.&lt;/li&gt;
&lt;li&gt;Preprocess noisy command output with PreToolUse hooks, and use &lt;code&gt;/btw&lt;/code&gt; for questions that do not need to stay in context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Token optimization in Claude Code is really context optimization. Trimming irrelevant context reduces the input you send on each turn - on API billing that is direct cost saved, and on a subscription it stretches your usage limits further. And since the docs note that performance degrades as context fills, a leaner context can also help Claude stay focused.&lt;/p&gt;

&lt;p&gt;Happy coding, and stay tuned for the next post!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources (official Claude Code docs, checked October 2026):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/costs" rel="noopener noreferrer"&gt;Manage costs effectively&lt;/a&gt; - /usage, prompt cache line, recommendations, reduce token usage checklist&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/context-window" rel="noopener noreferrer"&gt;Explore the context window&lt;/a&gt; - /context, /compact, /rewind, /autocompact, /clear, what survives compaction&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/best-practices" rel="noopener noreferrer"&gt;Best practices&lt;/a&gt; - specific prompts, /btw, CLAUDE.md guidance, code intelligence plugins&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/memory" rel="noopener noreferrer"&gt;Memory (CLAUDE.md)&lt;/a&gt; - file loading rules, /doctor trims, MEMORY.md limits, &lt;a class="mentioned-user" href="https://dev.to/path"&gt;@path&lt;/a&gt; imports&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/sub-agents" rel="noopener noreferrer"&gt;Subagents&lt;/a&gt; - separate context windows, Explore, model: haiku, description token warning&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/mcp" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; - deferred tool definitions, /mcp panel, disabling servers&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>claude</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
