Brief Notes From Effective Java Book
Omar Ismail
Senior Software Engineer @ Digitinary | Java 8 Certified? | Spring & Spring Boot?????? | AWS? | Microservices ?? | RESTFul Apis & Integrations ?? FinTech ?? | Open Banking ?? | Digital Payments and Transformation??
This blog post consists of brief notes from Effective Java(3rd edition) by Joshua Bloch and my thoughts. Especially to improve the post’s readability, I chose some items that I want to emphasize. This book includes very valuable experience in java and software engineering. You should add it to your reading list. Let’s start!
Eliminate obsolete object references
As is known java has an automatic memory management system. This system protects developers from the complexity of explicit memory management. But there is no free lunch. Some code habits can block GC, thus memory leaks and other memory problems can happen.
Let’s think we design a stack that uses an array in the background.
private int size = 0;
public Object pop() {
return elements[ — size];
}
If implements a pop method as above, GC can not deallocate unused parts of the array. And the devil shows itself slowly, “memory leak”.
public Object pop() {
Object result = elements[ — size];
elements[size] = null;
return result;
}
If a class manages its memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object references contained in the element should be nulled out. But nulling out object references should be the exception rather than the norm.
This occurs naturally if you define each variable in the narrowest possible scope.
Try-With-Resources Better Than Try-Finally
The libraries may include resources that must be closed manually by invoking a close method. File operations, DB connections, etc. Sometimes resource closing is missed by clients and it can cause bad consequences.
Okay, we decided to close resources. But why do we not use an old good friend “Try-Finally”?
Prone to error syntax
If we use inner try-finally blocks, the readability of the code decreases dramatically.
Exception obligating
The code in both the “try” block and the “finally” block is capable of throwing exceptions. In this scenario, the first exception was obligated by the second(when invoking the close method). In this manner, the root cause of the problem can not be viewed in the exception stack trace.
Try-Finally
static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
……
} finally {
out.close();
}
} finally {
in.close();
}
}
Try-With-Resources
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
...
}
}
Less prone to error, clean syntax, what else does a developer want?
Minimize The Accessibility Of Classes And Members
“The single most important factor that distinguishes a well-designed component from a poorly designed one is the degree to which the component hides its internal data and other implementation details from other components”
Encapsulation is one of the most important pillars for an object-oriented paradigm.
Private fields and public accessors are widely used “best practices”. In the level of class and method same tendency. If you do have not any acceptable cause for choice to access modifiers, the order must be?private, package-private, protected, public.
Minimize Mutability
James Gosling(the creator of Java), asked him in an interview when should one use immutables, he answered:
“I would use an immutable whenever I can.”
Main advantages of using immutability;
And on the other hand, this is the way goes Java* and other new programming languages*.
领英推荐
Don’t Use Raw Types
Generics were added to the Java programming language in 2004 with version 5. But because of requirements known as “migration compatibility” java still supports raw types. First of all, make a quick look at raw types and other alternatives.
List<String> strList = … → list of string
List strList = … → raw
The first instance provides a strong type-safe on the compiler phase. Do not make any surprise on runtime like “Hey this reference is not a string, I have little sweat ClassCastException for you”.
But the second one creates an error-prone environment. You can add any kind of object to this list without a compiler error(with compiler warning). Exactly this situation delays error to runtime.
On the other hand, if I want to create a method that works without caring about object type, can I use raw type??Unbound wildcard?was more proper/safe.
int numElementsInCommon(Set s1, Set s2) → raw type
int numElementsInCommon(Set<?> s1, Set<?> s2) → unbound wildcard
Briefly raw types are provided only for compatibility and interoperability with legacy code that predates the introduction of generics. Don’t use them.
Return Empty Collections Or Arrays, Not Nulls
Pretty simple but effective. If not used, every call must write a terrible if statement. Otherwise, encountering the null pointer exception will be cheesy.
Java presents some immutable empty collections;?Collections.emptyList(), Collections.emptySet(), Collections.emptyMap().?As?immutable objects may be shared freely, using these collections can be more convenient.
public List<Item> getItems() {
return itemList.isEmpty() ? Collections.emptyList()
: new ArrayList<>(itemList);
}
Design Method Signatures Carefully
Name
Choose method names carefully. Names should always obey the standard naming conventions and should be understandable and consistent. Especially using different names for the same operation is a bad habit. For example;
List<User> getAllUsers() {
// get all user from the database (with hibernate or any kind of ORM)
}
List<Store> loadAllStores() {
// get all store from the database (with hibernate or any kind of ORM)
}
Parameter List
Although most modern IDE’s helps to understand method signature long method list always error-prone. Gather them around a concept. For example;
addMarker(String title, String colorCode, String url, long latitude, long longitude)
addMarker(Marker marker)
Another alternative technique could be to implement the?builder pattern.
Don’t Reinvent the Wheel
Occasionally a library can fail your meets. But most of the time there is at least one library that presents the functionality you require. This library can be in java sub-packages or a third party(actively maintained, secure, reputable, etc.) In this context to mention some advantages of the using library can be beneficial;
Avoid Float And Double If Exact Answers Are Required
The float and double types are designed primarily for scientific and engineering calculations. They perform binary floating-point arithmetic* which is designed for approximations quickly over a broad range of magnitudes. They do not provide exact results and should not be used where exact results are required.
BigDecimal x = new BigDecimal(“1.89”);
BigDecimal y = new BigDecimal(“1.03”);
System.out.println(x.subtract(y));
System.out.println(1.89–1.03);
0.86
0.8599999999999999
If you require an exact result(for example monetary calculations), should use BigDecimal or other specific implementation.
*IEEE 754
Refer To Objects By Their Interfaces
Using interfaces as types make your program will be much more flexible. If you decide the change implementation for any reason(for example performance). All you have to do change the class name without compile error.
Map<String,String> map = new HashTable<>();
— — after a while, when I don’t need thread-safety
Map<String,String> map = new HashMap<>();
If there is no suitable interface, you can use the least specific class in the class hierarchy that provides the required functionality.
Favor The Use Of Standard Exceptions
“An attribute that distinguishes expert programmers from less experienced ones is that experts strive for and usually achieve a high degree of code reuse.”
The Java libraries provide a set of exceptions that cover most of the exception-throwing needs of most APIs. Benefits of reusing exception;
IllegalArgumentException, IllegalStateException, NullPointerException, IndexOutOfBoundsException, UnsupportedOperationException, ConcurrentModificationException?some of those.
If an exception fits your needs, use it. On the other hand, feel free to subclass a standard exception if you want to add more detail.
Thanks to:?sahibinden-technology
Quality Engineering Leader | Result focused and hands-on leader who can deliver high Quality products with speed with style. Meetup, conference Speaker
2 年Try-With-Resources is something still not used by many java uses. Excellent post Omar Ismail