MegaMek Coding Style Guide - MegaMek/megamek GitHub Wiki
Consistency is an important factor in code readability. Any code submitted to MegaMek, MegaMekLab, or MekHQ should follow the coding style outlined here. Anything not covered in here can probably be left up to the coder's preference, but if there is any doubt the Google Java Style Guide is a good source.
Note that MegaMek has been around for decades and has had many contributors over the years. Not all of the current code base adheres to these guidelines. These are the guidelines for new code, and old code is being brought into compliance gradually. Note also that despite the general state of the code we are not looking for contributions that only mean to modernize the code without addressing a specific issue (in other words, refactors), especially as a first time contribution.
Source File Structure
All source files must begin with a block comment that contains a copyright notice and the text of the license. Adjust the copyright year to be the current year when adding a new file. For existing files, this is to be merged at the top with existing copyrights that are NOT related to The MegaMek Team. If a new year and updating, hyphenate it with the current year. If it is already hyphenated, increment the end year to the current year.
In the below example, replace all comments of <Package Name>
with either MegaMek, MegaMekLab, or MekHQ and <Version for Package>
with either 2 for MegaMek or MegaMekLab or 3 for MekHQ
/*
* Copyright (C) 2025 The MegaMek Team. All Rights Reserved.
*
* This file is part of <Package Name>.
*
* <Package Name> is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL),
* version <Version for Package> or (at your option) any later version,
* as published by the Free Software Foundation.
*
* <Package Name> is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* A copy of the GPL should have been included with this project;
* if not, see <https://www.gnu.org/licenses/>.
*
* NOTICE: The MegaMek organization is a non-profit group of volunteers
* creating free software for the BattleTech community.
*
* MechWarrior, BattleMech, `Mech and AeroTech are registered trademarks
* of The Topps Company, Inc. All Rights Reserved.
*
* Catalyst Game Labs and the Catalyst Game Labs logo are trademarks of
* InMediaRes Productions, LLC.
*/
Wildcard imports are permitted for more than 10 imports from the same package.
Formatting
Braces
Braces follow the Kernigan and Ritchie style. The opening brace comes at the end of the line with the class declaration, method declaration, or control statement, separated from the closing round bracket by a space. The end brace is on a line by itself unless followed by a reserved word that is part of the block or connects a multi-block statement (else, catch, finally, while).
Examples:
class Foo {
// class definition
}
if (booleanExpr) {
// do a thing
} else {
// do a different thing
}
Braces are never omitted following if, else, for, while, or do, even for a single statement or an empty block:
if (booleanExpr) doSomething(); // wrong
if (booleanExpr) { //right
doSomething();
}
Empty blocks may appear on the same line if not part of a multi-block (if/else or try/catch) statement:
public void maybeDoTheThing() {} // ok
try {
defuseBomb();
} catch (WrongWireException ex) {} // not ok
Indentation
All block indentations are four spaces. Never tabs. Each case block in a switch statement should be indented one level.
Whitespace
A space should be used within a line in the following circumstances:
- Between a reserved word and a parenthesis or a brace.
- Between a parenthesis and a brace.
- On both sides of a binary or ternary operator, with the exception of a method reference (::) or the dot separator (.).
- After a comma
Parentheses
When building boolean expressions using multiple operators, the component expressions should be grouped explicitly:
if ((a == b) && (c == d))
rather than
if (a == b && c == d)
If the number of extra parentheses makes the expression hard to read, consider introducing local boolean variables.
Text String Handling and Localization
Any text strings displayed in the UI, either as UI elements or Report strings, should be stored in the appropriate messages.properties file to facilitate localization efforts.
Identifiers
Classes
Names of classes, interfaces, and enums should always be UpperCamelCase, with the first letter of every word capitalized and all other letters lowercase.
Variables and Methods
The names of methods and variables (including fields, local variables, and named parameters) should be lowerCamelCase, starting with a lower case letter and having the first letter of each additional word capitalized. The this. keyword as a prefix should only be used where necessary (e.g. in this.name = name).
The 'var' keyword can be used where it is helpful to avoid overly verbose declarations. It should however not be used when the type of the variable can't easily be seen from the declaration. In other words, avoid lines such as - var result = getResult();
Constants
Constants should be in all caps, with an underscore used to separate words. This includes fields that are declared static final and enum values.
Modern Java
We strive to use modern Java code. Still, it is important to keep in mind that the most concise code is not always the most readable. As many developers have to work with the code, it should prefer readability over being clever. Good ways to improve readability are:
- use descriptive names for variables and methods:
AmmoType ammoType
instead ofAmmoType at
(write code for humans, not computers) - use intermediate boolean variables for complex tests, or
- factor out to methods. This can be very useful to hide streams
- add javadoc comments to methods and classes; write the javadoc for those who do not already know what the method does and do not want to read the method's code
Streams and Optional
Streams can be very useful and very concise. However, their readability is debatable and their preferred form comprises multiple lines. Therefore, preferrably
- streams should not be used directly within the test expression of an if () statement
- when applicable, stream results should be stored in variables with descriptive names or placed in methods with descriptive names
Optionals can in some places improve the code, especially when used as a method return value, by forcing the caller to deal with the possibility of an empty return value. However, in other places they can be more cluttersome than helpful. Therefore, they should be used, but judiciously.
Comments and Documentation
JavaDoc
All public or protected methods and classes should be documented with a JavaDoc comment, but is good practice to do so for package and private methods as well. Exceptions can be made when in trivial cases where it is obvious what the method does, such as basic setters and getters, but it is better to err on the side of over documenting. It is not necessary to repeat the documentation when overriding a method that is documented in the parent class unless the method is overridden to do something that is not covered in the documentation of the parent class.
Annotations
When overriding an inherited method, the @Override annotation should always be used.