Java Coding Conventions
Formatting
Indentation
- Use 2 spaces for indentation (no tabs)
- Continuation indent: 4 spaces
Line Length
- Maximum line length: 120 characters
- Break long lines at logical points
Braces
- Use K&R style (opening brace on same line)
- Always use braces, even for single-line blocks
// Good
if (condition) {
doSomething();
}
// Bad
if (condition)
doSomething();Imports
Organization
- Group imports in the following order:
- Java imports (
java.*) - JavaX imports (
javax.*) - Third-party imports
- Spring imports (
org.springframework.*) - Project imports (
de.frachtwerk.*)
- Java imports (
- Separate groups with blank lines
- Avoid wildcard imports
Annotations
Entity Annotations
@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class User extends AbstractBaseModel {
// fields
}Service Annotations
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class UserService {
private final UserRepository repository;
// methods
}Controller Annotations
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Tag(name = "User Management")
public class UserController {
private final UserService service;
// endpoints
}Constants and Variables
Constants
- Use
UPPER_SNAKE_CASE - Declare as
public static final - Group related constants together
public static final String DEFAULT_ROLE = "USER";
public static final int MAX_LOGIN_ATTEMPTS = 3;
public static final long TOKEN_VALIDITY = 3600L;Variables
- Use meaningful names
- Avoid single-letter names except for loop indices
- Prefer immutability (
finalkeyword)
Method Conventions
Parameters
- Limit to 3-4 parameters
- Use builder pattern for many parameters
- Validate input with
@NotNull,@Valid
public User createUser(
@NotNull @Valid UserDto dto,
@NotNull Role defaultRole) {
// implementation
}Return Types
- Use
Optionalfor nullable returns - Return empty collections instead of null
- Use specific types over generic ones
Comments and Documentation
Javadoc
/**
* Creates a new user with the given data.
*
* @param dto the user data transfer object
* @param role the initial role to assign
* @return the created user entity
* @throws UserAlreadyExistsException if email is already taken
*/
public User createUser(UserDto dto, Role role) {
// implementation
}Inline Comments
- Use sparingly, prefer self-documenting code
- Explain why, not what
- Keep comments up-to-date
SQL and JPQL
Named Queries
@Query("""
SELECT u FROM User u
WHERE u.email = :email
AND u.active = true
""")
Optional<User> findActiveByEmail(@Param("email") String email);Native Queries
@Query(
value = """
SELECT * FROM users u
WHERE u.created_at > :date
ORDER BY u.last_name, u.first_name
""",
nativeQuery = true)
List<User> findRecentUsers(@Param("date") LocalDateTime date);Exception Handling
Custom Exceptions
public class UserNotFoundException extends EntityNotFoundException {
public UserNotFoundException(Long id) {
super(String.format("User with id %d not found", id));
}
}Exception Handler
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleUserNotFound(UserNotFoundException ex) {
return ErrorResponse.of(ex.getMessage());
}Best Practices
- DRY (Don’t Repeat Yourself) - Extract common code
- KISS (Keep It Simple) - Avoid over-engineering
- YAGNI (You Aren’t Gonna Need It) - Don’t add unnecessary features
- Favor composition over inheritance
- Program to interfaces, not implementations
- Make classes immutable where possible
- Minimize class and member accessibility