Blame

077f35 Melisha Dsouza 2026-01-15 16:09:48 1
# **Core Java**
2
3
| Version | Date | Description | Author |
4
| ------- | ------------ | --------------------------------- | -------------- |
5
| 1.0 | 30 Oct. 2018 | Core Java Coding Standards | Ronak Vakharia |
6
| 2.0 | 12 Jan. 2026 | Added new Java features standards | Ravi Bansode |
7
8
## **1. Introduction**
9
### **1.1 Purpose**
10
This document describes the Java coding standard to be adhered to when writing software at Blast Radius.
11
### **1.2 Scope**
12
This document is intended to be used by Blast Radius software developers.
13
### **1.3 Application**
14
* In a team development environment, programmers often need to maintain code developed by other programmers. When a wide variety of coding styles exist in that environment, maintenance usually takes longer and is more defect-prone. Coding to a standard style creates an end product that is easier to read and maintain. Following an agreed-upon set of rules when programming also allows tools and utilities to be built that gather information about the source code.
15
* If the rules and recommendations are followed, the result source code should be easy to maintain, have a style consistent with that produced by other developers on the project, and be free of practices that are error-prone.
16
* The following is a list of some of the positive and negative impacts of using a set of coding standards:
17
* **Consistency**: The team of developers can share a common view when reading, inspecting, and maintaining code.
18
* **Reduce errors**: The coding standards restrict the use of error-prone language features, and formatting.
19
* **Training**: Writing good code takes experience. If all existing code meets a minimal standard, new programmers are provided with good examples to start from.
20
* **Freedom**: Developer implementation freedom is reduced.
21
22
### **2. Rules and Recommendations**
23
#### **2.1 General**
24
##### **2.1.1 Rules:**
25
* Every time a rule in the coding standard is broken, there must be a clearly documented reason for doing so.
26
* No coding standard can anticipate every problem that a programmer will face, and this one doesn't pretend to. But be prepared to defend a divergence from the standard, and do so in a comment. This will prevent a well-intentioned attempt to fix the code later.
27
* When there is a difference between this coding standard and that of the client, the client's coding standard will take precedence.
28
##### **2.1.2 Recommendations:**
29
* Code for readability first. Optimize for performance only when there's a demonstrated and proven performance problem, and a clearly understood working solution is already available.
30
* **Exceptions**: when it's known beforehand that the performance of the code will be a critical bottleneck (e.g., network interface, disk access, etc), and where this coding standard indicates a practice for performance reasons.
31
32
#### **2.2 Coding Style**
33
##### **2.2.1 Rules:**
34
* One level of indentation equals four spaces. Tabs must be replaced with four spaces.
35
* Line length should not exceed 120 characters.
36
* Opening and closing braces must be formatted using one of the following two methods:
37
**Method 1:** On a line by themselves at the same level of indentation as the initiating keyword.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 38
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 39
40
if ( byteBuf == null )
41
{
42
byteBuf = new ByteBuffer( BUFFER_SIZE );
43
}
44
```
45
**Exception**: the closing brace of the do-while statement.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 46
```Java
47
do
48
{
49
charNumber++;
50
ch = clientName.getChar( charNumber );
51
52
} while ( ch != '\0' );
077f35 Melisha Dsouza 2026-01-15 16:09:48 53
```
54
**Method 2:** Opening brace on the same line as the initiating keyword and closing brace on a line by itself at the same level of indentation as the initiating keyword.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 55
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 56
if ( byteBuf == null ) {
57
byteBuf = new ByteBuffer( BUFFER_SIZE );
58
}
59
```
60
**Exception**: the closing brace of the do-while and try statements.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 61
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 62
do {
63
charNumber++;
64
ch = clientName.getChar( charNumber );
65
66
} while ( ch != '\0' );
67
68
try {
69
doSomeThing();
70
} catch (ExceptionClass e) {
71
handleException();
72
}
73
```
74
* The two methods for formatting braces must not be mixed in same file or package. When modifying an existing file or package, the existing brace formatting style must be used and not changed.
75
76
##### **2.2.2 Recommendations:**
77
* Always write the left parenthesis directly after a function name (no intervening space).
78
* Surround operators with spaces.
79
Don't do things like this:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 80
```java
077f35 Melisha Dsouza 2026-01-15 16:09:48 81
newXPos+=recClient.Width()+recUpdate.Width()+margin*columns;
82
```
83
It makes the operators easy to miss in a quick inspection. Do this instead:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 84
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 85
newXPos += recClient.Width() + recUpdate.Width() + margin * columns;
86
```
87
* When a statement spans more than one line, break the statement in a way that each line is obviously syntactically incorrect, and indent the continued line or lines in a way that makes the continuation more visible.
88
This prevents misreading of code. For example, the first line of the statement below could be interpreted as a complete statement:
89
```
90
Java
91
String addressLine1 = getApartmentNumber() + getStreetAddress() + getStreetName();
92
```
93
The code below provides a strong visual cue that it's continued on the next line:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 94
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 95
String addressLine1 = getApartmentNumber() + getStreetAddress()
96
+ getStreetName();
97
```
98
#### **2.3 Javadoc Comments**
99
##### **2.3.1 Rules:**
100
* All classes and public methods must be preceded by a javadoc comment.
101
* Class javadoc comments must contain a meaningful description of the class and an @author tag for each person who has worked on any part of the class.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 102
103
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 104
/**
105
* <p>COPYRIGHT</p>
106
* <p>Blast Radius -- Copyright (C) 2007 Blast Radius
107
* All rights reserved. No part of this computer program
108
* may be used or reproduced in any form by any
109
* means without prior written permission of
110
* Blast Radius.</p>
111
*
112
* <p>DESCRIPTION</p>
113
* <p>Contains the dimensions of a bounding box that will enclose
114
* zero or more graphical objects on a screen. The dimensions
115
* will increase as required when items are added to the box.</p>
116
*
117
* @author Pete Peterson
118
* @version 1.0
119
* @see related_class
120
*/
121
class BoundingBox {
122
// ...
123
}
124
```
125
* Method javadoc comments must include a meaningful description of the method, @param tags for each parameter, and, if applicable, @return and @exception tags.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 126
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 127
/**
128
* Adds a graphic object to the bounding box. If any of the object's
129
* dimensions fall outside the box, the box's dimensions will grow to
130
* include them.
131
*
132
* @param element the graphic element to be added to the box
133
* @return true if the bounding box has expanded as a result of adding
134
* the item, false if the dimensions are unchanged
135
* @see see_related_method or material
136
*/
137
public boolean addItem( GraphicElement element ) {
138
// ...
139
}
140
```
141
##### **2.3.2 Recommendations:**
142
* Precede all non-public methods by a javadoc comment.
143
144
### **2.4 Files**
145
###### **2.4.1 Rules:**
146
* All files or packages must include the standard comment header with copyright information as required by the project.
147
##### **2.4.2 Recommendations:**
148
* Try to keep the size of source files to less than one thousand lines.
149
If source files become larger than this, there's a good chance that the design should be looked at again, with more functionality being moved into smaller objects.
150
151
### **2.5 Naming Conventions**
152
#### **2.5.1 Rules:**
153
* Whenever mixed-case names are made up of more than one word, the first letter of each word following the first should be uppercase.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 154
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 155
closeFile();
156
Button okButton;
157
int accountTotal;
158
int average;
159
```
160
* Whenever all-uppercase names are made up of more than one word, each word should be separated with an underscore.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 161
```java
077f35 Melisha Dsouza 2026-01-15 16:09:48 162
final int MAX_RANGE = 100;
163
final String BUTTON_NAME = "a button name";
164
```
165
* Methods should be named so that they describe what the method does, starting with an active verb whenever possible.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 166
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 167
protected void hideComponent() { /* ... */ }
168
public int getAverage() { /* ... */ }
169
public void refreshScreen() { /* ... */ }
170
```
171
* Accessor methods that retrieve an attribute should begin with "get".
172
* Modifier methods should begin with "set".
173
* Components should end with the type of the component.
174
* This is to make the use of the variable a bit more obvious. For example `"ageTextField"` is unambiguous, while "age" may be mistaken for a numeric value.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 175
```java
077f35 Melisha Dsouza 2026-01-15 16:09:48 176
Button cancelButton = new Button();
177
List customerNameList;
178
BigGrid salesTrackingGrid;
179
```
180
* Class names should be a description of the class, and should be mixed case and begin with an uppercase letter.
181
* Interface names should be a description of the interface's services.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 182
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 183
interface Compressable { /* ... */ }
184
interface Singleton { /* ... */ }
185
```
186
* Package names should be all lower case, and be prefixed with the Internet domain of your organization, but with the components of the domain name in reverse order.
187
* For example, a for-profit organization with a domain `"ourcompany.com"` should create packages with names like `"com.ourcompany.ourproject"`, `"com.ourcompany.anotherproject"`, and `"com.ourcompany.ourproject.packageabc"`. Do not use capitals for the class A prefix.
188
* File names should be camel case. Java source files should match the name of the class they contain. Whether the first letter of the filename is upper or lower case should depend on the use of the file, standard conventions should be followed. Filenames should only contain `'a'-'z', 'A'-'Z', '0'-'9' and '_'`.
189
190
##### **2.5.2 Recommendations:**
191
* Avoid the overuse of "i", "j", and "k" as variable names.
192
* These variable names don't offer much in the way of providing readability. Compare:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 193
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 194
for ( int i = 0; i < totalMonthsDisplayed; i++ )
195
{
196
for ( j = 0; j < totalSales; j++ )
197
{
198
refresh( i, j );
199
}
200
}
201
```
202
... with ...
a837c9 Melisha Dsouza 2026-01-16 09:25:51 203
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 204
for ( int row = 0; row < totalMonthsDisplayed; row++ )
205
{
206
for ( column = 0; column < totalSales; column++ )
207
{
208
refresh( row, column );
209
}
210
}
211
```
212
213
#### **2.6 Class Member Access**
214
##### **2.6.1 Rules:**
215
* **All non-final fields should be private.**
216
* Hiding data provides all the benefits of using abstract data types, and limits the places that data can be changed (and/or corrupted). Giving an object the ability to prevent access to its internal state also allows it to test itself whenever its state is queried or changed to ensure that the change is consistent with the object's internal state.
217
218
**Don't do this:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 219
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 220
public class Foo
221
{
222
public int counter;
223
}
224
```
225
**Do this instead:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 226
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 227
public class Foo
228
{
229
private int counter;
230
231
public int getCounter( void )
232
{
233
return counter;
234
}
235
236
public void setCounter( int newCounter )
237
{
238
counter = newCounter;
239
}
240
}
241
```
242
Another problem with public, protected, or package access fields becomes apparent when a variable name must be changed or removed from the class. Every derived class (or friends of the derived classes) that directly reference those variables must also be modified.
243
* **Avoid having public member function return a reference to a private field.**
244
* This allows outside code to change the state of an object without that object knowing about it. When possible, return a clone of the member object.
245
#### **2.6.2 Recommendations:**
246
* When a private data member has a public or protected access method, those methods should be used internally by the class as much as possible to provide consistency.
247
**For example, given the following class:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 248
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 249
class Dimensions
250
{
251
public void setDimensions( int width, int height ) { /* ... */ }
252
253
public int getWidth( void ) { /* ... */ }
254
public int getHeight( void ) { /* ... */ }
255
public int getArea( void ) { /* ... */ }
256
257
private int width; // width dimension
258
private int height; // height dimension
259
}
260
```
261
The code in the body of `Dimension.getArea()` could look like this:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 262
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 263
area = width * height;
264
```
265
This would work, but will need to be modified if the height or width were changed from a data member to a calculated value. The following code would require no such modification:
266
a837c9 Melisha Dsouza 2026-01-16 09:25:51 267
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 268
area = getWidth() * getHeight();
269
```
270
271
#### **2.7 Class Constructors & Initialization**
272
##### **2.7.1 Rules:**
273
* **Instance initialization code blocks should only be used in anonymous classes.**
274
Putting construction code in constructors keeps all this related code together. When various code blocks initialize data throughout the class definition, understanding what's being initialized by whom becomes difficult.
275
* **Always explicitly call the base class constructor in any place that the compiler would implicitly call it.**
276
In any constructor that does not have as its first line of code (a) a call to a base class constructor, or (b) a call to another "this" constructor, the compiler will implicitly insert a call to `super()`. This can lead to confusion when the base class has no no-argument constructor.
277
An additional benefit is that tracing execution through a constructor chain makes more sense when there are explicit calls to `super()`.
278
* **Always explicitly create any constructor that the compiler would implicitly create, even if it contains no statements other than a call to super().**
279
The compiler will explicitly create an empty no-argument constructor when you define no constructors for a class. Explicitly coding one prevents some confusion when debugging, and makes more sense when tracing through constructor chains.
280
281
##### **2.7.2 Recommendations:**
282
* Avoid methods with many arguments.
283
* Avoid long and complex methods.
284
285
#### **2.8 Variables and Types**
286
##### **2.8.1 Rules:**
287
* Avoid the use of numeric values in code, use symbolic values instead.
288
**For example:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 289
```java
077f35 Melisha Dsouza 2026-01-15 16:09:48 290
colWidth = strWidth + 10 + ( level * 3 );
291
// ...
292
cellWidth = cellStrWidth + 10;
293
```
294
For the unfortunate programmer who has to maintain (or fix) the above code, there's no indication of what "10" or "3" represents, or whether both "10"s represent the same thing. And if the code maintainer finally figures out that "10" probably represents margin widths, and changes it to something smaller, there's an excellent chance that an instance will be missed, and more time will be wasted tracking down a difficult-to-find bug. Something like the following code should be written in the first place:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 295
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 296
final int COL_INDENT_WIDTH = 3; // amount to indent, per level
297
final int COL_LEFT_MARGIN = 5; // width of column left margin in pixels
298
final int COL_RIGHT_MARGIN = 5; // width of column right margin in pixels
299
300
// pixel width of both margins combined
301
final int COL_MARGINS_WIDTH = COL_LEFT_MARGIN + COL_RIGHT_MARGIN;
302
303
colWidth = strWidth + COL_MARGINS_WIDTH + ( level * COL_INDENT_WIDTH );
304
// ...
305
cellWidth = cellStrWidth + COL_MARGINS_WIDTH;
306
```
307
* Variables are to be declared with the smallest possible scope.
308
* Each variable is to be declared in a separate declaration statement, and have a commented description.
309
**Don't do this:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 310
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 311
int moveAmount, selectedIndex;
312
```
313
**Do this:**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 314
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 315
int moveAmount; // number of items to move
316
int selectedIndex; // currently selected item
317
```
318
#### **2.9 Flow Control Statements**
319
###### **2.9.1 Rules:**
320
* The code which follows a case label must always be terminated by a break statement.
321
* The switch statement must always contain a default branch, which handles unexpected cases.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 322
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 323
switch (tag)
324
{
325
case A:
326
{
327
// Do something
328
break;
329
}
330
default:
331
{
332
// If no match in above cases, this is executed
333
}
334
}
335
```
336
**Exception: **when several different cases have identical handling.
337
338
* Use opening and closing braces in case blocks that contain variable declarations.
339
* A switch statement must always contain a default branch which handles unexpected cases.
340
* All flow control statements (if, else, while, for and do) must have opening and closing braces, even if the block contains no statements.
341
Empty loops can be deceiving. In the example below, it's easy to mistakenly think that the last line is contained in the loop:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 342
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 343
for ( int rowNumber = initialRow;
344
( rowNumber < totalRows ) && !getRow( rowNumber ).getIsSelected() &&
345
( getRow( rowNumber ).getNumberOfCells() > 0 );
346
rowNumber++ );
347
numberOfRowFound = rowNumber;
348
```
349
When the braces are included, the empty loop is unmistakable:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 350
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 351
for ( int rowNumber = initialRow;
352
( rowNumber < totalRows ) && !getRow( rowNumber ).getIsSelected() &&
353
( getRow( rowNumber ).getNumberOfCells() > 0 );
354
rowNumber++ )
355
{
356
// empty
357
}
358
numberOfRowFound = rowNumber;
359
```
360
* Use an explicit if...else... structure rather than the ternary statement.
361
The ternary statement acts as a shortcut for the if...else... statement. However, the statement:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 362
```java
077f35 Melisha Dsouza 2026-01-15 16:09:48 363
( rowNumber == 0 ) ? selectTable() : selectRow( rowNumber );
364
```
365
...will likely compile the same as the more readable:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 366
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 367
if ( rowNumber == 0 )
368
{
369
selectTable();
370
}
371
else
372
{
373
selectRow( rowNumber );
374
}
375
```
376
**Exception**: cases in which a ternary statement simplifies an assignment.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 377
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 378
double scale = ( isHalfScale() ? 0.5 : 1 );
379
380
// ...may be more readable than...
381
382
double scale;
383
if ( isHalfScale() )
384
{
385
scale = 0.5;
386
}
387
else
388
{
389
scale = 1;
390
}
391
```
392
##### **2.9.2 Recommendations:**
393
* **Use inclusive lower limits and exclusive upper limits.**
394
Rather than say that x is the interval x >= 0 and x <= 9, use the limits x >= 0 and x < 10. If you do so, then:
395
* the difference in the limits is the size of the interval (interval = 10-0 rather than interval = 9-0+1)
396
* if the interval is zero, the limits will be equal
397
* the upper limit will never be less than the lower limit.
398
399
* **Avoid the use of continue.**
400
`continue` tends to make loops harder to understand by concealing the structure of program execution. When tempted to use them, try to use an if...else.. statement instead.
401
Exception: a `continue` statement near the top of a loop can sometimes make the code more readable by avoiding a series of if...else... statements, or a complex loop control structure. For example:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 402
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 403
while ( row != null )
404
{
405
if ( row.getIsEmpty() )
406
{
407
// row cannot contain data, do not process
408
continue;
409
}
410
// ... process row ...
411
row = row.getNext();
412
}
413
```
414
* **Avoid the use of break in anything but the switch statement.**
415
break tends to make loops harder to understand by concealing their exit conditions. Here's an example of break that confuses the structure of a loop:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 416
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 417
while ( true )
418
{
419
Rectangle areaRect = area.getRectArea();
420
if ( areaRect.pointInRect( firstPoint ) )
421
{
422
if ( area.getType() == NON_CLIENT_AREA )
423
areaWidth -= areaRect.Width();
424
else
425
break;
426
}
427
if ( area.getNext() == null )
428
break;
429
else
430
area = area.getNext();
431
}
432
433
```
434
**Exception**: break can sometimes be used judiciously to avoid messy nested if...else statements in loops or a large number of boolean conditions in the control statement at the top:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 435
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 436
while ( ch != '\u0000' )
437
{
438
// if this is a metastring token, drop out of the loop
439
if ( ch == '%' )
440
{
441
tokenPosition = pos;
442
break; // <------ early exit from loop
443
}
444
// ... more code to process 'ch' ...
445
}
446
```
447
* **Avoid the use of multiple return statements.**
448
The flow of control within a function is more difficult to understand when there are multiple exit points.
449
450
**Exception**: early returns can sometimes be used at the beginning of a function to avoid long if...else.. constructions. When used in this way, it's recommended that they are documented in a way that draws attention to them.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 451
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 452
boolean setName( Client client, String name )
453
{
454
int clientIndex = findClient( client );
455
if ( clientIndex == CLIENT_NOT_FOUND )
456
{
457
return; // <--------- early return for invalid client
458
}
459
// ...
460
}
461
```
462
#### **2.10 Comments**
463
##### **2.10.1 Recommendations:**
464
* **Comment in a style that's easy to maintain.**
465
Example of a hard-to-maintain commenting style:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 466
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 467
//--------------------------------------//
468
// get the size of the buffer //
469
//--------------------------------------//
470
```
471
Example of easy-to-maintain commenting styles:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 472
```Java
473
//------------------------------
474
// get the size of the buffer
475
//------------------------------
476
477
/*
478
* get the size of the buffer
479
* then allocate another buffer of the same size.
480
*/
481
```
077f35 Melisha Dsouza 2026-01-15 16:09:48 482
* **Comment as you go.**
483
Don't code with the intention of going back later and putting comments in. Try to comment first and code around the comments.
484
* **Avoid non-data endline comments.**
485
Endline comments are difficult to maintain because they have to aligned properly, are difficult to edit, and there usually isn't enough space to comment effectively.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 486
077f35 Melisha Dsouza 2026-01-15 16:09:48 487
**Exceptions**: data declarations, and comments at the end of blocks. Example of these:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 488
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 489
int numberOfKeys; // number of virtual keystrokes
490
// ...
491
} // switch
492
} // for
493
```
494
* **Don't duplicate the code in the comment.**
495
The following comments are redundant:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 496
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 497
// if the allocation flag is more than zero
498
if ( allocSize > 0 )
499
{
500
// initialize buffer size to allocSize
501
bufferSize = allocSize;
502
}
503
```
504
This comment explains what's actually happening:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 505
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 506
// if a buffer was successfully allocated, record the size
507
if ( allocSize > 0 )
508
{
509
bufferSize = allocSize;
510
}
511
```
512
#### **2.11 Exception-Handling**
513
##### **2.11.1 Rules:**
514
* **Where there is a clear separation between presentation classes and integration classes, the integration class should repackage checked exceptions to pass to the presentation class to preserve encapsulation.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 515
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 516
public class UserDAOImpl implements UserDAO
517
{
518
findByUserId(String userId)
519
{
520
User user = null;
521
try
522
{
523
user = (User)getSqlMapClientTemplate().queryForObject(GET_USER, userId);
524
}
525
catch(DataAccessException ex)
526
{
527
//service class, must repackage exception
528
logger.error("could not access database",ex);
529
throw new ApplicationException("could not connect to database", ex);
530
}
531
}
532
}
533
```
534
* **Preserve the original stack trace information throughout the life of the Exception.**
535
If an exception is caught in an integration class, and an exception is to be re-thrown to the presentation class, the newly thrown exception must preserve the caught exception stack trace.
536
* **Exceptions should be logged once whenever they are caught except as outlined by rule 4 and dealt with where they are caught, exceptions should not be passed to generic exception handling methods.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 537
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 538
public class UserDAOImpl implements UserDAO
539
{
540
findByUserId(String userId)
541
{
542
User user = null;
543
try
544
{
545
user = (User)getSqlMapClientTemplate().queryForObject(GET_USER, userId);
546
}
547
catch(DataAccessException ex)
548
{
549
//service class, must repackage exception
550
logger.error("could not access database",ex);
551
throw new ApplicationException("could not connect to database", ex);
552
}
553
}
554
}
555
```
556
* **Swallowed checked exceptions should be avoided, and where they cannot be avoided proper commenting should document why an empty catch block exists. The general exception java.lang.Exception should never be caught.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 557
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 558
try
559
{
560
AdditionalData additionalData = getAdditionalUserData(userId);
561
}
562
catch(UserNotRegistered ex)
563
{
564
/*
565
* thrown if the user has not been registered in the third party service
566
* which isn't necessary for updating the user information
567
*/
568
}
569
```
570
* **A function should not contain split try catch blocks, where multiple checked exceptions are caught they should be handled in subsequent catch blocks or if necessary in nested try blocks.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 571
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 572
try
573
{
574
User user = (User)getSqlMapClientTemplate().queryForObject(GET_USER, userId);
575
UserMetaData userMetaData = userMetaDataService.getUserMetaDataByUser(user);
576
}
577
catch(SQLException ex)
578
{
579
throw new ApplicationException("could not access database" , ex);
580
}
581
catch(WebServiceConnectionException ex)
582
{
583
throw new ApplicationException("could not connect to web service" , ex);
584
}
585
```
586
* **List all normal exceptions thrown in the throws clause, not just base class of related exceptions.**
587
In other words, if your method throws MyException and MyDerivedException (which is derived from MyException), don't just declare MyException. While this is legal in the language, it hides useful information from those using your class.
588
589
* **Catch subclasses before base classes.**
590
If you catch the base class of an exception before trying to catch classes derived from it, the first catch block will catch all derived exceptions:
a837c9 Melisha Dsouza 2026-01-16 09:25:51 591
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 592
try
593
{
594
doSomething();
595
}
596
catch ( BaseExceptionClass e ) // this should come after the next block
597
{
598
// ...
599
}
600
catch ( DerivedFromBaseExceptionClass e )
601
{
602
// ... will never get here, because the previous catch
603
// statement will catch all classes derived from
604
// BaseExceptionClass
605
}
606
```
607
#### **2.12 Event-Handling**
608
##### **2.12.1 Rules:**
609
610
* **Don't call message handlers directly.**
611
If another function needs to invoke code identical to that in a message handler, move the code out into a different function, and have both the message handler and the other function call the common code.
612
613
* **Event handler methods should be lightweight and delegate complex logic to service or business logic classes.**
614
Event handlers should primarily coordinate actions and delegate to appropriate service methods rather than containing complex business logic themselves.
615
616
#### **2.13 Memory Management and Performance**
617
##### **2.13.1 Rules:**
618
619
* **Always use try-with-resources for AutoCloseable resources.**
620
This ensures proper resource cleanup and prevents resource leaks.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 621
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 622
// Good
623
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
624
return reader.readLine();
625
}
626
627
// Bad
628
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
629
try {
630
return reader.readLine();
631
} finally {
632
reader.close();
633
}
634
```
635
* **Close resources in the reverse order of their creation in finally blocks (when try-with-resources cannot be used).**
636
* **Avoid creating unnecessary objects in loops.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 637
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 638
// Bad
639
for (int i = 0; i < 1000; i++) {
640
String status = "Processing " + i;
641
log.debug(status);
642
}
643
644
// Good
645
for (int i = 0; i < 1000; i++) {
646
log.debug("Processing {}", i);
647
}
648
```
649
* **Never ignore InterruptedException without re-interrupting the thread.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 650
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 651
try {
652
Thread.sleep(1000);
653
} catch (InterruptedException e) {
654
Thread.currentThread().interrupt(); // Preserve interrupt status
655
throw new RuntimeException("Thread interrupted", e);
656
}
657
```
658
##### **2.13.2 Recommendations:**
659
* **Use StringBuilder or StringBuffer for string concatenation in loops.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 660
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 661
// Bad
662
String result = "";
663
for (String item : items) {
664
result += item;
665
}
666
667
// Good
668
StringBuilder result = new StringBuilder();
669
for (String item : items) {
670
result.append(item);
671
}
672
```
673
* **Avoid premature optimization. Profile first, then optimize.**
674
* **Consider using object pooling only for expensive-to-create objects (e.g., database connections, thread pools).**
675
* **Avoid using finalizers. Use try-with-resources or explicit cleanup methods instead.**
676
* **Be aware of autoboxing/unboxing costs in performance-critical code.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 677
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 678
// Bad - autoboxing in loop
679
Integer sum = 0;
680
for (int i = 0; i < 1000000; i++) {
681
sum += i; // Boxing and unboxing on each iteration
682
}
683
684
// Good
685
int sum = 0;
686
for (int i = 0; i < 1000000; i++) {
687
sum += i;
688
}
689
```
690
* **Use lazy initialization for expensive objects only when necessary.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 691
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 692
private volatile ExpensiveObject instance;
693
694
public ExpensiveObject getInstance() {
695
if (instance == null) {
696
synchronized (this) {
697
if (instance == null) {
698
instance = new ExpensiveObject();
699
}
700
}
701
}
702
return instance;
703
}
704
```
705
#### **2.14 Concurrency and Thread Safety**
706
##### **2.14.1 Rules:**
707
* **Always use the highest-level concurrency utilities available** (Executor framework, concurrent collections) rather than wait(), notify(), and synchronized blocks when possible.
708
* **Document thread-safety guarantees for all classes.**
709
Use annotations like` @ThreadSafe`, `@NotThreadSafe`, or `@Immutable` in javadoc.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 710
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 711
/**
712
* This class is thread-safe. All methods can be called concurrently.
713
* @ThreadSafe
714
*/
715
public class ThreadSafeCounter {
716
// ...
717
}
718
```
719
* **Never expose mutable internal state without proper synchronization.**
720
* **Always use the volatile keyword for flags that are set by one thread and read by others.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 721
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 722
private volatile boolean shutdownRequested = false;
723
```
724
* **Avoid holding locks while calling methods on objects outside your control.**
725
This can lead to deadlocks.
726
* **Always acquire multiple locks in a fixed global order to prevent deadlock.**
727
* **Use thread-safe collections instead of manually synchronizing collection access.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 728
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 729
// Good
730
Map<String, String> map = new ConcurrentHashMap<>();
731
732
// Bad
733
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
734
```
735
##### **2.14.2 Recommendations:**
736
* **Prefer immutable objects for thread safety.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 737
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 738
public final class ImmutablePerson {
739
private final String name;
740
private final int age;
741
742
public ImmutablePerson(String name, int age) {
743
this.name = name;
744
this.age = age;
745
}
746
747
public String getName() { return name; }
748
public int getAge() { return age; }
749
}
750
```
751
* **Use ExecutorService instead of creating threads directly.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 752
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 753
// Good
754
ExecutorService executor = Executors.newFixedThreadPool(10);
755
executor.submit(() -> performTask());
756
executor.shutdown();
757
758
// Bad
759
new Thread(() -> performTask()).start();
760
```
761
* **Prefer ReentrantLock over synchronized when you need advanced features** (tryLock, timed locks, interruptible locks).
762
* **Use CountDownLatch, CyclicBarrier, or Phaser for coordinating multiple threads.**
763
* **Avoid ThreadLocal unless absolutely necessary, and always clean up ThreadLocal variables.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 764
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 765
private static final ThreadLocal<DateFormat> dateFormat =
766
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
767
768
public void cleanup() {
769
dateFormat.remove(); // Always clean up
770
}
771
```
772
* **Use CompletableFuture for asynchronous programming.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 773
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 774
CompletableFuture.supplyAsync(() -> fetchData())
775
.thenApply(data -> processData(data))
776
.thenAccept(result -> saveResult(result))
777
.exceptionally(ex -> {
778
log.error("Error in async chain", ex);
779
return null;
780
});
781
```
782
* **Document lock ordering to prevent deadlocks.**
783
* **Consider using the Fork/Join framework for recursive parallel tasks.**
784
785
#### **2.15 API Design and Interfaces**
786
##### **2.15.1 Rules:**
787
788
* **Prefer interfaces to abstract classes for defining types.**
789
Interfaces provide more flexibility as Java supports multiple interface implementation but only single inheritance.
790
* Use functional interfaces for single abstract method interfaces, and annotate with @FunctionalInterface.
a837c9 Melisha Dsouza 2026-01-16 09:25:51 791
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 792
@FunctionalInterface
793
public interface DataProcessor {
794
void process(Data data);
795
}
796
```
797
* **Never expose collection implementations in public APIs. Return interfaces instead.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 798
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 799
// Good
800
public List<String> getNames() {
801
return new ArrayList<>(names);
802
}
803
804
// Bad
805
public ArrayList<String> getNames() {
806
return names;
807
}
808
```
809
* **Return empty collections or arrays instead of null.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 810
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 811
// Good
812
public List<Customer> getCustomers() {
813
return customers.isEmpty() ? Collections.emptyList() : new ArrayList<>(customers);
814
}
815
816
// Bad
817
public List<Customer> getCustomers() {
818
return customers.isEmpty() ? null : customers;
819
}
820
```
821
* **Use defensive copying for mutable objects passed to or returned from methods.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 822
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 823
public class DateRange {
824
private final Date start;
825
private final Date end;
826
827
public DateRange(Date start, Date end) {
828
this.start = new Date(start.getTime()); // Defensive copy
829
this.end = new Date(end.getTime()); // Defensive copy
830
}
831
832
public Date getStart() {
833
return new Date(start.getTime()); // Defensive copy
834
}
835
}
836
```
837
* **Never return null from methods that return collections or arrays**
838
839
##### **2.15.2 Recommendations:**
840
* **Design interfaces for the clients, not for implementations.**
841
* **Keep interfaces small and focused (Interface Segregation Principle).**
842
* **Use default methods in interfaces sparingly, primarily for evolution.**
843
a837c9 Melisha Dsouza 2026-01-16 09:25:51 844
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 845
public interface Repository {
846
List<Entity> findAll();
847
848
default List<Entity> findAllSorted() {
849
return findAll().stream()
850
.sorted()
851
.collect(Collectors.toList());
852
}
853
}
854
```
855
* **Prefer method overloading to optional parameters for API design.**
856
* **Use Builder pattern for classes with many parameters.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 857
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 858
public class User {
859
private final String name;
860
private final String email;
861
private final int age;
862
863
private User(Builder builder) {
864
this.name = builder.name;
865
this.email = builder.email;
866
this.age = builder.age;
867
}
868
869
public static class Builder {
870
private String name;
871
private String email;
872
private int age;
873
874
public Builder name(String name) {
875
this.name = name;
876
return this;
877
}
878
879
public Builder email(String email) {
880
this.email = email;
881
return this;
882
}
883
884
public Builder age(int age) {
885
this.age = age;
886
return this;
887
}
888
889
public User build() {
890
return new User(this);
891
}
892
}
893
}
894
895
// Usage
896
User user = new User.Builder()
897
.name("John")
898
.email("john@example.com")
899
.age(30)
900
.build();
901
```
902
* **Document preconditions, postconditions, and invariants in javadoc.**
903
* **Consider using marker interfaces for metadata (like Serializable, Cloneable).**
904
* **Provide programmatic access to string representations (toString() should not be the only way).**
905
906
#### **2.16 Collection Framework Best Practices**
907
##### **2.16.1 Rules:**
908
* **Choose the correct collection type based on the use case:**
909
* `ArrayList` for random access and iteration
910
* `LinkedList` for frequent insertions/deletions
911
* `HashSet` for fast lookups with no duplicates
912
* `TreeSet` for sorted sets
913
* `HashMap` for key-value pairs
914
* `LinkedHashMap` for insertion-ordered maps
915
* `TreeMap` for sorted maps
916
917
* **Specify initial capacity for collections when the size is known in advance.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 918
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 919
// Good
920
List<String> list = new ArrayList<>(expectedSize);
921
Map<String, String> map = new HashMap<>(expectedSize);
922
923
// Bad
924
List<String> list = new ArrayList<>(); // Will resize multiple times
925
```
926
* **Never remove elements from a collection while iterating with for-each loop.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 927
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 928
// Bad - ConcurrentModificationException
929
for (String item : list) {
930
if (condition) {
931
list.remove(item);
932
}
933
}
934
935
// Good
936
Iterator<String> iterator = list.iterator();
937
while (iterator.hasNext()) {
938
String item = iterator.next();
939
if (condition) {
940
iterator.remove();
941
}
942
}
943
944
// Better (Java 8+)
945
list.removeIf(item -> condition);
946
```
947
* **Use Collections.unmodifiable or List.of(), Set.of(), Map.of() to return immutable collections.***
a837c9 Melisha Dsouza 2026-01-16 09:25:51 948
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 949
// Good (Java 9+)
950
List<String> immutableList = List.of("a", "b", "c");
951
Map<String, Integer> immutableMap = Map.of("key1", 1, "key2", 2);
952
953
// Good (Java 8)
954
List<String> immutableList = Collections.unmodifiableList(
955
new ArrayList<>(Arrays.asList("a", "b", "c"))
956
);
957
```
958
* **Never use raw types; always parameterize collections.**
959
```
960
Java
961
// Bad
962
List list = new ArrayList();
963
964
// Good
965
List<String> list = new ArrayList<>();
966
```
967
968
##### **2.16.2 Recommendations:**
969
* **Use the diamond operator (<>) to avoid redundant type information.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 970
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 971
// Good
972
Map<String, List<String>> map = new HashMap<>();
973
974
// Bad
975
Map<String, List<String>> map = new HashMap<String, List<String>>();
976
```
977
* **Prefer Arrays.asList() or List.of() for fixed-size lists.**
978
```
979
Java
980
// Good (immutable, Java 9+)
981
List<String> list = List.of("a", "b", "c");
982
983
// Good (fixed-size, pre-Java 9)
984
List<String> list = Arrays.asList("a", "b", "c");
985
```
986
* **Use EnumSet instead of bit fields for enum collections.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 987
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 988
// Good
989
Set<DayOfWeek> weekend = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
990
991
// Bad
992
int weekend = SATURDAY | SUNDAY;
993
```
994
* **Use EnumMap for enum keys instead of HashMap.**
995
```
996
Java
997
Map<DayOfWeek, String> schedule = new EnumMap<>(DayOfWeek.class);
998
```
999
* **Consider using Guava collections for advanced use cases (Multimap, BiMap, Table, etc.).**
1000
* **Use Collection.toArray(new T[0]) instead of Collection.toArray(new T[size]).**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1001
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1002
// Good
1003
String[] array = list.toArray(new String[0]);
1004
1005
// Outdated
1006
String[] array = list.toArray(new String[list.size()]);
1007
```
1008
* **Sort collections using Comparator and Collection.sort() or Stream API.**
1009
```
1010
Java
1011
// Good
1012
list.sort(Comparator.comparing(Person::getName));
1013
1014
// Or using Stream
1015
List<Person> sorted = list.stream()
1016
.sorted(Comparator.comparing(Person::getName))
1017
.collect(Collectors.toList());
1018
```
1019
1020
#### **2.17 Java 8+ Features Standards**
1021
##### **2.17.1 Rules:**
1022
* **Use lambda expressions instead of anonymous inner classes for functional interfaces.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1023
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1024
// Good
1025
list.forEach(item -> System.out.println(item));
1026
1027
// Bad
1028
list.forEach(new Consumer<String>() {
1029
@Override
1030
public void accept(String item) {
1031
System.out.println(item);
1032
}
1033
});
1034
```
1035
* **Use method references when they are clearer than lambda expressions.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1036
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1037
// Good
1038
list.forEach(System.out::println);
1039
1040
// Acceptable
1041
list.forEach(item -> System.out.println(item));
1042
```
1043
* **Use Optional to represent potentially absent values, but not for collections, arrays, or method parameters.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1044
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1045
// Good
1046
public Optional<User> findUserById(String id) {
1047
return Optional.ofNullable(userMap.get(id));
1048
}
1049
1050
// Bad - don't use Optional for parameters
1051
public void processUser(Optional<User> user) { }
1052
1053
// Bad - don't return Optional collections
1054
public Optional<List<User>> getUsers() { }
1055
```
1056
* **Never call Optional.get() without checking Optional.isPresent() first, or use proper Optional methods.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1057
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1058
// Bad
1059
Optional<User> user = findUser();
1060
User u = user.get(); // May throw NoSuchElementException
1061
1062
// Good
1063
Optional<User> user = findUser();
1064
User u = user.orElse(defaultUser);
1065
1066
// Or
1067
user.ifPresent(u -> processUser(u));
1068
```
1069
* **Use Stream API for collection processing, but avoid overusing streams for simple iterations.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1070
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1071
// Good - streams add value
1072
List<String> names = users.stream()
1073
.filter(user -> user.isActive())
1074
.map(User::getName)
1075
.sorted()
1076
.collect(Collectors.toList());
1077
1078
// Bad - simple loop is clearer
1079
users.stream().forEach(user -> processUser(user));
1080
// Better
1081
for (User user : users) {
1082
processUser(user);
1083
}
1084
```
1085
* **Always close streams that are backed by I/O resources.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1086
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1087
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
1088
lines.filter(line -> line.contains("error"))
1089
.forEach(System.out::println);
1090
}
1091
```
1092
* **Use java.time package (LocalDate, LocalDateTime, ZonedDateTime) instead of Date and Calendar.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1093
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1094
// Good
1095
LocalDate today = LocalDate.now();
1096
LocalDateTime now = LocalDateTime.now();
1097
ZonedDateTime zonedNow = ZonedDateTime.now(ZoneId.of("UTC"));
1098
1099
// Bad
1100
Date date = new Date();
1101
Calendar calendar = Calendar.getInstance();
1102
```
1103
1104
##### **2.17.2 Recommendations:**
1105
* **Prefer functional composition over imperative code when it improves readability.**
1106
* **Use Collectors for stream terminal operations.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1107
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1108
// Collect to list
1109
List<String> names = users.stream()
1110
.map(User::getName)
1111
.collect(Collectors.toList());
1112
1113
// Collect to map
1114
Map<String, User> userMap = users.stream()
1115
.collect(Collectors.toMap(User::getId, Function.identity()));
1116
1117
// Joining strings
1118
String csv = names.stream()
1119
.collect(Collectors.joining(", "));
1120
1121
// Grouping
1122
Map<Department, List<Employee>> byDept = employees.stream()
1123
.collect(Collectors.groupingBy(Employee::getDepartment));
1124
```
1125
* **Use Optional.orElseThrow() for validation.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1126
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1127
User user = findUserById(id)
1128
.orElseThrow(() -> new UserNotFoundException("User not found: " + id));
1129
```
1130
* **Prefer flatMap for nested optionals or streams.**
1131
```
1132
Java
1133
Optional<String> result = user
1134
.flatMap(User::getAddress)
1135
.flatMap(Address::getZipCode);
1136
```
1137
* **Use parallel streams judiciously, only for CPU-intensive operations on large datasets.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1138
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1139
// Use parallel streams only when appropriate
1140
long count = largeList.parallelStream()
1141
.filter(this::expensiveOperation)
1142
.count();
1143
```
1144
* **Use Stream.iterate() or Stream.generate() for infinite streams with limit().**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1145
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1146
Stream.iterate(0, n -> n + 1)
1147
.limit(10)
1148
.forEach(System.out::println);
1149
```
1150
* **Use CompletableFuture for asynchronous programming.**
1151
* **Leverage default and static methods in interfaces for backward compatibility.**
1152
* **Use @FunctionalInterface annotation for functional interfaces.**
1153
* **Consider using var (Java 10+) for local variables when the type is obvious.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1154
``` Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1155
// Good - type is obvious
1156
var list = new ArrayList<String>();
1157
var user = userRepository.findById(id);
1158
1159
// Bad - type is not obvious
1160
var result = process(); // What type is this?
1161
```
1162
#### **2.18 Logging Standards**
1163
##### **2.18.1 Rules:**
1164
* **Use SLF4J as the logging facade, not Log4j or java.util.logging directly.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1165
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1166
import org.slf4j.Logger;
1167
import org.slf4j.LoggerFactory;
1168
1169
public class UserService {
1170
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
1171
}
1172
```
1173
* **Initialize loggers as private static final fields.**
1174
* **Use appropriate log levels:**
1175
* **ERROR**: System failures, unrecoverable errors
1176
* **WARN:** Recoverable errors, deprecated API usag
1177
* **INFO**: Important business events, application lifecycle
1178
* **DEBUG**: Detailed information for debugging
1179
* **TRACE**: Very detailed information, typically for diagnosis
1180
* **Never log sensitive information (passwords, credit cards, PII, tokens, session IDs)**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1181
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1182
// Bad
1183
logger.info("User logged in: {}", user.getPassword());
1184
1185
// Good
1186
logger.info("User logged in: {}", user.getUsername());
1187
```
1188
* **Use parameterized logging instead of string concatenation.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1189
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1190
// Good
1191
logger.debug("Processing user {} with status {}", userId, status);
1192
1193
// Bad
1194
logger.debug("Processing user " + userId + " with status " + status);
1195
```
1196
* **Always log exceptions with the exception object, not just the message.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1197
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1198
// Good
1199
try {
1200
processData();
1201
} catch (DataException e) {
1202
logger.error("Failed to process data for user {}", userId, e);
1203
}
1204
1205
// Bad
1206
catch (DataException e) {
1207
logger.error("Failed to process data: " + e.getMessage());
1208
}
1209
```
1210
* **Guard expensive log statements with level checks.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1211
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1212
if (logger.isDebugEnabled()) {
1213
logger.debug("Complex calculation result: {}", expensiveCalculation());
1214
}
1215
```
1216
##### **2.18.2 Recommendations:**
1217
* **Use MDC (Mapped Diagnostic Context) for request tracking.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1218
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1219
MDC.put("requestId", requestId);
1220
MDC.put("userId", userId);
1221
try {
1222
// Process request
1223
logger.info("Processing request");
1224
} finally {
1225
MDC.clear();
1226
}
1227
```
1228
* **Log method entry and exit only at DEBUG or TRACE level.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1229
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1230
public void processOrder(Order order) {
1231
logger.debug("Entering processOrder with order: {}", order.getId());
1232
try {
1233
// Process order
1234
logger.debug("Exiting processOrder successfully");
1235
} catch (Exception e) {
1236
logger.debug("Exiting processOrder with error", e);
1237
throw e;
1238
}
1239
}
1240
```
1241
* **Use structured logging for complex data.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1242
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1243
logger.info("Order processed: orderId={}, userId={}, amount={}, status={}",
1244
order.getId(), order.getUserId(), order.getAmount(), order.getStatus());
1245
```
1246
* **Avoid logging in loops unless absolutely necessary.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1247
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1248
// Bad
1249
for (User user : users) {
1250
logger.debug("Processing user: {}", user.getId());
1251
processUser(user);
1252
}
1253
1254
// Good
1255
logger.debug("Processing {} users", users.size());
1256
for (User user : users) {
1257
processUser(user);
1258
}
1259
```
1260
* **Include context in log messages.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1261
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1262
// Bad
1263
logger.error("Processing failed");
1264
1265
// Good
1266
logger.error("Order processing failed for orderId: {}, userId: {}",
1267
orderId, userId);
1268
```
1269
* **Use consistent log message formatting across the application.**
1270
* **Configure appropriate log rotation and retention policies.**
1271
* **Use asynchronous logging for high-throughput applications.**
1272
1273
#### **2.19 Testing and Mocking Standards**
1274
##### **2.19.1 Rules:**
1275
* **Follow naming convention for test classes**: `<ClassUnderTest>Test`
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1276
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1277
// Class under test: UserService.java
1278
// Test class: UserServiceTest.java
1279
```
1280
* **Follow naming convention for test methods:** `testMethodName_StateUnderTest_ExpectedBehavior` or `methodName_StateUnderTest_ExpectedBehavior`
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1281
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1282
@Test
1283
public void findUserById_UserExists_ReturnsUser() { }
1284
1285
@Test
1286
public void findUserById_UserNotFound_ThrowsException() { }
1287
```
1288
* **Structure tests using the Arrange-Act-Assert (AAA) pattern.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1289
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1290
@Test
1291
public void calculateTotal_WithDiscount_ReturnsDiscountedTotal() {
1292
// Arrange
1293
Order order = new Order();
1294
order.addItem(new Item("Product", 100.0));
1295
Discount discount = new Discount(0.1); // 10% discount
1296
1297
// Act
1298
double total = order.calculateTotal(discount);
1299
1300
// Assert
1301
assertEquals(90.0, total, 0.01);
1302
}
1303
```
1304
* **Each test method should test one specific behavior or scenario.**
1305
* **Use @Before/@BeforeEach for common setup and @After/@AfterEach for cleanup.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1306
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1307
@BeforeEach
1308
public void setUp() {
1309
userRepository = mock(UserRepository.class);
1310
userService = new UserService(userRepository);
1311
}
1312
1313
@AfterEach
1314
public void tearDown() {
1315
// Cleanup resources
1316
}
1317
```
1318
* **Always use assertion libraries (JUnit assertions, AssertJ, Hamcrest).**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1319
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1320
// Good - JUnit 5
1321
assertEquals(expected, actual);
1322
assertThrows(IllegalArgumentException.class, () -> service.process(null));
1323
1324
// Good - AssertJ
1325
assertThat(result).isNotNull()
1326
.hasSize(3)
1327
.contains("item1", "item2");
1328
```
1329
* **Never catch exceptions in tests; use assertThrows instead.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1330
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1331
// Good
1332
assertThrows(UserNotFoundException.class, () -> userService.findById("invalid"));
1333
1334
// Bad
1335
try {
1336
userService.findById("invalid");
1337
fail("Expected UserNotFoundException");
1338
} catch (UserNotFoundException e) {
1339
// Expected
1340
}
1341
```
1342
* **Mock external dependencies, but don't mock the class under test.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1343
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1344
@Test
1345
public void createUser_ValidUser_SavesUser() {
1346
// Arrange
1347
UserRepository mockRepository = mock(UserRepository.class);
1348
UserService service = new UserService(mockRepository);
1349
User user = new User("John", "john@example.com");
1350
1351
when(mockRepository.save(any(User.class))).thenReturn(user);
1352
1353
// Act
1354
User result = service.createUser(user);
1355
1356
// Assert
1357
verify(mockRepository).save(user);
1358
assertEquals("John", result.getName());
1359
}
1360
```
1361
1362
##### **2.19.2 Recommendations:**
1363
* **Use Mockito for mocking, avoid PowerMock unless absolutely necessary.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1364
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1365
@ExtendWith(MockitoExtension.class)
1366
public class UserServiceTest {
1367
1368
@Mock
1369
private UserRepository userRepository;
1370
1371
@InjectMocks
1372
private UserService userService;
1373
1374
@Test
1375
public void testFindUser() {
1376
when(userRepository.findById("123")).thenReturn(Optional.of(user));
1377
// Test logic
1378
}
1379
}
1380
```
1381
* **Use ArgumentCaptor to verify complex method arguments.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1382
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1383
@Test
1384
public void createUser_ValidUser_SavesWithCorrectData() {
1385
ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
1386
1387
userService.createUser("John", "john@example.com");
1388
1389
verify(userRepository).save(userCaptor.capture());
1390
User capturedUser = userCaptor.getValue();
1391
assertEquals("John", capturedUser.getName());
1392
assertEquals("john@example.com", capturedUser.getEmail());
1393
}
1394
```
1395
* **Use @ParameterizedTest for testing multiple inputs.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1396
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1397
@ParameterizedTest
1398
@ValueSource(strings = {"", " ", " "})
1399
public void isBlank_BlankStrings_ReturnsTrue(String input) {
1400
assertTrue(StringUtils.isBlank(input));
1401
}
1402
1403
@ParameterizedTest
1404
@CsvSource({
1405
"1, 1, 2",
1406
"2, 3, 5",
1407
"5, 5, 10"
1408
})
1409
public void add_TwoNumbers_ReturnsSum(int a, int b, int expected) {
1410
assertEquals(expected, calculator.add(a, b));
1411
}
1412
```
1413
* **Use test fixtures for complex test data setup.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1414
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1415
public class UserFixtures {
1416
public static User createDefaultUser() {
1417
return new User("John", "john@example.com", 30);
1418
}
1419
1420
public static User createAdminUser() {
1421
User user = createDefaultUser();
1422
user.setRole(Role.ADMIN);
1423
return user;
1424
}
1425
}
1426
```
1427
* **Aim for high test coverage, but focus on critical paths and edge cases.**
1428
* **Use integration tests for testing component interactions, unit tests for isolated logic**.
1429
* **Use @SpringBootTest sparingly; prefer @WebMvcTest, @DataJpaTest, etc., for focused testing.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1430
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1431
@WebMvcTest(UserController.class)
1432
public class UserControllerTest {
1433
@Autowired
1434
private MockMvc mockMvc;
1435
1436
@MockBean
1437
private UserService userService;
1438
1439
@Test
1440
public void getUser_ValidId_ReturnsUser() throws Exception {
1441
when(userService.findById("123")).thenReturn(user);
1442
1443
mockMvc.perform(get("/users/123"))
1444
.andExpect(status().isOk())
1445
.andExpect(jsonPath("$.name").value("John"));
1446
}
1447
}
1448
```
1449
* **Use test containers for integration testing with databases and external services**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1450
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1451
@Testcontainers
1452
public class UserRepositoryIntegrationTest {
1453
1454
@Container
1455
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13");
1456
1457
@Test
1458
public void testDatabaseOperations() {
1459
// Test with real database
1460
}
1461
}
1462
```
1463
* **Never use System.out.println() in tests; use proper assertions and logging.**
1464
* **Keep tests fast. Slow tests won't be run frequently.**
1465
* **Use BDD style for better readability (given-when-then).**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1466
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1467
@Test
1468
public void userRegistration_ValidData_CreatesUser() {
1469
// Given
1470
String email = "test@example.com";
1471
String password = "password123";
1472
1473
// When
1474
User user = userService.register(email, password);
1475
1476
// Then
1477
assertThat(user).isNotNull();
1478
assertThat(user.getEmail()).isEqualTo(email);
1479
assertThat(user.isActive()).isTrue();
1480
}
1481
```
1482
* **Document complex test scenarios with comments.**
1483
* **Use @Disabled with a reason when temporarily disabling tests.**
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1484
```Java
077f35 Melisha Dsouza 2026-01-15 16:09:48 1485
@Test
1486
@Disabled("Disabled until bug #123 is fixed")
1487
public void testComplexScenario() {
1488
// Test code
1489
}
1490
```
a837c9 Melisha Dsouza 2026-01-16 09:25:51 1491
1492
**Document** - [Enovate Coding Standards - Core Java](https://docs.google.com/document/d/1EaOaSk-hbuje0igvIxl1DXcHQROc3KP-S49eD1IUGqg/edit?tab=t.0)