Java Code Review: Process, Checklist, and Critical Points
Java code review works best when the team has a clear process. Without that, review turns into a mix of opinion, style comments, architecture discussions, and bugs slipping through the diff.
A good review needs to answer a few simple questions: does the change do what it is supposed to do? Is the code easy to maintain? Is there any security, performance, or concurrency risk? Do the tests cover the most important behavior? Is the PR small enough to be reviewed carefully?
This guide shows a practical Java code review process, with a technical checklist and points that deserve attention in projects with Spring, JPA, APIs, jobs, and backend services.
Java code review process: quick overview
| Step | What to do | What to check in Java |
|---|---|---|
| Before opening the PR | Run tests, build, lint, and self-review | JUnit, Maven/Gradle, Checkstyle, SpotBugs, PMD |
| PR description | Explain the problem, solution, risk, and how to test | Endpoints, migrations, jobs, events, and affected flows |
| Automated review | Let tools catch repetitive problems | Style, likely bugs, dependencies, security, and coverage |
| Human review | Evaluate design, business rules, and maintainability | Spring, JPA, concurrency, exceptions, performance, and tests |
| Adjustments and merge | Respond to feedback, fix risks, and validate CI | No regressions, no critical warnings, no hidden debt |
Why Java code review needs special attention
Java is common in large systems, with multiple layers, integrations, business rules, and long lifecycles. A small piece of code in the diff can affect transactions, JPA queries, queues, caches, permissions, or asynchronous jobs.
There is also a false sense of safety. The compiler helps, types help, the IDE helps. Even so, many important issues only appear when someone looks at the behavior of the change. A query can pass tests and still create an N+1 problem in production. A method can compile and still swallow a critical exception. A class can look simple and still open the door to poor coupling.
That is why Java code review needs to combine tools and analysis from people who know the system. Tools catch the repetitive work. People evaluate context, design, and the real impact of the change.
Before opening the pull request
Before asking for review, the author should review their own PR carefully. This prevents reviewers from wasting time on problems that could have been fixed earlier.
- The build passes locally with Maven or Gradle.
- The relevant tests were executed.
- There are no temporary logs, dead code, or debug comments.
- New dependencies were justified.
- The PR is focused on one main change.
- The description explains the reason for the change and how to test it.
If the PR changes critical behavior, such as checkout, authorization, payment, financial calculations, or asynchronous processing, make that clear in the description. That way, reviewers know where to focus their attention.
How to write a Java PR that is easy to review
An easy-to-review PR makes the intent of the change clear. Reviewers should not need to reconstruct the entire story in another tool to understand what is happening.
## What changed?
Explain the main change in a few sentences.
## Why does this change exist?
Link to the ticket, bug, business rule, or technical decision.
## How was it tested?
List unit tests, integration tests, manual tests, and critical scenarios.
## Risks
Mention migrations, transactions, queues, caches, permissions, or affected integrations.
## Review focus
Tell the reviewer where they should pay more attention.
If there was a visual change, include a screenshot. If there was a migration, explain whether it is reversible. If there was a change to a public API, document the impact on consumers.
Automatic checks for Java
The basics should not depend on manual comments. Formatting, imports, simple style rules, likely bugs, and vulnerable dependencies should appear before human review.
| Tool | What it helps review |
|---|---|
| Checkstyle | Style conventions, imports, formatting, and project standards |
| SpotBugs | Likely bugs, incorrect API usage, and dangerous patterns |
| PMD | Complexity, duplication, and common bad practices |
| Error Prone | Errors detectable at compile time |
| OWASP Dependency-Check | Dependencies with known vulnerabilities |
Kodus works in another layer. Instead of replacing a linter, it reviews the pull request with repository context, team-specific rules, and cross-file analysis. In projects that use Java, this helps find problems that traditional tools do not always understand well, such as incorrect transaction usage, risks in Spring flows, changes that are hard to maintain, missing tests for business rules, and alignment with what was requested in the issue or spec.
How to review readability in Java code
Java tends to be explicit. That helps, but it also makes it possible to create huge classes with generic names and too many responsibilities.
During review, look at names as if you were going to maintain that code six months from now. process(), handle(), data, and manager rarely say enough. Names like recalculateInvoiceTotals(), CustomerEligibilityService, or PaymentAttemptRepository make the intent clearer.
Also look at the responsibility of the class. If it validates input, calculates business rules, persists data, and also publishes events, it may be accumulating too many decisions in one place.
Logic, edge cases, and real behavior
After understanding the change, validate the behavior: does the code do what the product needs?
Look for scenarios outside the expected flow:
- null input;
- empty collection;
- dates with time zones;
- financial values with rounding;
- user without permission;
- external integration down;
- duplicate message in a queue;
- event arriving out of order.
When the PR fixes a bug, ask for a regression test. Without that, the problem can come back in a future change.
Resource management
Files, streams, sockets, readers, and connections need to have a clear lifecycle. If the object implements AutoCloseable, the review should look for the use of try-with-resources.
try (BufferedReader reader = Files.newBufferedReader(path)) {
return reader.readLine();
}
Oracle’s documentation on try-with-resources shows exactly this point: the resource is closed at the end of the block, including when an exception happens.
This detail looks small in the diff. In a high-load service, a connection, stream, or socket leak can become an incident.
Exceptions and logs
In Java, error-handling problems often appear when code catches exceptions too broadly or leaves important failures untreated.
During review, check for:
- empty
catch; catch (Exception e)without a clear reason;catch (Throwable t)in common application code;- logs without context for later investigation;
- logs with sensitive data;
- external errors treated as silent success.
The code needs to make clear what happens when something fails. Sometimes the right answer is to retry. Sometimes it is to return an error. In other cases, it is to stop the flow to preserve consistency. The review should evaluate whether that choice makes sense.
Spring: what to review more carefully
In Spring projects, a small change in the diff can significantly change the application’s runtime behavior.
Check mainly:
- whether
@Transactionalis in the right layer; - whether a transaction does not wrap an HTTP call or an operation that is too slow;
- whether controllers are not carrying business logic;
- whether services have not become classes with too many responsibilities;
- whether input validation is at the system boundary;
- whether changes in beans or configs affect other flows.
A common case is using @Transactional to work around a lazy loading error. It may work in the short term, but it can also hide a modeling, query, or layer boundary problem.
JPA and Hibernate
JPA requires special attention during review. The code may look simple in Java, but generate expensive queries, N+1 problems, or dangerous database changes.
Look for:
- N+1 queries;
- lazy loading outside the expected context;
- queries without pagination;
- new relationships between entities;
- migrations that lock large tables;
- batch operations done item by item;
- cascade changes without explicit discussion.
If the PR changes an entity, repository, or migration, ask for a test or validation with realistic data. It does not need to be perfect, but “I ran it on my empty local database” is usually not enough for this kind of change.
Performance and data structures
Performance in Java does not always start with a profiler. Often, the problem is in a data structure that does not match the expected volume.
An ArrayList iterated several times may work well with 20 items and become a problem with 200,000. A HashMap or Set may be more appropriate when the main operation is lookup.
Also look for nested loops over large collections, unnecessary object creation in heavily executed flows, database calls inside loops, and streams that make a simple rule harder to read.
Concurrency and asynchronous code
When the code involves threads, executors, queues, or asynchronous tasks, review more carefully. Concurrency bugs rarely appear in the simplest tests and may only show up in production.
Check whether there is shared mutable state, whether the structure being used is concurrency-safe, and whether exceptions in asynchronous tasks are observed. The java.util.concurrent documentation is a good reference for queues, locks, executors, and atomic classes.
Also ask whether the code really needs concurrency. Sometimes the PR adds async to compensate for a slow operation that should be reviewed.
Security in Java code review
Security review starts at the system boundaries: controllers, queue consumers, jobs, external integrations, and anywhere that receives outside data.
If the code builds SQL by concatenating strings with external input, that needs to be adjusted before merge. In JDBC, use PreparedStatement or a layer that handles parameters correctly.
PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM users WHERE email = ?"
);
statement.setString(1, email);
The OWASP guide on SQL injection recommends parameterized queries as the primary defense.
Also review:
- whether external inputs are validated on the backend;
- whether new endpoints have correct authorization;
- whether logs do not expose tokens, documents, emails, or sensitive data;
- whether new dependencies were checked;
- whether secrets do not appear in code or versioned files.
Tests in Java PRs
A weak test can give a false sense of safety. In code review, look at what the test actually validates.
For Java changes, it is usually worth looking for:
- unit test for business logic;
- integration test when there is a database, queue, or external API;
- regression test for a bug fix;
- test for error, null value, and empty list;
- permission test when the change touches access;
- test with enough data to reveal a query problem.
JUnit and Mockito cover many unit cases. For databases and integrations, Testcontainers can help when the behavior depends on real infrastructure.
Technical Java code review checklist
1. Readability and design
- Is the intent of the code clear without external explanation?
- Are class, method, and variable names specific?
- Do methods and classes have clear responsibility?
- Does the code follow the patterns of the surrounding codebase?
- Do comments explain decisions that are not obvious?
2. Behavior and performance
- Does the code do what the ticket describes?
- Were null cases, empty lists, and boundary values handled?
- Is there any repeated query, expensive loop, or inadequate data structure?
- Are resources closed correctly?
- Can the PR affect a critical production flow?
3. Spring and persistence
- Is
@Transactionalin the right place? - Is there a risk of N+1 in JPA or Hibernate?
- Do large queries have pagination?
- Were migrations designed with existing data in mind?
- Do controllers, services, and repositories keep clear boundaries?
4. Errors and resilience
- Is there no empty
catch? - Does the code avoid catching
Exceptionunnecessarily? - Do external failures have timeout, retry, or fallback when it makes sense?
- Do logs help investigation without exposing sensitive data?
5. Security
- Are external inputs validated on the backend?
- Do queries use parameters instead of string concatenation?
- Are there no hardcoded secrets?
- Were permissions reviewed on the affected endpoints?
- Were new dependencies checked?
6. Tests
- Does the new logic have a relevant test?
- Does the bug fix have a regression test?
- Do tests validate behavior, not just absence of exceptions?
- Were error and edge cases covered?
- Is the code testable without too many mocks?
How Kodus helps with Java code reviews
Kodus enters the pull request as an AI review layer, but without being stuck with generic comments on the diff. It can run automatically when a PR is opened or updated, and it can also be called manually when the team wants to review again after adjustments.
In Java projects, this mainly helps with the points traditional linters usually do not catch: cross-file risks, changes in services and repositories, incorrect transaction usage, missing tests for business rules, weak input validation, poor exception handling, and changes that deviate from the architecture agreed on by the team.
The team can also create Kody Rules to turn internal standards into review rules. For example: every new endpoint needs a test, changes in sensitive directories require extra attention, services should not access a certain layer directly, or PRs that are too large need to be flagged before a person reviews them.
These rules can be applied by file or to the entire pull request. They consider PR context, such as title, description, changed files, and complete diff, as well as references to files in the repository itself. For Java teams, this makes it possible to create specific standards for Spring, JPA, transactions, security, tests, and layer organization.
Another option is to use the Kodus rules library. Instead of starting from scratch, the team can search ready-made rules by severity, language, or tags, import what makes sense, and activate them in a few clicks. After that, each rule can be adjusted to reflect the real conventions of the codebase.
To check whether the PR implements what was requested, Kodus also has Business Logic Validation. It compares the diff with an issue, spec, document, or acceptance criteria, and points out when something required was left out of the implementation. This is useful in changes involving business rules, because the risk is not always in syntax or style, but in incomplete behavior.
Kodus is open source, available on GitHub, and supports BYOK. The team can use its own model key, choose the provider, and keep control over cost, configuration, and internal AI policy.
FAQ about Java code review
How do you do code review in Java?
Start with the PR goal, run automatic checks, and then review behavior, readability, security, performance, exceptions, and tests. In Java projects, also look at Spring, JPA, transactions, concurrency, and resource management.
What should you check in a Java code review?
Check names, class structure, business rules, collection usage, queries, exception handling, input validation, dependencies, tests, and production impact. The review should find risks that the compiler, linter, and tests may not catch on their own.
What is the ideal process for reviewing Java PRs?
A good process starts with the author’s self-review, goes through build, tests, and automatic checks, moves to human review focused on behavior and design, then returns for adjustments and final validation before merge.
Which tools help with Java code review?
Checkstyle, SpotBugs, PMD, Error Prone, OWASP Dependency-Check, JUnit, Mockito, Testcontainers, and AI review tools like Kodus can help.
How do you review Java code with Spring?
In Spring projects, review separation between controllers, services, and repositories, use of @Transactional, input validation, error handling, endpoint security, and the impact of changes in beans, events, and configurations.
How do you avoid security issues in Java?
Validate external inputs on the backend, avoid concatenated SQL, use parameterized queries, do not expose secrets, review permissions, and check vulnerable dependencies. It is also worth checking logs to make sure sensitive data is not being recorded.
Conclusion
Java code review improves when the team knows what each part of the process should catch. Tools handle the repetitive work. People look at behavior, architecture, security, and maintainability.
When this flow is clear, review depends less on individual memory. The PR arrives with more context, risks appear earlier, and the team spends less energy discussing details that could have been automated.