Java Coding Standards

Mastering Clean, Readable, and Maintainable Code in Java

Author

Chuck Nelson

Published

August 25, 2025

1 Java Coding Standards Handbook

Java_Coding_Standards_Handbook

This handbook outlines the coding standards and best practices for Java programming in this course. Adhering to these guidelines will help you write clean, readable, maintainable, and professional-looking code. Consistency is key, especially when working on projects that might be reviewed by others or maintained in the future.


1.1 Table of Contents

  1. General Principles
  2. Naming Conventions
  3. Formatting
  4. Comments & Documentation
  5. Declarations
  6. Control Structures
  7. Error Handling
  8. Object-Oriented Principles (Basic)
  9. General Best Practices
  10. Tools and IDEs

1.2 1. General Principles

  • Consistency: Always apply the same rules throughout your codebase. If a rule isn’t explicitly stated, be consistent with existing code.
  • Readability: Code should be easy to understand at a glance, even by someone unfamiliar with it.
  • Clarity: Be explicit. Avoid clever but obscure tricks.
  • Simplicity: Prefer the simplest solution that meets the requirements.
  • Maintainability: Write code that is easy to fix, update, and extend in the future.

1.3 2. Naming Conventions

Follow standard Java naming conventions to make your code predictable and readable.

1.3.1 2.1. Packages

  • Lowercase: All letters should be lowercase.

  • Reverse Domain Name: Start with your organization’s reversed internet domain name (e.g., com.example.projectname). For academic projects, edu.yourinstitution.yourcourse.projectname is a good pattern (e.g., edu.pstcc.cisp1310.myproject).

  • Separators: Use dots (.) to separate components.

    Example: package edu.pstcc.cisp1310.assignment1;

1.3.2 2.2. Classes and Interfaces

  • PascalCase (UpperCamelCase): Start with an uppercase letter, and capitalize the first letter of each subsequent word.

  • Nouns: Names should generally be nouns or noun phrases.

  • Descriptive: Clearly indicate the purpose or responsibility.

    Examples: Student, Course, ShoppingCart, DataLoader, Printable, Serializable

1.3.3 2.3. Methods

  • camelCase (LowerCamelCase): Start with a lowercase letter, and capitalize the first letter of each subsequent word.

  • Verbs: Names should generally be verbs or verb phrases, indicating an action.

    Examples: calculateTotal(), processOrder(), getName(), isValid()

1.3.4 2.4. Variables

  • camelCase (LowerCamelCase): Same as methods.

  • Descriptive: Choose names that clearly indicate the variable’s purpose. Avoid single-letter variable names unless they are common loop counters (i, j, k).

    Examples: studentName, courseId, totalAmount, isValidInput, loopCounter

1.3.5 2.5. Constants

  • SCREAMING_SNAKE_CASE: All uppercase letters, with words separated by underscores (_).

  • final static: Constants should always be declared as public static final.

    Examples: public static final int MAX_STUDENTS = 100;, public static final String DEFAULT_NAME = "Guest";


1.4 3. Formatting

Consistent formatting makes code easy to scan and understand.

1.4.1 3.1. Indentation

  • 4 Spaces: Use 4 spaces for each level of indentation. Never use tabs. Configure your IDE to use spaces for tabs.

1.4.2 3.2. Line Length

  • Maximum 120 Characters: Aim for a maximum line length of 120 characters. Break long lines into multiple lines for readability.

1.4.3 3.3. Brace Style

  • K&R Style (Egyptian Brackets): The opening brace ({) is on the same line as the statement, and the closing brace (}) is on its own line.

    public class MyClass {
        public void myMethod() {
            if (condition) {
                // code
            } else {
                // code
            }
        }
    }

