Thursday, 27 April 2023

Mastering Java: 20 Best Practices for Optimal Code Development

 

1) Favour primitives over primitive wrappers whenever possible.
2) To check for the oddity of a number the bitwise AND operator is much faster than the arithmetic modulo operator.

3) Avoid redundant initialization (0, false, null..)
Do not initialize variables with their default initialization, for example, a boolean by default has the value false so it is redundant to initialize it with the false value.

4) Declare class members private wherever possible and always give the most restricted access modifier.

5) Avoid the use of the ‘new’ keyword while creating a String

6) Use the concat method when concatenating possibly-empty Strings, and use + otherwise (since Java 8).

NB: Before Java 8, StringBuilder andStringBuffer were the best way for concatenating strings.

7) Using underscores in Numeric Literals.

8) Avoid using ‘for loops’ with indexes.
Do not use a for loop with an index (or counter) variable if you can replace it with the enhanced for loop (since Java 5) or forEach (since Java 8). It’s because the index variable is error-prone, as we may alter it incidentally in the loop’s body, or we may start the index from 1 instead of 0.

9) Replace try–catch-finally with try-with-resources.

10) No vacant catch blocks
An empty catch block will make the program fail in silence and will not give any information about what went wrong.

11) Avoid the null pointer exception as possible.
Try to avoid the null pointer exceptions that may occur in runtime by:

  • Return Empty Collections instead of returning Null elements
  • Use Optional as you can
  • requireNonNull methods of java.utils.Objects
  • NotNullNotEmptyNotBlank Annotations
  • Objects::nonNull in Streams
  • requireNonNullmethods in java.util.Objects

12) Add only needed getters, setters and constructors and avoid Lombok (YAGNI).
Add only the code that you need.
Lombok is a great tool that may help you in generating some boilerplate code but it has some drawbacks like IDE incompatibility, usage of non-public API and it is closely tied to the Java compiler. Besides that since Java 14, records can replace some of its utilities.

13) Always implement hashCode when you implement equals.
Always remember to override hashCode if you override equals so as not to "break the contract".
As per the API, the result returned from the hashCode() method for two objects must be the same if their equals methods show that they are equivalent. The converse is not necessarily true.
Use the same properties in both equals() and hashCode() method implementations so that their contract doesn’t violate when any properties are updated.

14) Favour records (since java14) for immutable data

15) For constants, use an enum or final class instead of an interface.
Constants defined in an interface are also accessible using the name of the implementing class and its sub-classes, which can be confusing. Any changes to the value of the constant can potentially affect all the classes that use the interface.
An interface is supposed to define a contract, and constant values are considered implementation details. By defining constants in an interface, we are exposing implementation details, which is not ideal.

To define constants, we can use a final class and define a private constructor to hide the public one, or an enum if the constants have a strong connection. You can find more details on this topic here.

16) Declare an explicit serial version uid in every serialization class.
If a serializable class doesn’t declare a serialVersionUID, the JVM will generate one automatically at run-time. However, it’s highly recommended that each class declares its serialVersionUID, as the generated one is compiler dependent and thus may result in unexpected InvalidClassExceptions.

public class Person implements Serializable {
private static final long serialVersionUID = 123123L; // version UID for serialization

private String name;
private int age;
...
}

17) Add an empty line before the annotation

18) The static fields should be placed at the top of the class.

19) For date type handling java.handling.java.localDateTimeis recommended since Java 8.

20) Try to use the suitable type for your variables.
If two or more types satisfy your functional needs, use the type that takes less space in memory if that does not affect maintainability and readability.

Exploring the Power of Generative AI Services: Unlocking Limitless Creativity

Introduction In recent years, we have witnessed remarkable advancements in the field of artificial intelligence (AI). One of the most intrig...