The guide + private style inspector

Write Java
people trust.

Learn the standard, then check your own code against it. Get line-level guidance for readable, typed, testable, production-ready Java—without sending your code anywhere.

Evidence-led, not dogmatic.
Reviewed against primary sources · July 2026

service.java ● typed
import java.util.Comparator;
import java.util.List;

final class UserService {
    List<String> activeNames(List<User> users) {
        return users.stream()
                .filter(User::isActive)
                .map(User::name)
                .sorted(Comparator.naturalOrder())
                .toList();
    }
}
All checks passed 0.18s
Aa Readable by defaultOptimize for the next person.
Low noiseTools handle the trivia.

Built-in utility

Paste. Inspect.
Improve.

Get an immediate, line-by-line review based on this guide’s core principles. Every finding explains what matters and suggests a concrete next move.

Private by designYour code never leaves this browser.
Your Java
0 lines · 0 characters
+ Enter

FORMATIndentation · whitespace · line length · statements

INTENTNaming · imports · generics · complexity

SAFETYNulls · exceptions · secrets · shell use

SCOPEFast heuristic review · not a compiler or CI replacement

01Instant style reviewLine-level, private feedback

02Google Style groundedCanonical rules, with context

03Production mindedAPIs, tests, security, CI

04Actionable guidanceEvery finding explains why

The north star

Style is how code
communicates intent.

Great Java feels intentional. Readers spend their attention on the problem—not decoding inconsistent names, hidden nulls, overgrown classes, or invisible side effects.

01

Readability counts

Choose explicit names, linear control flow, and small interfaces. Code is read far more often than it is written.

Make intent visible
02

Boundaries matter

Validate at the edges, type public contracts, and keep side effects easy to find. Make invalid states hard to represent.

Design clear contracts
03

Automate consistency

Let formatters, linters, type checkers, and tests settle mechanical questions before review begins.

Build the safety net

Express ideas directly in code.
Prefer clear APIs over clever plumbing.
Make invalid states hard to represent.

— Google Java Style, Effective Java, Oracle guidance

The practical guide

From first line to
production.

Use these as strong defaults. Every rule has a purpose; when the rule obscures that purpose, use judgment and document the exception.

01

Format & name

Remove friction
before it starts.

Formatting should be boring, predictable, and automated. Names should carry enough meaning that comments explain why, not what a variable contains.

01.1

Indent with spaces

Follow the project formatter. Google Java Style uses two spaces; many teams choose four. Do not mix tabs and spaces, and let the formatter settle layout debates.

return users.stream()
    .filter(User::isActive)
    .map(User::name)
    .toList();
01.2

Use a deliberate line length

Keep lines easy to review. This guide flags lines over 100 characters; configure google-java-format, Spotless, or Checkstyle so the choice is automatic.

100commonautoformatter enforced
01.3

Name for the reader

Use UpperCamelCase for classes, lowerCamelCase for methods and fields, and UPPER_SNAKE_CASE for constants. Avoid vague containers like data, info, and utils.

invoiceTotalvariable PaymentClientclass MAX_RETRIESconstant
× Avoid
Hidden meaning
double calc(List<Item> items, boolean f) {
    double x = 0;
    for (Item item : items) x += item.value();
    return f ? x * 1.2 : x;
}
Prefer
Intent in the names
Money invoiceTotal(List<LineItem> lineItems,
                   TaxMode taxMode) {
    Money subtotal = Money.zero();
    for (LineItem item : lineItems) {
        subtotal = subtotal.plus(item.price());
    }
    return taxMode == TaxMode.INCLUDE
            ? subtotal.times(TAX_RATE)
            : subtotal;
}
02

Modern Java patterns

Idiomatic,
not clever.

Modern Java uses records, streams, sealed types, and pattern matching when they clarify the model. It avoids clever chains when a small method would communicate better.

Guard early

Return or throw at boundaries so the happy path stays flat and readable.

Prefer immutability

Use final fields, records, defensive copies, and unmodifiable views for stable state.

Compare correctly

Use equals, Objects.equals, or domain predicates for object equality.

Stream with restraint

Streams are great for transformations; use a loop when branching or side effects dominate.

