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>