Checkstyle Coding Rules
Rules ΒΆ
Array initialization contains a trailing comma. [Recommend] ΒΆ
This rule demands a comma at the end if neither left nor right curly braces are on the same line as the last element of the array.
![]()
return new int[] { 0 }; return new int[] { 1, 2, };![]()
return new int[] {1, 2,} return new int[] {100000000000000000000, }
check ArrayTrailingComma for the original rule.
Avoid Double Brace Initialization. [Mandatory] ΒΆ
Double brace initialization (set of Instance Initializers in class body) may look cool, but it is considered as anti-pattern and should be avoided. This is also can lead to a hard-to-detect memory leak, if the anonymous class instance is returned outside and other object(s) hold reference to it. The created anonymous class is not static, it holds an implicit reference to the outer class instance.
![]()
class MyClass { List<Integer> list1 = new ArrayList<>() { { add(1); } }; List<String> list2 = new ArrayList<>() { { add("foo"); } }; }
check AvoidDoubleBraceInitialization for the original rule.
Avoid Inline Conditionals. [Reference] ΒΆ
Inline conditionals are hard to read, which should be avoided.
![]()
String str1; if (str2 != null && str2.length() >= 1) { // OK str1 = str2.substring(1); } else { str1 = null; }![]()
str1 = (str2 != null && str2.length() >= 1) ? str2.substring(1) : null;
check AvoidInlineConditionals for the original rule.
Avoid No Argument Super Constructor Call. [Recommend] ΒΆ
Such invocation is redundant because constructor body implicitly begins with a super class constructor invocation super().
![]()
class SubClass extends SuperClass { SubClass(int arg) { super(arg); // call with argument have to be explicit } SubClass(long arg) { // call is implicit } }![]()
class SubClass extends SuperClass { SubClass() { super(); } }
check AvoidNoArgumentSuperConstructorCall for the original rule.
Classes and Records which define a covariant equals() method also override method equals(Object). [Mandatory] ΒΆ
Covariant equals() is a method that similar to equals(Object), but with a covariant parameter type (any subtype of Object).
The covariant version of equals() does not override the version in the Object class, and it may lead to unexpected behavior at runtime, especially if the class is used with one of the standard collection classes which expect that the standard equals(Object) method is overridden.
This kind of bug is not obvious because it looks correct, and in circumstances where the class is accessed through the references of the class type (rather than a super type), it will work correctly. However, the first time it is used in a container, the behavior might be mysterious.
![]()
class Test { public boolean equals(Test i) { // no violation return false; } @Override public boolean equals(Object i) { return false; } }![]()
class Test { public boolean equals(Test i) { return false; } }
check CovariantEquals for the original rule.
Keep declaration order. [Recommend] ΒΆ
According to Code Conventions for the Java Programming Language, the parts of a class or interface declaration should appear in the following order: 1. Class (static) variables. First the public class variables, then protected, then package level (no access modifier), and then private. 2. Instance variables. First the public class variables, then protected, then package level (no access modifier), and then private. 3. Constructors 4. Methods
![]()
public class Test { public int a; protected int b; public int c; // violation, variable access definition in wrong order Test() { this.a = 0; } public void foo() { // do something } Test(int a) { // violation, constructor definition in wrong order this.a = a; } private String name; // violation, instance variable declaration in wrong order }
check DeclarationOrder for the original rule.
default is after all the cases in a switch statement. [Mandatory] ΒΆ
Java allows default anywhere within the switch statement. But it is more readable if it comes after the last case.
Allow default label to be not last if it is shared with case.
![]()
switch (i) { case 1: break; case 2: default: // OK, shared with case 2 break; case 3: break; }![]()
switch (i) { case 1: break; default: // violation case 2: break; }
check DefaultComesLast for the original rule.
Empty statement is not allowed. [Mandatory] ΒΆ
Empty statements often introduce bugs that are hard to spot
![]()
public void foo() { int i = 5; if (i > 3); // violation, ";" right after if statement i++; for (i = 0; i < 5; i++); // violation i++; while (i > 10) { // OK i++; } }
check EmptyStatement for the original rule.
Avoid NPE when calling method equals(). [Mandatory] ΒΆ
String literals should be placed on the left side of an equals() comparison, which will avoid a potential NullPointerException.
Method
ignoreEqualsIgnoreCase()should also follow this rule.
![]()
String nullableString = null; "My_Sweet_String".equals(nullableString); // OK "My_Sweet_String".equalsIgnoreCase(nullableString); // OK![]()
String nullableString = null; nullableString.equals("My_Sweet_String"); nullableString.equalsIgnoreCase("My_Sweet_String");
check EmptyStatement for the original rule.
Classes that either override equals() or hashCode() should also override the other. [Mandatory] ΒΆ
The contract of equals() and hashCode() requires that equal objects have the same hash code. Therefore, whenever you override equals() you must override hashCode() to ensure that your class can be used in hash-based collections.
Method
ignoreEqualsIgnoreCase()should also follow this rule.
![]()
public static class Example1 { public int hashCode() { // code } public boolean equals(java.lang.Object o) { // code } }![]()
public static class Example2 { public int hashCode() { // code } public boolean equals(String o) { // violation, overloaded implementation of 'equals' // code } } public static class Example2 { public boolean equals(Object o) { // violation, no 'hashCode' // code } public boolean equals(String o) { // code } } public static class Example3 { public static int hashCode(int i) { // violation, overloaded implementation of 'hashCode' // code } public boolean equals(Object o) { // code } }
check EqualsHashCode for the original rule.
Avoid Explicit Initialization. [Recommend] ΒΆ
When an instance variable being explicitly initialized to its default value, then it will get initialized twice, to the same value.
Java initializes each instance variable to its default value (0 or null) before performing any initialization specified in the code. So there is a minor inefficiency.
Method
ignoreEqualsIgnoreCase()should also follow this rule.
![]()
public class Test { private int intField2 = 1; private int intField3; private char charField2 = 'b'; private char charField3; private boolean boolField2 = true; private boolean boolField3; private Obj objField2 = new Obj(); private Obj objField3; private int arrField2[] = new int[10]; private int arrField3[]; }![]()
public class Test { private int intField1 = 0; private char charField1 = '\0'; private boolean boolField1 = false; private Obj objField1 = null; private int arrField1[] = null; }
check ExplicitInitialization for the original rule.
Avoid a switch case contains Java code but lacks a break, return, yield, throw or continue statement. [Mandatory] ΒΆ
Above-mentioned cases usually lead to potential bugs.
Method
ignoreEqualsIgnoreCase()should also follow this rule.
![]()
public int bar() { int i = 0; return switch (i) { case 1: i++; yield 11; case 2: // OK i++; return; case 3: // OK i++; throw new Exception(); case 4: // OK i++; continue; case 5: // OK case 6: // Previous case: OK, case does not contain code i++; default: // OK yield -1; }; }![]()
public void foo() throws Exception { int i = 0; while (i >= 0) { switch (i) { case 1: i++; case 2: // violation, previous case contains code but lacks break, return, yield, throw or continue statement i++; break; } } }
check FallThrough for the original rule.
A local variable or a parameter should not shadow a field that is defined in the same class. [Mandatory] ΒΆ
Shadowing a field would sometimes lead to potential bugs.
![]()
Constructorparameters andSetterparameters are ignored.
![]()
public class SomeClass { private String testField; public SomeClass(String testField) { // OK, ignore constructor parameter } public void setTestField(String testField) { // OK, ignore setter parameter this.testField = testField; } }![]()
public class SomeClass { private String field; public void method(String param) { String field = param; // violation, 'field' variable hides 'field' field } public SomeClass setField(String field) { // violation, 'field' param hides 'field' field this.field = field; } }
check FinalLocalVariable for the original rule.
Certain exception types should not appear in a catch statement. [Recommended] ΒΆ
Catching java.lang.Exception, java.lang.Error or java.lang.RuntimeException is almost never acceptable. Novice developers often simply catch Exception in an attempt to handle multiple exception classes. This unfortunately leads to code that inadvertently catches NullPointerException, OutOfMemoryError, etc.
Forbidden exception types are
Error,Exception,Throwable,java.lang.Error,java.lang.Exception,java.lang.RuntimeException,java.lang.Throwable.
![]()
try { // some code here } catch (ArithmeticException e) { // OK }![]()
try { // some code here } catch (ArithmeticException e) { } catch (RuntimeException e) { // violation, catching RuntimeException is illegal and order of catch blocks doesn't matter } try { // some code here } catch (ArithmeticException | Exception e) { // violation, catching Exception is illegal }
check IllegalCatch for the original rule.
Certain exception types should never be thrown. [Recommended] ΒΆ
Declaring that a method throws java.lang.Error or java.lang.RuntimeException is almost never acceptable, reason is same as above rule.
Forbidden exception types are
Error,RuntimeException,Throwable,java.lang.Error,java.lang.RuntimeException,java.lang.Throwable.
Overridden methods are ignored.
![]()
public class Test { public void func2() throws CustomizedException {} // ok public void func5() throws NullPointerException {} // ok @Override public void toString() throws Error {} // Overridden methods are ignored. }![]()
public class Test { public void func1() throws RuntimeException {} // violation public void func3() throws Error {} // violation public void func4() throws Throwable {} // violation }
check IllegalThrows for the original rule.
Do not do assignments in sub-expressions. [Recommended] ΒΆ
All assignments should occur in their own top-level statement to increase readability. With inner assignments like the one given above, it is difficult to see all places where a variable is set.
Inner assignment in
for/while/do-whileloop is allowed since it's popular.
Overridden methods are ignored.
![]()
void foo() { int a, b; a = 5; // OK b = 5; // OK a = 5; b = 5; // OK for (int k = 0; k < 10; k = k + 2) { // OK, allowed in for loop // some code } boolean someVal; InputStream is = new FileInputStream("textFile.txt"); while ((b = is.read()) != -1) { // OK, this is a common idiom // some code } }![]()
void foo() { int a, b; a = b = 5; // violation, assignment to each variable should be in a separate statement a = b += 5; // violation double myDouble; double[] doubleArray = new double[] {myDouble = 4.5, 15.5}; // violation String nameOne; List<String> myList = new ArrayList<String>(); myList.add(nameOne = "tom"); // violation boolean someVal; if (someVal = true) { // violation // some code } }
check InnerAssignment for the original rule.
Avoid using magic numbers. [Recommended] ΒΆ
magic number is a numeric literal that is not defined as a constant. By default,
-1,0,1, and2are not considered to be magic numbers.
Field declarations,
hashCodemethod, annotation element defaults are ignored.
![]()
public record MyRecord() { private static int myInt = 7; // ok, field declaration is ignored void foo() { int i = myInt + 1; // ok, 1 is defined as non-magic } public int hashCode() { return 10; // ok, hashCode method is ignored } } @interface anno { int value() default 10; // ok, annotation element defaults is ignored }![]()
public record MyRecord() { private static int myInt = 7; void foo() { int i = 10; // violation int j = myInt + 8; // violation } }
check MagicNumber for the original rule.
Avoid multiple occurrences of the same string literal within a single file. [Reference] ΒΆ
Code duplication makes maintenance more difficult, so it can be better to replace the multiple occurrences with a constant.
Maximum number of occurrences allowed is 2.
![]()
public class MyClass { String a = "StringContents"; String a1 = "unchecked"; @SuppressWarnings("unchecked") // OK, duplicate strings are ignored in annotations public void myTest() { String a4 = "SingleString"; // OK } }![]()
public class MyClass { String a = "StringContents"; String a1 = "unchecked"; public void myTest() { String a2 = "StringContents"; String a3 = "StringContents"; // violation, "StringContents" occurs three times String a5 = "DoubleString" + "DoubleString" + "DoubleString"; // violation, "DoubleString" occurs three times String a7 = ", " + ", " + ", "; // violation, ", " occurs three times } }
check MultipleStringLiterals for the original rule.
Need to restrict nested for blocks to a specified depth. [Recommended] ΒΆ
Nested for blocks lead to poor reading experience.
Maximum allowed nesting depth is 1.
![]()
for(int i=0; i<10; i++) { for(int j=0; j<i; j++) { // ok } }![]()
for(int i=0; i<10; i++) { for(int j=0; j<i; j++) { for(int k=0; k<j; k++) { // violation, max allowed nested loop number is 1 } } }
check NestedForDepth for the original rule.
Need to restrict nested if-else blocks to a specified depth. [Recommended] ΒΆ
Nested if-else blocks lead to poor reading experience.
Maximum allowed nesting depth is 2.
![]()
if (true) { if (true) { if (true) { // ok } }![]()
if (true) { if (true) { if (true) { if (true) { // violation, nested if-else depth is 3 (max allowed is 2) } } } }
check NestedIfDepth for the original rule.
Need to restrict nested try-catch-finally blocks to a specified depth. [Recommended] ΒΆ
Nested try-catch-finally blocks lead to poor reading experience.
Maximum allowed nesting depth is 1.
![]()
try { try { // OK, current depth is 1, default max allowed depth is also 1 } catch (Exception e) { } } catch (Exception e) { }![]()
try { try { try { // violation, current depth is 2, default max allowed depth is 1 } catch (Exception e) { } } catch (Exception e) { } } catch (Exception e) { }
check NestedTryDepth for the original rule.
Avoid using finalize method. [Reference] ΒΆ
Finalizers are unpredictable, often dangerous, and generally unnecessary. Their use can cause erratic behavior, poor performance, and portability problems. For more information on the finalize method and its issues, see Effective Java: Programming Language Guide Third Edition by Joshua Bloch, Β§8.
Maximum allowed nesting depth is 1.
![]()
public class Test { protected void finalize() throws Throwable { // violation try { System.out.println("overriding finalize()"); } catch (Throwable t) { throw t; } finally { super.finalize(); } } }
check NoFinalizer for the original rule.
Allow only one statement per line. [Recommended] ΒΆ
It is very difficult to read multiple statements on one line.
![]()
//Each line causes violation: int var1; int var2; var1 = 1; var2 = 2; int var1 = 1; int var2 = 2; var1++; var2++; Object obj1 = new Object(); Object obj2 = new Object(); import java.io.EOFException; import java.io.BufferedReader; ;; //two empty statements on the same line. //Multi-line statements: int var1 = 1 ; var2 = 2; //violation here int o = 1, p = 2, r = 5; int t; //violation here
![]()
OutputStream s1 = new PipedOutputStream(); OutputStream s2 = new PipedOutputStream(); // only one statement(variable definition) with two variable references try (s1; s2; OutputStream s3 = new PipedOutputStream();) // OK {}![]()
// two statements with variable definitions try (Reader r = new PipedReader(); s2; Reader s3 = new PipedReader() // violation ) {}
check OneStatementPerLine for the original rule.
Need to group overloaded methods together. [Recommended] ΒΆ
Overloaded methods have the same name but different signatures where the signature can differ by the number of input parameters or type of input parameters or both.
![]()
public void foo(int i) {} public void foo(String s) {} public void foo(String s, int i) {} public void foo(int i, String s) {} public void notFoo() {}
![]()
public void foo(int i) {} public void foo(String s) {} public void notFoo() {} // violation. Have to be after foo(String s, int i) public void foo(int i, String s) {} public void foo(String s, int i) {}
check OverloadMethodsDeclarationOrder for the original rule.
Disallow assignment of parameters. [Recommended] ΒΆ
Parameter assignment is often considered poor programming practice. Forcing developers to declare parameters as final is often onerous. Having a check ensure that parameters are never assigned would give the best of both worlds.
Example:
class MyClass { int methodOne(int parameter) { if (parameter <= 0 ) { throw new IllegalArgumentException("A positive value is expected"); } parameter -= 2; // violation return parameter; } int methodTwo(int parameter) { if (parameter <= 0 ) { throw new IllegalArgumentException("A positive value is expected"); } int local = parameter; local -= 2; // OK return local; } IntPredicate obj = a -> ++a == 12; // violation IntBinaryOperator obj2 = (int a, int b) -> { a++; // violation b += 12; // violation return a + b; }; IntPredicate obj3 = a -> { int b = a; // ok return ++b == 12; }; }
check ParameterAssignment for the original rule.
Restrict the number of return statements in methods, constructors and lambda expressions. [Reference] ΒΆ
Too many return points can mean that code is attempting to do too much or may be difficult to understand.
![]()
public int sign(int x) { if (x < 0) return -1; if (x == 0) return 1; return 0; } // OK
![]()
public int badSign(int x) { if (x < -2) return -2; if (x == 0) return 0; if (x > 2) return 2; return 1; } // violation, more than three return statements
check ReturnCount for the original rule.
Simplify over-complicated boolean expression. [Recommended] ΒΆ
Complex boolean logic makes code hard to understand and maintain. Simplify for over-complicated boolean expressions. Currently, it finds code like if (b == true), b || true, !false, boolean a = q > 12 ? true : false, etc.
Example:
public class Test { public void bar() { boolean a, b; Foo c, d, e; if (!false) {}; // violation, can be simplified to true if (a == true) {}; // violation, can be simplified to a if (a == b) {}; // OK if (a == false) {}; // violation, can be simplified to !a if (!(a != true)) {}; // violation, can be simplified to a e = (a || b) ? c : d; // OK e = (a || false) ? c : d; // violation, can be simplified to a e = (a && b) ? c : d; // OK int s = 12; boolean m = s > 1 ? true : false; // violation, can be simplified to s > 1 boolean f = c == null ? false : c.someMethod(); // OK } }
check SimplifyBooleanExpression for the original rule.
Simplify over-complicated boolean return statements. [Recommended] ΒΆ
Simplify for over-complicated boolean return statements.
![]()
if (valid()) return false; else return true;
![]()
return !valid();
check SimplifyBooleanReturn for the original rule.
Always use String.equals() to check tring literals instead of == or !=. [Reference] ΒΆ
String literals are not used with == or !=. Since == will compare the object references, not the actual value of the strings, String.equals() should be used.
Example:
String status = "pending"; if (status == "done") {} // violation while (status != "done") {} // violation boolean flag = (status == "done"); // violation boolean flag = (status.equals("done")); // OK String name = "X"; if (name == getName()) {} // OK, limitation that check cannot tell runtime type returned from method call
check StringLiteralEquality for the original rule.
Remove unused local variables. [Recommended] ΒΆ
Remove that a local variable is declared and/or assigned, but not used.
Example: ```java class Test {
int a; { int k = 12; // violation, assigned and updated but never used k++; } Test(int a) { // ok as 'a' is a constructor parameter not a local variable this.a = 12; } void method(int b) { int a = 10; // violation int[] arr = {1, 2, 3}; // violation int[] anotherArr = {1}; // ok anotherArr[0] = 4; } String convertValue(String newValue) { String s = newValue.toLowerCase(); // violation return newValue.toLowerCase(); } void read() throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String s; // violation while ((s = reader.readLine()) != null) { } try (BufferedReader reader1 // ok as 'reader1' is a resource and resources are closed // at the end of the statement = new BufferedReader(new FileReader("abc.txt"))) { } try { } catch (Exception e) { // ok as e is an exception parameter } } void loops() { int j = 12; for (int i = 0; j < 11; i++) { // violation, unused local variable 'i'. } for (int p = 0; j < 11; p++) // ok p /= 2; } void lambdas() { Predicate<String> obj = (String str) -> { // ok as 'str' is a lambda parameter return true; }; obj.test("test"); }} ```
check UnusedLocalVariable for the original rule.
Reference ΒΆ
Checkstyle - Coding
Weekly meeting minutes 2022-10-13
Weekly meeting minutes 2022-12-01 Weekly meeting minutes 2022-12-08