Java Code Conventions

Writing Consistent, Readable Java Code

← Back to Index

Why Code Conventions Matter

Consistent code conventions make codebases easier to read, maintain, and collaborate on. Well-formatted code reduces cognitive load and helps developers focus on logic rather than deciphering style.

Key Principles
  • Consistency within a project trumps personal preference
  • Readability is more important than brevity
  • Follow your team's established style guide

Naming Conventions

Classes and Interfaces

// Classes: PascalCase, nouns
public class UserAccount { }
public class HttpConnectionManager { }
public class OrderProcessingService { }

// Interfaces: PascalCase, often adjectives or capabilities
public interface Serializable { }
public interface Runnable { }
public interface PaymentProcessor { }

// Abstract classes: PascalCase, often prefixed with Abstract
public abstract class AbstractRepository { }

// Exceptions: PascalCase, suffixed with Exception
public class InvalidUserException extends RuntimeException { }

Methods

// Methods: camelCase, verbs or verb phrases
public void calculateTotal() { }
public User findById(Long id) { }
public boolean isValid() { }
public void sendNotification() { }

// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }

// Boolean getters: is, has, can, should
public boolean isActive() { }
public boolean hasPermission() { }
public boolean canExecute() { }

// Factory methods
public static User of(String name) { }
public static User createDefault() { }

Variables and Constants

// Variables: camelCase
String userName = "john";
int orderCount = 0;
List<Order> pendingOrders = new ArrayList<>();

// Constants: SCREAMING_SNAKE_CASE
public static final int MAX_RETRY_COUNT = 3;
public static final String DEFAULT_ENCODING = "UTF-8";
private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

// Avoid single-letter names except for loops
for (int i = 0; i < items.size(); i++) { }  // OK for loop counters
int x = calculate();  // Avoid - not descriptive

Packages

// Packages: lowercase, reverse domain name
package com.company.project.module;
package org.example.utils;
package io.github.username.library;

// Common package structure
com.company.app
├── controller    // REST controllers
├── service       // Business logic
├── repository    // Data access
├── model         // Domain objects
├── dto           // Data transfer objects
├── config        // Configuration
└── exception     // Custom exceptions

Formatting

Braces and Indentation

// Opening brace on same line (K&R style - most common in Java)
public class Example {
    public void method() {
        if (condition) {
            // code
        } else {
            // code
        }
    }
}

// Use 4 spaces for indentation (not tabs)
public void example() {
    if (condition) {
        doSomething();
        if (nestedCondition) {
            doMore();
        }
    }
}

// Always use braces, even for single statements
// GOOD
if (valid) {
    process();
}

// AVOID
if (valid)
    process();  // Easy to introduce bugs

Line Length and Wrapping

// Keep lines under 120 characters (80-100 preferred)

// Method call wrapping
List<User> users = userRepository
        .findByStatusAndCreatedDateAfter(
                UserStatus.ACTIVE,
                LocalDate.now().minusDays(30)
        );

// Stream operation wrapping
List<String> names = users.stream()
        .filter(User::isActive)
        .map(User::getName)
        .sorted()
        .collect(Collectors.toList());

// Long string concatenation
String message = "This is a very long message that "
        + "spans multiple lines for better "
        + "readability in the source code.";

Blank Lines

public class UserService {

    private final UserRepository userRepository;
    private final EmailService emailService;
                                              // Blank line after fields
    public UserService(UserRepository repo, EmailService email) {
        this.userRepository = repo;
        this.emailService = email;
    }
                                              // Blank line between methods
    public User createUser(UserDto dto) {
        User user = mapToEntity(dto);
        user = userRepository.save(user);
                                              // Blank line for logical separation
        emailService.sendWelcome(user);
        return user;
    }
}

Class Structure

Recommended Order

public class WellOrganizedClass {

    // 1. Static constants
    private static final Logger LOGGER = LoggerFactory.getLogger(...);
    public static final int MAX_SIZE = 100;

    // 2. Static variables
    private static int instanceCount = 0;

    // 3. Instance variables (fields)
    private final String name;
    private int value;

    // 4. Constructors
    public WellOrganizedClass(String name) {
        this.name = name;
    }

    // 5. Static factory methods
    public static WellOrganizedClass createDefault() {
        return new WellOrganizedClass("default");
    }

    // 6. Public methods
    public void doSomething() { }

    // 7. Package-private methods
    void internalMethod() { }

    // 8. Protected methods
    protected void extensionPoint() { }

    // 9. Private methods
    private void helperMethod() { }

    // 10. Inner classes
    private static class InnerHelper { }
}

Import Statements

// Order: java.*, javax.*, third-party, project packages
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.company.project.model.User;
import com.company.project.repository.UserRepository;

// Avoid wildcard imports
import java.util.*;  // AVOID - hides what's actually used

// Avoid static imports except for common utilities
import static org.junit.jupiter.api.Assertions.*;  // OK in tests
import static java.lang.Math.PI;  // OK for constants

Comments and Documentation

Javadoc

/**
 * Service for managing user accounts.
 *
 * <p>Provides operations for creating, updating, and
 * retrieving user information from the database.</p>
 *
 * @author Development Team
 * @since 1.0
 */
public class UserService {

    /**
     * Finds a user by their unique identifier.
     *
     * @param id the user's unique identifier
     * @return the user if found
     * @throws UserNotFoundException if no user exists with the given id
     */
    public User findById(Long id) {
        // implementation
    }
}

Inline Comments

// GOOD: Explain WHY, not WHAT
// Retry connection up to 3 times due to transient network issues
for (int attempt = 0; attempt < 3; attempt++) {
    try {
        return connect();
    } catch (IOException e) {
        // Log and retry
    }
}

// BAD: States the obvious
// Increment counter by 1
counter++;

// TODO comments for work tracking
// TODO: Implement caching (JIRA-1234)
// FIXME: Handle null case properly

Modern Java Style

// Use var for obvious types (Java 10+)
var users = new ArrayList<User>();
var response = httpClient.send(request, BodyHandlers.ofString());

// Use records for data classes (Java 16+)
record UserDto(String name, String email) { }

// Use text blocks for multi-line strings (Java 15+)
String json = """
    {
        "name": "John",
        "age": 30
    }
    """;

// Use switch expressions (Java 14+)
String result = switch (status) {
    case ACTIVE -> "Active user";
    case PENDING -> "Awaiting approval";
    case INACTIVE -> "Deactivated";
};

Enforcing Conventions

Automation Tools
  • Checkstyle - Enforces coding standards
  • SpotBugs - Finds potential bugs
  • Google Java Format - Auto-formats code
  • EditorConfig - Consistent settings across IDEs
<!-- Maven Checkstyle Plugin -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <configLocation>google_checks.xml</configLocation>
    </configuration>
</plugin>