1.4.4 3.4. Whitespace

  • Operators: Use a single space around binary operators (=, +, -, *, /, ==, &&, ||, etc.). Example: int sum = a + b;
  • Commas and Semicolons: Use a space after commas and semicolons. Example: for (int i = 0; i < 10; i++) {
  • Parentheses: No space between a method name and its opening parenthesis. No space inside parentheses. Example: myMethod(arg1, arg2);
  • Braces: A space before an opening brace. Example: if (condition) {

1.4.5 3.5. Blank Lines

  • Between Methods: Use one blank line to separate methods.
  • Between Logical Blocks: Use blank lines to separate logical sections within a method for better readability.
  • After Package/Import Statements: Use one blank line after the package declaration and after the import statements block.

1.4.6 3.6. Imports

  • Wildcards: Avoid using wildcard imports (import java.util.*;). Explicitly import each class.
  • Ordering: Imports should be grouped and ordered:
    1. java.* imports
    2. javax.* imports
    3. Third-party library imports
    4. Project-specific imports
    • Each group should be sorted alphabetically.
    • Use a blank line between groups.
    • Most IDEs can automatically organize imports for you.

1.5 4. Comments & Documentation

Comments explain the why behind the code, not just the what. Good code should be self-documenting as much as possible. All code requires Javadoc comments.

1.5.1 4.1. Purpose of Comments

  • Context: Explain the purpose of complex algorithms or business logic.
  • Assumptions: Document any assumptions made.
  • Limitations: Note known limitations or potential issues.
  • Future Work: Use TODO or FIXME comments for pending tasks or known bugs.

1.5.2 4.2. Types of Comments

  • Javadoc Comments (/** ... */): Mandatory for all public and protected classes, interfaces, methods, and fields. They describe the purpose, parameters (@param), return values (@return), and exceptions (@throws).

    /**
     * Calculates the sum of two integers.
     * This method provides a basic arithmetic operation.
     * @param a The first integer.
     * @param b The second integer.
     * @return The sum of a and b.
     * @throws IllegalArgumentException if a or b are negative (example).
     */
    public int add(int a, int b) {
        if (a < 0 || b < 0) {
            throw new IllegalArgumentException("Inputs must be non-negative.");
        }
        return a + b;
    }
  • Multi-line Comments (/* ... */): Use for larger blocks of explanation within a method or class that are not part of the public API documentation.

  • Single-line Comments (//): Use for short explanations or to temporarily disable code. Place them on a separate line above the code they refer to, or at the end of a line if very brief.

1.5.3 4.3. When to Comment

  • Non-obvious Code: If a piece of code is not immediately clear, add a comment.

    // Calculate the nth Fibonacci number using an iterative approach
    // This is more efficient than the recursive solution for large n
    public long fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        long a = 0, b = 1;
        for (int i = 2; i <= n; i++) {
            long next = a + b;
            a = b;
            b = next;
        }
        return b;
    }
  • Complex Logic: Explain the high-level steps of a complex algorithm.

    // --- Complex Data Processing Workflow ---
    // 1. Fetch raw data from external API.
    // 2. Validate data schema and integrity.
    // 3. Transform data into canonical format.
    // 4. Persist transformed data to database.
    // 5. Trigger downstream analytics pipeline.
    public void processIncomingData(String rawData) {
        // ... implementation details for each step ...
    }
  • Workarounds: Document why a particular workaround is necessary.

    // WORKAROUND: Due to a bug in LibraryX v1.2.3,
    // we must explicitly close the stream even though it's wrapped in try-with-resources.
    // Remove this workaround when upgrading to LibraryX v1.2.4 or higher.
    try (InputStream is = new FileInputStream("file.txt")) {
        // ... read data ...
    } catch (IOException e) {
        // ... handle exception ...
    } finally {
        // Explicitly closing due to known library bug
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                // Log secondary close error
            }
        }
    }
  • Future Work: Use TODO or FIXME comments for pending tasks or known bugs.

    // TODO: Implement proper input validation for all user-provided strings.
    // This currently only checks for null, but should also check for empty or malicious input.
    public void setUserName(String name) {
        if (name == null) {
            throw new IllegalArgumentException("Name cannot be null.");
        }
        this.userName = name;
    }
    
    // FIXME: This method has a known concurrency issue when multiple threads access it simultaneously.
    // Needs proper synchronization or a thread-safe data structure.
    public void incrementCounter() {
        counter++;
    }

