java
Definitive guidelines for writing high-quality, maintainable, and performant Java code, adhering to modern best practices (Java 21/25) and enterprise standards like Google Java Style.
Le skill
# Java Best Practices
This document outlines the definitive best practices for Java development within our team. Adherence to these rules ensures consistent, high-quality, and maintainable code, leveraging modern Java features and enterprise standards.
## 1. Code Organization and Structure
### 1.1. Style Guide Adherence
Always follow the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) for formatting, naming, and structural conventions. Configure your IDE (e.g., IntelliJ IDEA, VS Code with appropriate plugins) to automatically apply this style.
### 1.2. File Naming and Encoding
Source files must be named after the single top-level class they contain, with a `.java` extension. All source files must use **UTF-8** encoding.
### 1.3. Indentation and Whitespace
Use **4 spaces** for indentation. **Never use tabs.** For wrapped lines, use **8 spaces** (twice the normal indentation).
❌ BAD
```java
public class MyClass {
void myMethod() {
// Tab used for indentation
System.out.println("Hello");
}
}
```
✅ GOOD
```java
public class MyClass {
void myMethod() {
// 4 spaces for indentation
System.out.println("Hello");
}
}
```
### 1.4. Braces
Always use K&R style braces for non-empty blocks. Braces are mandatory for `if`, `else`, `for`, `do`, and `while` statements, even for single-line bodies.
❌ BAD
```java
if (condition)
doSomething(); // Missing braces
while (true){ // Bad K&R style
doSomething();
}
```
✅ GOOD
```java
if (condition) {
doSomething();
}
while (true) {
doSomethingElse();
}
```
### 1.5. Package and Import Statements
Every class must belong to a package. Use explicit imports; **wildcard imports (`*`) are forbidden**. Imports are ordered: static imports, then non-static imports, separated by a single blank line, both groups in ASCII sort order.
❌ BAD
```java
import java.util.*; // Wildcard import
import static com.example.Constants.*; // Wildcard static import
public class MyClass { /* ... */ }
```
✅ GOOD
```java
import static com.example.Constants.DEFAULT_VALUE;
import java.util.ArrayList;
import java.util.List;
public class MyClass { /* ... */ }
```
### 1.6. Naming Conventions
Adhere strictly to these conventions:
* **Packages**: `com.yourcompany.project.module` (all lowercase, dot-separated).
* **Classes/Enums/Records/Interfaces**: `PascalCase` (nouns).
* **Variables/Parameters**: `camelCase`.
* **Constants**: `SCREAMING_SNAKE_CASE` (for `static final` fields).
* **Methods**: `camelCase` (verbs).
* **Boolean Variables/Methods**: Prefix with `is`, `has`, `can`, `should`.
* **Collections**: Use plural names (e.g., `users`, `messages`).
* **Test Methods**: `featureUnderTest_testScenario_expectedBehavior()`.
❌ BAD
```java
public class userManager { // Class name not PascalCase
public static final String default_user_name = "guest"; // Constant not SCREAMING_SNAKE_CASE
private List userList; // Collection not plural
public boolean checkUser(User u) { /* ... */ } // Boolean method name unclear
}
```
✅ GOOD
```java
package com.example.app.users;
import java.util.List;
public class UserManager {
public static final String DEFAULT_USER_NAME = "guest";
private List<User> users;
public boolean isValidUser(User user) { /* ... */ }
}
```
## 2. Common Patterns and Anti-patterns
### 2.1. Prefer Immutability
Design classes to be immutable whenever possible. This simplifies concurrency and reasoning about state. Use `record` classes (Java 16+) for simple immutable data carriers.
❌ BAD
```java
public class User {
private String name;
public User(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } // Mutable setter
}
```
✅ GOOD
```java
public record User(String name) {} // Immutable record (Java 16+)
// Or traditional immutable class:
public final class ImmutableUser {
private final String name;
public ImmutableUser(String name) { this.name = name; }
public String getName() { return name; }
}
```
### 2.2. Embrace Functional Programming with Streams and Optionals
Leverage Java's Stream API for collection processing and `Optional` for handling potentially absent values.
❌ BAD
```java
List<String> names = getUsers().stream()
.filter(u -> u.getAge() > 18)
.map(User::getName)
.collect(Collectors.toList());
// Handling null:
User user = findUserById(123L);
if (user != null) {
System.out.println(user.getName());
} else {
System.out.println("User not found");
}
```
✅ GOOD
```java
List<String> names = users.stream()
.filter(user -> user.getAge() > 18)
.map(User::getName)
.toList(); // Java 16+ for .toList()
// Handling Optional:
findUserById(123L)
.map(User::getName)
.ifPresentOrElse(
System.out::println,
() -> System.out.println("User not found")
);
```
### 2.3. Resource Management with Try-with-resources
Always use try-with-resources for any resource that implements `AutoCloseable`.
❌ BAD
```java
FileInputStream fis = null;
try {
fis = new FileInputStream("file.txt");
// ... read from fis
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
✅ GOOD
```java
try (FileInputStream fis = new FileInputStream("file.txt")) {
// ... read from fis
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
```
## 3. Performance Considerations
### 3.1. Efficient String Concatenation
Use `StringBuilder` for concatenating multiple strings in loops or when building complex strings.
❌ BAD
```java
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // Creates many intermediate String objects
}
```
✅ GOOD
```java
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
```
### 3.2. Logging Performance
Avoid expensive string formatting or method calls in logging statements unless the log level is enabled. Use parameterized logging.
❌ BAD
```java
logger.debug("Processing user: " + user.getName() + " with ID: " + user.getId()); // String concatenation always happens
```
✅ GOOD
```java
logger.debug("Processing user: {} with ID: {}", user.getName(), user.getId()); // Parameters only evaluated if debug is enabled
```
## 4. Common Pitfalls and Gotchas
### 4.1. Avoid Mutable Static State
Mutable static fields are a common source of concurrency bugs and make testing difficult. Minimize their use.
❌ BAD
```java
public class Counter {
public static int count = 0; // Mutable static field
public static void increment() { count++; }
}
```
✅ GOOD
```java
// Use dependency injection for stateful services or pass state explicitly
public class CounterService {
private int count = 0; // Instance field
public synchronized void increment() { count++; } // Thread-safe instance method
public int getCount() { return count; }
}
```
### 4.2. Dependency Version Management
Always pin dependency versions. Use Bill-of-Materials (BOMs) for managing compatible versions across related libraries (e.g., Spring Boot BOM, Google Cloud Libraries BOM).
❌ BAD (Maven)
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- No version specified, relies on parent or latest -->
</dependency>
```
✅ GOOD (Maven with BOM)
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.5</version> <!-- Pin BOM version -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Version inherited from BOM -->
</dependency>
</dependencies>
```
### 4.3. Correct `equals()` and `hashCode()` Implementation
Always override both `equals()` and `hashCode()` together, or neither. Use `Objects.equals()` and `Objects.hash()` for robust implementations. For data classes, `record` types handle this automatically.
❌ BAD
```java
public class Point {
private int x, y;
// Only equals() overridden, or incorrectly
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
// Missing hashCode()
}
```
✅ GOOD
```java
import java.util.Objects;
public final class Point { // Make final if not intended for extension
private final int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return
Comment l’installer
1. Open the tool and start a new conversation, project or template. 2. Paste the text below wherever the tool keeps standing instructions — usually called system prompt, instructions, or persona. 3. Save it so it applies to every run rather than a single message.