orders.java
Receipt dispatch(Order order, Warehouse warehouse) {
    if (order.items().isEmpty()) {
        throw new EmptyOrderException(order.id());
    }

    if (order.status() != OrderStatus.PAID) {
        throw new OrderNotPaidException(order.id());
    }

    List<Item> available = order.items().stream()
            .filter(item -> warehouse.hasStock(item.sku()))
            .toList();
    return warehouse.dispatch(available);
}
1 Guard clauses expose invalid states. 2 An enum makes a closed state explicit. 3 The stream names the filtering step.
03

Types & boundaries

Turn assumptions
into contracts.

Concrete types, generics, records, annotations, and clear absence handling make APIs searchable and mistakes cheaper. They are most valuable at public boundaries and code that changes often.

Wide in

Accept the smallest useful interface: List, Collection, Iterable, or a domain-specific command object.

Narrow out

Return a concrete, predictable type. Use Optional sparingly for return values where absence is expected.

Explicit nulls

Document nullability with annotations or forbid it by policy. Do not make callers guess.

pricing.java
record Priced(Money price) {}
record BasketSummary(int itemCount, Money total) {}

BasketSummary summarize(List<Priced> items) {
    Money total = items.stream()
            .map(Priced::price)
            .reduce(Money.zero(), Money::plus);
    return new BasketSummary(items.size(), total);
}
i

Set a version floor. Declare a supported JDK once in Maven or Gradle, then use the modern syntax that floor supports. Java 21 is a strong current LTS default for new production work.

04

Methods & data

Keep the center
of gravity small.

Methods

  • Do one thing at one level of abstraction.
  • Make dependencies and side effects explicit.
  • Use enums, records, or small value objects for ambiguous values.
  • Return consistently; use results, optionals, or exceptions deliberately.

Classes & data

  • Prefer records for transparent value carriers.
  • Keep fields private and final unless mutation is part of the model.
  • Prefer composition over inheritance.
  • Expose small public APIs; keep internals replaceable.
05

Errors & logging

Fail with context,
not confusion.

Errors are part of your API. Catch only what you can handle, preserve context, and make the operational trail useful without leaking sensitive data.

× Avoid
Swallowed failure
try {
    gateway.charge(card);
} catch (Exception e) {
    System.out.println("Something went wrong");
    return false;
}
Prefer
Precise and traceable
try {
    Receipt receipt = gateway.charge(request);
} catch (GatewayTimeoutException ex) {
    logger.warn("Payment timed out for order {}", order.id(), ex);
    throw new PaymentUnavailableException(order.id(), ex);
}
05.1

Use domain exceptions

Name the failure in the language of the caller. Keep exception hierarchies shallow.

05.2

Libraries log carefully

Applications own sinks, levels, and formatting. Libraries should preserve causes and avoid noisy global configuration.

05.3

Never log secrets

Treat tokens, credentials, payment data, and personal information as toxic. Redact at the boundary.

06

Project structure

Make the right place
obvious.

acme-service/

├── build.gradle.kts
├── src/
│   ├── main/
│   │   ├── java/com/acme/service/
│   │   │   ├── OrderService.java
│   │   │   └── PricingPolicy.java
│   │   └── resources/
│   └── test/
│       └── java/com/acme/service/
│           └── PricingPolicyTest.java
└── README.md
01

Use standard source sets

Keep production and test code separate with Maven or Gradle conventions.

02

Package by responsibility

Prefer cohesive packages over a catch-all utils. Mirror domain concepts, not framework jargon.

03

Make boundaries visible

Keep controllers, services, repositories, and clients easy to locate and review.

Import order

1Static imports2Standard library3Third party4Project
One import per line; avoid wildcards; keep static imports narrow and obvious.
07

Testing

Test behavior,
not choreography.

FastUnit tests run constantly.

FocusedOne behavior, clear failure.

FaithfulIntegration tests cover real boundaries.

IndependentNo order or shared-state surprises.

PricingPolicyTest.java
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

class PricingPolicyTest {
    @Test
    void discountedTotalAppliesPercentageDiscounts() {
        assertThat(discountedTotal(Money.of(100), 0.10))
                .isEqualTo(Money.of(90));
    }
}

Coverage is a map, not a target. Use it to find untested risk; a high percentage cannot prove useful assertions.

08

Reliability

Be safe under
real conditions.