1.5.4 4.4. Javadoc Generation

  • Mandatory: Javadoc documentation must be generated for all projects. This ensures that your code’s public API is well-documented and easily accessible.

  • Maven Integration: For Maven projects, you can generate Javadoc using the maven-javadoc-plugin. Add the following to the <build><plugins> section of your pom.xml:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>3.6.3</version> <!-- Use a recent stable version -->
        <executions>
            <execution>
                <id>attach-javadocs</id>
                <goals>
                    <goal>jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    Then, run mvn javadoc:javadoc or mvn install (if the plugin is configured to run during install phase). The generated documentation will be in target/site/apidocs/.


1.6 5. Declarations

1.6.1 5.1. Variable Declaration

  • One Variable Per Line: Declare one variable per line for clarity. Good:

    int count = 0;
    String name = "Alice";

    Bad:

    int count = 0, index = 1;
  • Initialize Variables: Initialize variables at the point of declaration if possible, or as soon as they are assigned a meaningful value.

1.6.2 5.2. Access Modifiers

  • Least Restrictive Possible: Use the most restrictive access modifier that allows the code to function.
    • private: For members only accessible within the class.
    • protected: For members accessible within the class and its subclasses/package.
    • (default/package-private): For members accessible only within the same package.
    • public: For members accessible from anywhere.

1.7 6. Control Structures

Make control structures clear and robust.

1.7.1 6.1. if/else Statements

  • Always Use Braces: Always use curly braces ({}) even for single-statement if or else blocks. This prevents logical errors if you later add more statements.

    Good:

    if (condition) {
        doSomething();
    } else {
        doSomethingElse();
    }

    Bad:

    if (condition)
        doSomething(); // Easy to introduce bugs later

1.7.2 6.2. for and while Loops

  • Always Use Braces: Same rule as if/else statements.
  • Clear Loop Conditions: Ensure loop conditions are clear and prevent infinite loops.

1.7.3 6.3. switch Statements

  • default Case: Always include a default case, even if it’s just to throw an IllegalArgumentException or log a warning.
  • break Statements: Remember break statements to prevent fall-through, unless fall-through is explicitly intended and commented.

1.8 7. Error Handling

  • Use Exceptions: Handle errors using Java’s exception mechanism (try-catch-finally).
  • Specific Exceptions: Catch specific exceptions rather than generic Exception where possible.
  • Don’t Swallow Exceptions: Do not catch an exception and do nothing with it. At least log it or rethrow it.
  • Informative Error Messages: Provide clear and helpful error messages.

1.9 8. Object-Oriented Principles (Basic)

1.9.1 8.1. Encapsulation

  • Private Fields: Declare fields (instance variables) as private.
  • Public Getters/Setters: Provide public getter (accessor) and setter (mutator) methods if external access or modification is required.

