Checkstyle Class Design
Rules ¶
Check final classes. [Recommended] ¶
Checks that a class that has only private constructors and has no descendant classes is declared as final.
![]()
final class MyClass { // OK private MyClass() {} }
![]()
class MyClass { // violation, class should be declared final private MyClass() {} }
![]()
class MyClass { // OK, since it has a public constructor int field1; String field2; private MyClass(int value) { this.field1 = value; this.field2 = " "; } public MyClass(String value) { this.field2 = value; this.field1 = 0; } }
![]()
class TestAnonymousInnerClasses { // OK, class has an anonymous inner class. public static final TestAnonymousInnerClasses ONE = new TestAnonymousInnerClasses() { }; private TestAnonymousInnerClasses() {} }
check FinalClass for the original rule.
Make sure that utility classes do not have a public constructor. [Recommended] ¶
Instantiating utility classes does not make sense. Hence, the constructors should either be private or (if you want to allow subclassing) protected. A common mistake is forgetting to hide the default constructor.
![]()
class Test { // violation, class only has a static method and a constructor public Test() {} public static void fun() {} }
![]()
class Foo { // OK private Foo() {} static int n; }
![]()
class Bar { // OK protected Bar() { // prevents calls from subclass throw new UnsupportedOperationException(); } }
![]()
class UtilityClass { // violation, class only has a static field static float f; }
check HideUtilityClassConstructor for the original rule.
Use Interfaces only to define types. [Recommended] ¶
According to Bloch, an interface should describe a type. It is therefore inappropriate to define an interface that does not contain any methods but only constants. The Standard interface javax.swing.SwingConstants is an example of an interface that would be flagged by this check.
![]()
public interface Test1 { // violation int a = 3; }
![]()
public interface Test2 { // OK }
![]()
public interface Test3 { // OK int a = 3; void test(); }
check InterfaceIsType for the original rule.
Ensure exception classes have only final fields. [Recommended] ¶
Exception instances should represent an error condition. Having non-final fields not only allows the state to be modified by accident and therefore mask the original condition but also allows developers to accidentally forget to set the initial state. In both cases, code catching the exception could draw incorrect conclusions based on the state.
![]()
class FirstClass extends Exception { private int code; // OK, class name doesn't match with default pattern public FirstClass() { code = 1; } }
![]()
class MyException extends Exception { private int code; // violation, The field 'code' must be declared final public MyException() { code = 2; } }
![]()
class MyThrowable extends Throwable { final int code; // OK String message; // violation, The field 'message' must be declared final public MyThrowable(int code, String message) { this.code = code; this.message = message; } }
![]()
class BadException extends java.lang.Exception { int code; // violation, The field 'code' must be declared final public BadException(int code) { this.code = code; } }
check MutableException for the original rule.
Check top-level class, interface, enum or annotation. [Mandatory] ¶
Checks that each top-level class, interface, enum or annotation resides in a source file of its own. Official description of a 'top-level' term: 7.6. Top Level Type Declarations. If file doesn't contain public class, interface, enum or annotation, top-level type is the first type in file.
![]()
public class Foo { // OK, first top-level class // methods } class Foo2 { // violation, second top-level class // methods } record Foo3 { // violation, third top-level "class" // methods }
![]()
class Foo { // OK, first top-level class // methods } class Foo2 { // violation, second top-level class // methods }
![]()
public class Foo { // OK, only one top-level class // methods }
check OneTopLevelClass for the original rule.
Restrict throws statements to a specified count. [Recommended] ¶
Exceptions form part of a method's interface. Declaring a method to throw too many differently rooted exceptions makes exception handling onerous and leads to poor programming practices such as writing code like catch(Exception ex).
4 is the empirical value which is based on reports that we had for the ThrowsCountCheck over big projects such as OpenJDK. This check also forces developers to put exceptions into a hierarchy such that in the simplest case, only one type of exception need be checked for by a caller but any subclasses can be caught specifically if necessary. For more information on rules for the exceptions and their issues, see Effective Java: Programming Language Guide Second Edition by Joshua Bloch pages 264-273.
class Test { public void myFunction() throws CloneNotSupportedException, ArrayIndexOutOfBoundsException, StringIndexOutOfBoundsException, IllegalStateException, NullPointerException { // violation, max allowed is 4 // body } public void myFunc() throws ArithmeticException, NumberFormatException { // ok // body } private void privateFunc() throws CloneNotSupportedException, ClassNotFoundException, IllegalAccessException, ArithmeticException, ClassCastException { // ok, private methods are ignored // body } }
check ThrowsCount for the original rule.