Security

  • Never hard-code secrets.
  • Validate untrusted input at boundaries.
  • Avoid shell strings, unsafe deserialization, and SQL concatenation.
  • Audit dependencies and lock applications reproducibly.

Performance

  • Measure before optimizing.
  • Fix algorithms and I/O before micro-tuning syntax.
  • Benchmark representative workloads.
  • Keep performance choices readable and documented.

Concurrency

  • Use executors, structured concurrency, or virtual threads deliberately.
  • Use immutable data and thread-safe collections at shared boundaries.
  • Bound queues, fan-out, lifetimes, and shutdown paths.
  • Test cancellation, interruption, and timeouts.
!

Make failure finite. Network calls need explicit timeouts, retries need backoff and a cap, queues need bounds, and shutdown paths need tests.

The modern toolchain

Automate the
boring parts.

Use one command locally and the same command in CI. The exact tools can change; the feedback loop should remain fast and dependable.

A pragmatic baseline

One file.
Shared expectations.

Put supported configuration in Gradle or Maven, then check in formatter and static-analysis settings. Start focused; add stricter rules because they catch problems your team actually has—not because a tool offers them.

  • Formatting and import order are automatic.
  • Rule selection is explicit and reviewable.
  • The Java version is declared once.
build.gradle.kts
plugins {
    java
    id("com.diffplug.spotless") version "6.25.0"
    id("net.ltgt.errorprone") version "4.1.0"
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

repositories { mavenCentral() }

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.11.4")
    errorprone("com.google.errorprone:error_prone_core:2.36.0")
}

spotless {
    java { googleJavaFormat() }
}

tasks.test { useJUnitPlatform() }

NoteThis is a starting point, not universal law. Match the JDK, formatter, static-analysis checks, dependency policy, and framework versions to the oldest runtime you actually support.

Before you merge

The ten-minute
quality pass.

A compact review for the risks automation cannot fully understand. Your progress is saved on this device.

0/ 10 complete

The Java bookshelf

Six books worth
keeping close.

Enduring references and modern practitioner favorites, selected for a useful path from first Java program to maintainable production systems.

Start hereHead FirstCore Java

Write better codeEffectiveModern Java

Build for productionConcurrencySpring

Cover of Head First Java
Beginner favorite
Beginner2022

Head First Java

Sierra · Bates · Gee · 3rd edition

A friendly, visual path through real-world Java programming, updated for Java 8–17.

Best forFirst serious Java learning
View at publisher
Cover of Core Java, Volume I: Fundamentals
Deep reference
Intermediate2025

Core Java, Volume I

Cay S. Horstmann · 13th edition

A detailed, current treatment of the Java language, APIs, generics, collections, lambdas, modules, and concurrency.

Best forExperienced programmers who want depth
View at publisher
Cover of Effective Java
Best-practice classic
Intermediate2018

Effective Java

Joshua Bloch · 3rd edition

Concise, specific guidance on objects, generics, lambdas, streams, exceptions, concurrency, and serialization.

Best forTurning working Java into excellent Java
View at publisher
Cover of Modern Java in Action
Modern idioms
Intermediate2018

Modern Java in Action

Urma · Fusco · Mycroft

A practical guide to lambdas, streams, functional style, reactive programming, and modern language features.

Best forUsing modern Java deliberately
View at publisher
Cover of Java Concurrency in Practice
Concurrency classic
Advanced2006

Java Concurrency in Practice

Goetz · Peierls · Bloch · Bowbeer · Holmes · Lea

The classic mental model for thread safety, publication, synchronization, liveness, and the Java Memory Model.

Best forReasoning about shared state
View at publisher
Cover of Spring in Action, Sixth Edition
Production framework
Framework2022

Spring in Action

Craig Walls · 6th edition

A practical route through Spring, Spring Boot, data access, REST services, security, and reactive applications.

Best forBuilding production Java services
View at publisher

Editorial noteSelections are independent and use current English-language editions reviewed July 2026. Labels are editorial recommendations, not live sales rankings. No affiliate links or paid placements.

Primary sources

Go deeper.

This guide synthesizes standards and practice. When precision matters, follow the living source.

Java is a registered trademark of Oracle and/or its affiliates. This independent guide is not affiliated with or endorsed by Oracle, Google, Maven, Gradle, or the JUnit team. Last editorial review: July 19, 2026.

Copied to clipboard