CIS 120 Java Style Guide

Good Style Requirements

For the most part, we follow the Google Java Style Guide in CIS 120.

However, there are a few exceptions. Blocks should be indented with 4 spaces instead of 2. Tabs are not allowed, but you can configure your tab key to put down 4 spaces (highly recommend!). Our stylechecker in will ensure that your style conforms to these style guidelines. It will tell you the types of style errors you have and sometimes what you can do to fix them, but you can find more of an explanation of those errors in the Google Style Guide.

Additionally, for JUnit tests, we have a few extra good style rules:

  • Use assertEquals(a,b) over assertTrue(a.equals(b)): JUnit provides comparison assertions (which implicitly call objects’ equals methods), but provide more useful failure information than assertTrue. Similarly, there are other more specific assertion methods such as assertNotEquals, assertArrayEquals, etc, which should be used over their more generic counterparts. See JUnit's Assertion Library for a list of these assertion methods and their types.
  • Use assertTrue(a) over assertEquals(a,true) (same for assertFalse and assertNull): Using assertEquals is unnecessary since the value is known to be true, false, or null. See the Java Testing Guide for more information on testing.
  • Test floating-point values with a threshold: Do not use JUnit’s default assertEquals(double expected, double actual) method. Instead, use assertEquals(double expected, double actual, double epsilon), which allows for some wiggle room (an epsilon value) to account for the imprecision of floating-point values. An epsilon value of 0.0001 usually suffices for most purposes.

Good Style in CIS 120

Reading the Google Java Style Guide will give you the most comprehensive coverage of good style. This guide aims to highlight the most important or helpful aspects for CIS 120 and to break down some of the terms or explanations to help you further understand good style. The below style items are not all of the things we will be checking, but they are the ones you are most likely to encounter in 120. If you have questions about what something means or why it’s considered good style, there is so much documentation available that you should Google your question.

Style Guidelines

Source file basics

File Name

The file name should be the case-sensitive name of the top-level class plus the .java extension. For example, the name of the file that contains a class called HauntedHouse will be HauntedHouse.java.

Whitespace

The only whitespace should be a regular space. This means tabs are not used to indent. You can often set your tab key in your IDE to type 4 spaces instead.

Special Escape Sequences