1.9.2 8.2. Avoid Magic Numbers

  • Constants for Literals: Replace hardcoded literal values (e.g., 3.14, 100, "error") with named constants.

    Good:

    public static final double PI = 3.14159;
    public static final int MAX_RETRIES = 3;

    Bad:

    double circumference = 2 * 3.14 * radius;
    for (int i = 0; i < 3; i++) { // What does 3 mean?

1.10 9. General Best Practices

1.10.1 9.1. Keep Methods Small and Focused

  • Each method should ideally do one thing and do it well. This improves readability, testability, and reusability.

1.10.2 9.2. Don’t Repeat Yourself (DRY)

  • Avoid duplicating code. If you find yourself writing the same logic multiple times, consider extracting it into a separate method or class.

1.10.3 9.3. Fail Fast

  • Validate inputs early. If a method receives invalid arguments, throw an exception immediately rather than allowing the program to proceed with bad data.

1.10.4 9.4. Avoid Deep Nesting

  • Too many nested if statements or loops make code hard to read and understand. Consider refactoring using guard clauses, separate methods, or design patterns.

1.10.5 9.5. UML Class Diagrams

  • Mandatory: For all projects with a class structure (i.e., more than one class), a UML Class Diagram is required.

  • Purpose: The diagram should visually represent the classes, their attributes, methods, and relationships (e.g., inheritance, association, aggregation, composition).

  • Tool: Use PlantUML to create these diagrams. You will typically create a .puml file in your project (e.g., docs/uml/ClassDiagram.puml) and include the generated image (PNG or SVG) in your project’s README.md or assignment submission.

  • Example PlantUML Structure:

1.10.6 9.6. Version Control (Git & GitHub)

  • Mandatory for All Projects: All projects must be managed using Git and hosted on a GitHub repository. This is essential for collaborative development, tracking changes, and maintaining project history.
  • Repository Setup:
    • Initialize a Git repository in your project’s root directory: git init
    • Create a remote repository on GitHub and link it to your local repository: git remote add origin https://github.com/[your-username]/[your-repo-name].git
    • Push your initial code: git push -u origin main (or master)
  • Commit Frequency & Messages:
    • Commit changes frequently, in small, logical chunks.
    • Write clear, concise, and descriptive commit messages that explain what changes were made and why.
      • Good: feat: Add user authentication module
      • Good: fix: Resolve NullPointerException in data loader
      • Bad: Update code
  • Branching Strategy: Use a simple branching strategy (e.g., main for stable code, feature branches for new work).
  • Releases and Tagging:
    • Mandatory: All project releases (e.g., for assignment submissions or major milestones) must be tagged with a release version in Git.
    • Use Semantic Versioning (e.g., v1.0.0, v1.0.1, v1.1.0).
    • To tag a release: git tag -a v[MAJOR.MINOR.PATCH] -m "Release version [MAJOR.MINOR.PATCH]"
    • Push tags to GitHub: git push origin --tags
    • Create a corresponding release on GitHub for better visibility and to attach compiled artifacts if needed.

1.10.7 9.7. Project Documentation (README.md)

  • Mandatory: Every project must include a README.md file at its root directory.

  • Purpose: The README.md serves as the primary entry point for understanding your project. It should provide a quick overview, setup instructions, usage examples, and other essential information for anyone looking at your repository.

  • Content Requirements: The README.md file must follow a clear and comprehensive structure, including at least the following sections (following the template provided by the instructor):

    # Table of Contents
    
    - About the Project
        - Built With
    - Getting Started
        - Prerequisites
        - Installation
    - Usage
    - Project Structure
    - Testing
    - Contributing
    - License
    - Contact
    - Acknowledgments

1.11 10. Tools and IDEs

Modern Integrated Development Environments (IDEs) and build tools can help you adhere to these standards:

  • VS Code (with Extension Pack for Java): This is the recommended IDE for this course. It provides excellent code completion, error checking, and refactoring.
  • OpenJDK: The required Java Development Kit (JDK) for this course. Ensure you are using OpenJDK 21 or the specified version for your assignments.
  • PlantUML: The required tool for generating UML diagrams. Install the PlantUML extension in VS Code for easy preview and export.
  • Apache Maven: The required build system for this course. It helps manage dependencies and standardizes the project structure.
  • Git: The required version control system. Learn basic Git commands for committing, branching, and merging.
  • GitHub: The required platform for hosting your Git repositories.

Most IDEs allow you to configure code formatters (e.g., Google Java Format, Oracle Java Conventions) that can automatically apply many of these rules. Learn how to use your IDE’s formatting features!


By following these guidelines, you’ll not only write better Java code but also develop habits that are highly valued in the software development industry. Good luck!

Back to top