Java coding standards P. 6
Access modifiers
In the sixth instalment of my series on Java coding standards, we'll delve into access modifiers—an essential feature that controls the visibility of classes, methods, and variables. Access modifiers play a pivotal role in promoting encapsulation, safeguarding the internal state of objects, and ensuring robust, maintainable code.
Understanding access modifiers in Java
Java provides four access modifiers: private, default (no modifier), protected, and public. Each modifier offers a different level of access control.
Private
The private modifier is the most restrictive, limiting access to the class itself. Private members cannot be accessed or modified from outside their own class.
public class User {
private String name; // Accessible only within the User class
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
In this example, the name variable is private, ensuring it can only be accessed and modified through the public getName() and setName() methods. This encapsulation protects the name variable from unintended external changes.
Default (package-private)
The default modifier, also known as package-private, is used when no explicit access modifier is specified. Members with default access are accessible within the same package but not from outside it.
class Common {
int count; // Accessible within the same package
}
Here, the count variable is accessible to other classes within the same package, promoting modular design while restricting external access.
Protected
The protected modifier allows access within the same package and by subclasses, even if they are in different packages. It strikes a balance between encapsulation and extensibility.
public class Parent {
protected void display() {
System.out.println("Protected method");
}
}
public class Child extends Parent {
public void show() {
display(); // Accessible in subclass
}
}
In this example, the display() method is protected, allowing the Child class to access and extend its functionality. This facilitates inheritance while maintaining a level of protection.
Public
The public modifier is the least restrictive, allowing access from any other class in any package. Public members are accessible globally.
public class Printer {
public void printMessage(String message) {
System.out.println(message);
}
}
The printMessage(String message) method is public, making it accessible to all classes. Use public access for methods and variables that are intended for widespread use.
Best practices for applying access modifiers
While access modifiers are powerful tools, using them wisely is essential. Here are some best practices to help you apply access modifiers effectively:
1. Minimise accessibility
Use the most restrictive access level that makes sense for a particular member. Start with private and increase accessibility only when necessary.
public class Account {
private double balance;
public double getBalance() {
return balance;
}
}
By keeping balance private, you prevent external classes from modifying it directly, thus maintaining control over how the balance changes.
2. Encapsulate sensitive data
Protect sensitive data by using private access and providing public getter and setter methods when appropriate.
public class Employee {
private String nationalInsuranceNumber;
public String getNationalInsuranceNumber() {
return nationalInsuranceNumber;
}
// No setter provided to prevent changes after initial assignment
}
This approach safeguards critical information while allowing controlled read access.
3. Design for extensibility
Use protected access for members intended to be used or overridden by subclasses.
public class Vehicle {
protected void startEngine() {
// Engine starting logic
}
}
public class Car extends Vehicle {
@Override
protected void startEngine() {
// Custom engine starting logic for Car
}
}
This allows subclasses to customise or extend the functionality while keeping it hidden from the rest of the application.
4. Avoid public fields
Exposing public fields can lead to unintended modifications and break encapsulation. Instead, use private fields with public getter and setter methods if necessary.
public class Config {
private int maxConnections;
public int getMaxConnections() {
return maxConnections;
}
public void setMaxConnections(int maxConnections) {
if (maxConnections > 0) {
this.maxConnections = maxConnections;
}
}
}
This ensures that maxConnections is only set to valid values, maintaining the integrity of the configuration.
5. Be cautious with overusing access
While it's important to restrict access, overusing access modifiers can lead to overly complex code that's difficult to maintain. Strive for a balance between protection and usability.
Conclusion
Access modifiers are a cornerstone of writing clean, maintainable, and secure Java code. By thoughtfully applying private, default, protected, and public access levels, you enforce encapsulation, protect sensitive data, and promote a modular design that stands the test of time.
In the next part of this series, we'll explore the use of the final keyword in Java. We'll discuss how it enforces immutability, aids in creating constant values, and prevents unwanted modifications. Stay tuned!
Feel free to share your thoughts or ask questions in the comments below. Engaging with these concepts is a great way to deepen your understanding and become a more proficient Java developer.
Follow me on X for more insights and updates!