Why Code Review is Not About Nitpicking, But About Quality
\nImagine: you open a colleague's pull request. There are 500 lines of code, it smells of copy-paste, and in one place someone forgot to close a resource. Your task is not just to find bugs, but to make the code better. Code review in Java is not police surveillance, but collaborative creativity. A good reviewer saves the team from technical debt, a bad one demotivates or lets vulnerabilities slip through.
\nIn this article, I will tell you what to check in a code review in Java, so you don't waste time on trivialities but don't miss the critical. You will get a ready-made checklist and real-world examples.
\n\nArchitecture and Design: Look at the Root
\nBefore diving into details, assess the big picture. Bad architecture cannot be fixed with formatting.
\nViolation of SOLID
\nCheck if the class has turned into a "god object". An example of violating Single Responsibility:
\npublic class OrderService {\n public void createOrder(Order order) {\n // validation\n // discount calculation\n // sending email\n // logging\n // saving to DB\n }\n}\n\nHere there are five reasons for change. The correct approach is to extract logging and sending into separate services.
\nExcessive Complexity
\nSometimes code solves a simple problem in a complex way. Ask yourself: "Can it be simpler?" If yes, write it in the review. Remember the KISS principle.
\n\nSecurity: Holes You Must Not Miss
\nJava code review must include a security check. Even if the project is internal.
\nSQL Injection
\nString concatenation is evil:
\n// BAD\nString query = "SELECT * FROM users WHERE name = '" + userName + "'";\nStatement stmt = connection.createStatement();\nResultSet rs = stmt.executeQuery(query);\n\nThe correct way is to use PreparedStatement:
// GOOD\nString query = "SELECT * FROM users WHERE name = ?";\nPreparedStatement pstmt = connection.prepareStatement(query);\npstmt.setString(1, userName);\nResultSet rs = pstmt.executeQuery();\n\nLeakage of Sensitive Data
\nCheck that passwords, tokens, or card numbers are not being logged. Use @ToString.Exclude in Lombok or explicit exclusion.
Unsafe Object Comparison
\n// BAD (reference comparison)\nif (password == storedPassword) { ... }\n// GOOD\nif (password.equals(storedPassword)) { ... }\n\n\nPerformance: Bottlenecks
\nDon't optimize prematurely, but don't miss obvious slowdowns either.
\nUnnecessary Operations in Loops
\n// BAD: length() is called every time\nfor (int i = 0; i < list.size(); i++) { ... }\n// GOOD\nint size = list.size();\nfor (int i = 0; i < size; i++) { ... }\n\nUsing Stream for Simple Tasks
\nSometimes a regular loop is more readable and faster:
\n// Overkill\nlist.stream().filter(x -> x > 5).collect(Collectors.toList());\n// Simple\nList<Integer> result = new ArrayList<>();\nfor (int x : list) {\n if (x > 5) result.add(x);\n}\n\nMemory Leaks
\nCheck if InputStream, Connection, or Session were not forgotten to be closed. Use try-with-resources:
try (Connection conn = getConnection();\n PreparedStatement stmt = conn.prepareStatement(sql)) {\n // work\n} catch (SQLException e) {\n log.error("DB error", e);\n}\n\n\nReadability and Style: Code as a Book
\nCode review checklist must include readability. Code is written once, read dozens of times.
\nMagic Numbers and Strings
\n// BAD\nif (status == 3) { ... }\n// GOOD\nprivate static final int STATUS_COMPLETED = 3;\nif (status == STATUS_COMPLETED) { ... }\n\n