For characters with special escape sequences, use the sequence (ex. \b, \t, \n, \f, \r, \", \' and \\),not an octal or Unicode escape.

Non-ASCII characters

For non-ASCII characters, either the actual Unicode character (e.g. ∞) or the equivalent Unicode escape (e.g. \u221e) is used. Whichever is easier to read and understand should be used.

Source file structure

Order

The source file consists of these, in order, and if present. One blank line separates each section that’s present:

  1. License or copyright information, if present
  2. Package statement
  3. Import statements
  4. Exactly one top-level class

Package and import statements are not line-wrapped. They can exceed the column limit.

Imports

There should be no redundant or unused imports. Imports are ordered as follows:

  1. All static imports in a single block.
  2. All non-static imports in a single block. If there are both static and non-static imports, a single blank line separates the two blocks. There are no other blank lines between import statements.

Class declaration

There is exactly one top-level class declaration, so each class has its own source file. There is no explicit ordering for contents in a class,but they should be ordered in some logical way (chronological does not count). If a class has multiple constructors or multiple methods with the same name, they should appear together with no other code in between.

Formatting

Formatting shortcuts can help format your code automatically. You can use ctrl/cmd + shift + F or ctrl/cmmd + i. You can also right click on the project, hover over Source, and click Format.

Braces

Braces are used even where optional. For example, they are used with if, else, for, do and while statements, even when the body is empty or contains only a single statement.

Nonempty blocks: K & R style

Braces follow the following style for blocks:

  • No line break before the opening brace
  • Line break after the opening brace
  • Line break before the closing brace
  • Line break after the closing brace, only if that brace terminates a statement or terminates the body of a method, constructor, or named class. For example, there is no line break after the brace if it is followed by else or a comma

Example:

@Override
public int compareTo(Pixel o) {
    int rc = getRed() - o.getRed();
    int gc = getGreen() - o.getGreen();
    int bc = getBlue() - o.getBlue();

    if (rc != 0) {
        return rc;
    } else if (gc != 0) {
        return gc;
    } else {
        return bc;
    }
}

Empty blocks

Empty blocks may be written as given above, but the braces may also be closed immediately ({}) unless it’s part of a multiblock statement like if/else.

Example:

// This is acceptable
void doNothing() {}

// This is equally acceptable
void doNothingElse() {
}

// This is not acceptable
if (condition) {
    doSomething();
} else {} 

Block formatting

Each time a new block is opened, indentation increases by 4 spaces. When the block is over, the indent comes back to what it was at before. Code and comments should follow this indentation.

Line wrapping

There should be one statement per line, and each line has a column limit of 100.

Line breaks should follow the rules:

  1. When a line is broken at a non-assignment operator (like +, -, %, etc) the break comes before the symbol. This also applies to the “operator-like” the dot separator (.).
  2. When a line is broken at an assignment operator (like =) the break typically comes after the symbol, but either way is acceptable.
  3. A method or constructor name stays attached to the open parenthesis (() that follows it.
  4. A comma (,) stays attached to the item that precedes it.

When line-wrapping, each line after the first is indented at least 4 spaces. Two indented lines should have the same indentation only if they contain syntactically parallel elements.

Vertical Whitespace

A single blank line always appears between consecutive members or initializers of a class: fields, constructors, methods, nested classes, static initializers, and instance initializers. A blank line between two consecutive fields is optional. Such blank lines are used as needed to create logical groupings of fields.

A single blank line can also be used anywhere that improves readability. Multiple blank lines are permitted but not encouraged.

Horizontal whitespace

Beyond where required by the language or other style rules, and apart from literals, comments and Javadoc, a single ASCII space also appears in the following places only.

  1. Separating any reserved word, such as if, for or catch, from an open parenthesis (() that follows it on that line
  2. Separating any reserved word, such as else or catch, from a closing curly brace (}) that precedes it on that line
  3. Before any open curly brace ({), with two exceptions:
    • @SomeAnnotation({a, b}) (no space is used)
    • String[][] x = {{"foo"}}; (no space is required between {{)
  4. On both sides of any binary or ternary operator (like +, -, %, etc), but not the dot separator (.), which is written like object.toString()
  5. After ,:; or the closing parenthesis ()) of a cast
  6. On both sides of the double slash (//) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required
  7. Between the type and variable of a declaration: List<String> list
  8. Optional just inside both braces of an array initializer:
    • new int[] {5, 6} and new int[] { 5, 6 } are both valid
  9. Between a type annotation and [] or ...

Other formatting

Horizontal alignment is never required.

Examples:

private int x; // this is fine
private Color color; // this too

private int   x;      // permitted, but future edits
private Color color;  // may leave it unaligned

Grouping parentheses are recommended. They can only be omitted when there is no reasonable chance the code will be misinterpreted nor would they have made the code easier to read.

Variable declarations

There should be one variable per declaration. Declarations like int a, b; are not used.

Local variables should be declared when needed close to where they are used to minimize their scope. They should also have initializers or be initialized immediately after declaration.

Arrays

Array initializers can be “block-like;” the following are all acceptable:

new int[] {           new int[] {
  0, 1, 2, 3            0,
}                      1,
                        2,
new int[] {            3,
  0, 1,               }
  2, 3
}                     new int[]
                          {0, 1, 2, 3}

Switch statements

Switch blocks are indented +4 like other blocks. After a switch label, there is a line break, and the indentation level is increased +4, exactly as if a block were being opened. The following switch label returns to the previous indentation level, as if a block had been closed.

Within a switch block, each statement group either terminates abruptly (with a break, continue, return or thrown exception), or is marked with a comment to indicate that execution will or might continue into the next statement group. Any comment that communicates the idea of fall-through is sufficient (typically // fall through). This special comment is not required in the last statement group of the switch block.

The default case should present in each switch statement, even if it contains no code.

Annotations

Annotations applying to a class, method or constructor appear immediately after the documentation block, and each annotation is listed on a line of its own (that is, one annotation per line). For example:

@Override
@Nullable
public String getNameIfPresent() {...}

A single parameterless annotation may instead appear together with the first line of the signature. For example:

@Override public int hashCode() { ... }

Comments

Block comments are indented at the same level as the surrounding code. All of the following are okay:

/*
 * This is
 * okay.
*/

// And so 
// is this

/* Or you can
* even do this. */ 

Naming

Package names

Package names are all lowercase, with consecutive words simply concatenated together (no underscores). For example, com.example.deepspace, not com.example.deepSpace or com.example.deep_space.

Class names

Class names are written in UpperCamelCase where the first letter of every word is capitalized. Class names are typically nouns or noun phrases. For example, HauntedHouse, not hauntedHouse

Method names

Method names are written in lowerCamelCase where the first letter of every word except the first word is capitalized. Method names are typically verbs or verb phrases. For example, sendMessage or stop.

Underscores may appear in JUnit test method names to separate logical components of the name, with each component written in lowerCamelCase. One common pattern is <methodToBeTested>_<state>, for example, distance_nullPixel.

Constant names

Constant names use CONSTANT_CASE: all uppercase letters, with each word separated from the next by a single underscore. For example:

final int MAXIMUM = 255; 
final int PIXEL_MINIMUM = 0;

Other

Non-constant field names, parameter names, local variable names (static or otherwise) are written in lowerCamelCase. For example, comptedAverage or count.

Programming practices

@Override

The @Override annotation is always used when it is legal. This includes a class method overriding a superclass method, a class method implementing an interface method, and an interface method respecifying a superinterface method.

Static members

When a reference to a static class member must be qualified, it is qualified with that class’s name, not with a reference or expression of that class’s type.

Example:

Thing aThing = ...;
Thing.aStaticMethod(); // good
aThing.aStaticMethod(); // bad
somethingThatYieldsAThing().aStaticMethod(); // very bad