================================================================== Checkstyle Basics by Peter Froehlich, Joanne Selinski & Kirk Trombley last updated 1/28/2019 Enforcing coding standards: Many companies have specific coding standards to insure consistency and readability of code. The main standard for Java comes from the Sun Code Conventions. There is a much-used tool for checking the style of your java code that we will be using called Checkstyle. This is a program that evaluates your code with respect to many different coding conventions, such as whitespace, where to place {}, naming conventions, proper commenting, etc. The program is configurable with xml files in order to customize styles. You can read more about it here: http://checkstyle.sourceforge.net/ Note: Checkstyle is meant to be used with programs that are compiling. If you have compiler errors, checkstyle will probably only give you a limited set of errors because it can't parse your program properly. This document contains instructions for setting up and using checkstyle in several different programming environments. It then goes on to explain some of the most common errors students will have. You should definitely use the checkstyle website (checkstyle.sourceforge.net) for a clear understanding of the style expectations, in conjunction with the configuration file for your course. The best practice is to type your program consistent with the checkstyle configuration as you go along. Because the style conventions are created for readability, using them will also really help you with debugging your code, and in some cases preventing errors in the first place. ================================================================== Common Errors: This section explains lot of the less obvious checkstyle errors you'll probably see when writing code. There are plenty of self-explanatory errors, such as trailing whitespace or incorrect indentation levels. As a quick note, Checkstyle expects you to be indenting with 3-4 spaces per level, depending on the config file. Please note that these are space characters, NOT tab characters! If you are using some IDE for this course (eclipse, JGrasp) or even if you are using vim/emacs, be sure that you either manually indent with spaces, or set your editor to convert tabs to the correct number of spaces. It is your responsibility to ensure that this is done. Additional obvious errors are things like certain characters needing to be surrounded by whitespace (e.g. "4 + a" not "4+a"), or certain characters needing to be on a new line or the same line. For instance, regardless of your feelings on bracket placement, this is a common Checkstyle-approved if/else structure: if (condition) { // ... statements go here } else if (condition2) { // other statements } else { // more statements } Note that else appears on the same line as the closing brace of the if statement. [The configuration may be slightly different in order to be compatible with the jGRASP CSD format.] Also, note that brackets are required even for single line if blocks (this also applies to any kind of loop). Occasionally, you might see something like this: Name '_distance_traveled' must match pattern '^[a-z][a-zA-Z0-9]*$' For any of you familiar with regular expressions, you might know what's wrong. For those of you who aren't, this is saying that variable names must start with a character in the range a-z (i.e., lower-case letters), and can be followed by any number of lowercase letters, uppercase letters, or numbers. Good coding style here is camel case, which is usually the standard in Java (e.g., distanceTraveled not distance_traveled). If you put numeric literals into your code that are not 0, 1, or 2, you may see "5000 is a magic number." There is plenty of literature on why magic numbers are a bad idea, but the simplest explanation is this: If you have some numeric literal in your code, it can be difficult to quickly find and change it, should the needs of the project change. It is a much better idea to save that value as a constant (a variable declared as final) above the code that it is used in. Give it a name that describes its purpose, and then if it ever needs to change you only need to change it in one place. Granted, later there will be cases where you could argue that, yes, putting a 3 literal in your code is cleaner than assigning some constant THREE = 3 and using the constant, but that is the coding standard you are held to for this course. When you are writing a driver class, you will most likely see the error that utility classes should not have a public or default constructor. It is bad design to have a driver class that objects could be instantiated from. Thus, that class should not have a publicly available constructor. The solution is to write an empty constructor, and set it to private instead of public. This will only fix half of the error however, changing it into another one. You must now set the utility class to be final, by adding final to the "public class A" declaration at the top of the file. This prevents other classes from extending your utility class, another good design practice. If you try to use the ternary or inline conditional operator (?:), you may be told you cannot. In theory, ternaries can be very useful for concise code. In practice, it is way to tempting to use them in a confusing way. The last error to mention is cyclomatic complexity. This refers, roughly, to the number of ways that a given function can "branch." Every if-else statement is a branch, every switch statement is potentially many branches, and every loop with breaks/continues could potentially branch. If you have several nested loops, each with many conditionals in them, you will most likely run into a checkstyle error stating that your cyclomatic complexity is too high. The max allowed may differ by course, ranging usually from 10-15. This requires you to think about your algorithm. Are you checking things you don't need to be? Could portions of this code be moved out to helper functions? An important thing to remember is that cyclomatic complexity checks do not traverse into other functions when counting! So, you can have the same number of total if-else branches, but simply have some in one function, and some in another, and call both of those functions. The purpose of this check is to make reading and testing your code easier. The more branches in a given function, the harder it is to reason about what that function does just by reading it, and the more cases you must use in order to thoroughly test it. Feel free to ask your instructor, or any of the TAs, if you have any questions about what is explained here, or encounter an error you don't understand (use Piazza!). Remember, checkstyling is exactly as easy as checking to see if your code compiles. You wouldn't submit code that doesn't compile, so don't submit code that doesn't pass checkstyle! ================================================================== USING CHECKSTYLE: First download the course designated checkstyle*.jar file and your instructor's configuration file (usually named something with check and a .xml extension) to your computer. We recommend saving/moving them to a folder where you do your programming. (Ie, don't leave in Downloads.) ------------------------------------------ UNIX: Checkstyle from the command line In order to run checkstyle on a Java source file that's stored in the same directory as the jar and config file, you have to use the following command, with the exact .jar and .xml filenames you downloaded: > java -jar checkstyle*.jar -c *check*.xml SomeJavaFile.java This will execute the checkstyle program which is in a jar (java archive) using the specified configuration file on your java source code. You will then see a (most likely) long list of errors. In many cases the errors indicate what must be changed in order to fix things and bring your code up to standard. When in doubt, consult the checkstyle on-line documentation to find out what the expectations are. If your java file is in a child directory of the folder where the checkstyle files are located, (such as for project1 - recommended!), you can use relative paths in your unix command (but again substituting the actual filenames): > java -jar ../checkstyle*.jar -c ../*check*.xml SomeJavaFile.java Lastly, we recommended creating an alias in your shell .rc file for this so you don't have to remember what and how to type it all the time. ----------------------------------------------------------------- JGRASP: configuring & using Checkstyle Once you've launched jGrasp, go to Tools -> Checkstyle -> Configure There are two things you need to set: 1) The full path (location) of the folder containing your checkstyle*.jar file goes in the Checkstyle Home entry, not including the actual filename. 2) The full path (location) of the check*.xml configuration file goes in the Checks File entry, including the actual filename. To use on an active file, go to Tools -> Checkstyle -> Check File. You can also use the "check file" icon to the right. Note that checkstyle only works when a file has no syntax errors. ------------------------------------------------------------------ [NOTE: these instructions have not been checked in recent years] ECLIPSE: configuring to work with checkstyle, auto-formatting Here are the steps you need to get this all working together: 1) Install the Eclipse checkstyle plug-in: Help -> Install Software -> http://eclipse-cs.sf.net/update/, restart Eclipse. 2) Go to Preferences/Properties (Window menu on PC, Eclipse menu on Mac) -> Checkstyle, click new to add the checks*.xml configuration file, as an external file. Then select the course configuration and "Set as Default". 3) Again from Preferences/Properties -> Java -> Code Style set Clean-up and Formatter to be the styles you need to satisfy checkstyle, and save as your own custom profile. Specifically, in Formatter, under the Indentation tab change the Tab Policy drop down to Spaces Only. These files are eclipse specific, not quite the same as the checkstyle configuration files. They are the configurations for the next step. 4) For each project that you want to configure to work with checkstyle: right click the project in the package list -> Checkstyle -> Activate Checkstyle. This will check as you type and highlight violations. If you find this too annoying, you can turn it off again by right-clicking the project. (However, we strongly recommend you keep it on and make your files compliant as you go!!) 5) Once your project is configured, everytime you save a file it will update your checkstyle issues. In order to clean up your file using the settings above, go to the Source menu -> Clean up and Format and it will change things according to the settings from 3) so it's important to make those match the expected checkstyle exactly. 6) Eclipse Preferences are workspace specific. So if you create a new workspace and want the same settings, you'll have to repeat steps 2-4.