Posts

Showing posts with the label Java

Java Singleton Pattern: Enum, Lazy Holder & Double-Checked Locking Explained

Maya's bookstore app has grown since the last post. Checkout, receipts, and nightly reports all need the same shop settings: the store name, the currency, and the tax rate. Each part of the app loads those settings its own way — checkout reads the settings file when it starts, receipts read it again when printing, reports read it a third time overnight. That worked until the day Maya changed the tax rate at noon: checkout used the new rate, receipts still used the old one, and the day's books did not reconcile. Three copies of "the settings" turned out to be three chances to disagree. This post is about the pattern that answers a different question from the last one. Post 1, Design Patterns in Java: What They Are, When to Use Them, and When Not To , asked what varies? This post asks how many? — and when the honest answer is "exactly one," the Singleton pattern is the shape for it. The principle for this lesson: a singleton answers "how many?" —...

Design Patterns in Java: What They Are, When to Use Them, and When Not To

Maya runs a small online bookstore. Her checkout code started simple: add up the cart, apply a discount, print a receipt. Then the business grew. Students asked for 10% off. A seasonal sale added 15%. Loyal customers earned 5%. Each new rule meant opening the checkout code, adding another branch, and re-testing everything the checkout already did — because every edit touched the same method that all the old rules lived in. This is the exact moment design patterns exist for. Not as clever tricks, and not as a badge of seniority — as answers to a recurring question: this part of my program keeps changing; how do I shape the code so the next change is small and safe? This post answers that question with one pattern, worked end to end, and gives you the map for the rest of the track. The principle for this lesson: give what varies a name and a seam. 1. The customer problem Maya's checkout has one job that never changes — turn a cart into a total and a receipt — and one part that ...

JDK 27 Released: G1 GC Is Now the Default, Compact Object Headers & Post-Quantum TLS — Should You Upgrade?

On September 15, 2026 , JDK 27 reached general availability — the 18th feature release in a row to ship on Java's six-month cadence. It carries nine JEPs, but the headline is not the count. It is this: JDK 27 is the release where Java stops asking you to opt in to good defaults and turns them on. Two of the four finalized JEPs quietly change how your running services behave without you touching a line of code — and a third hardens every TLS connection your apps make against quantum computers. If your services run in small containers and you never set a GC flag, this release changes your garbage collector. Read on before you bump the base image. The release at a glance Four JEPs are final and active with no special flags; the rest stay in preview or incubator, meaning their APIs can still change: JEP Feature Status 523 Make G1 the default garbage collector in all environments Final 527 Post-quantum hybrid key exchange for TLS 1.3 Final 534 Compact object headers by defa...

Building a Production RAG Service in Java: A Complete Guide

Your manager's exact words: "We're launching the docs assistant to customers next month. It needs to be reliable, observable, and safe." Not "build a chatbot." Not "demo something with an LLM." A service — one that strangers will rely on, that breaks at 2 AM, that answers questions about your product with your company's name on every response. Everything in this track was preparation for this moment. Calling LLMs from Java gave you the client. Prompt engineering gave you the answer-shaping. Embeddings and vector search gave you retrieval. RAG from scratch gave you the grounded-answer loop. LangChain4j and Spring AI showed you the framework options. Function calling taught you structured outputs. Evals taught you how to measure. This post assembles all of it into one coherent service skeleton — the ingestion pipeline, the query path, and the production concerns that separate a demo from a service: configuration, guardrails, observability,...

LLM Evals in Java: How to Test Non-Deterministic AI Systems

You shipped the summarizer on Tuesday. It takes an earnings-call transcript and returns JSON — a title plus three bullets — that the mobile app parses and renders as a card. On Thursday you tweaked the system prompt: "be a bit more conversational, users find raw JSON cold." You eyeballed three outputs. They looked warmer, friendlier, better. You shipped it. The following Tuesday, support tickets arrive: the mobile card is blank. Your "warmer" prompt now wraps the JSON in chatty prose — Here is your summary! on top, Hope that helps. at the bottom. The mobile parser, which does exactly what it was told and extracts nothing gracefully, choked on the preamble. A week of summaries silently failed to render, and the only reason you found out is that a user complained. Your three eyeballed samples all happened to be clean. This is the testing gap every AI feature has. The prompt is code, the model is a dependency you don't control, and "it looked fine...