Lecture18 - Good vs. Bad Practices Part 1 - CreatingObjects
Lecture18 - Good vs. Bad Practices Part 1 - CreatingObjects
Objects
Note: In the following slides, the item numbers correspond to their numbers in the
book (we will not cover all the items which is why the numbers are not consecutive)
➢ Approach2:
// Singleton with public static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public int data;
}
All calls to Elvis.getInstance() return the same object reference, and no other Elvis instance will ever be created
Approach1 is simpler, however Approach2 gives you the flexibility to change your mind about whether the class is a
singleton without changing its API
Item 2: Singletons (cont)
Using reflection, a user can violate the singleton property and create 2 instances of the object:
To create an instance, you use the constructor with the shortest parameter list containing all the parameters you want to set:
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27); // you care about all 6 params except ‘fat’
Item 3: Use a builder … (cont)
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27); // don’t care about the value of fat
What if we have more parameters and we don’t care about many parameters?
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 0, 0, …, 8, 0…, 27);
This approach is bad for readability and writability, a source of runtime bugs.
+1: This client code is easy to write and, more importantly, easy to read.
-1: The Builder pattern is more verbose than the original approach, so it should be used only if
there are enough parameters to make it worthwhile, say 4 or more.
Item 6: Avoid creating unnecessary objects
➢An object can always be reused if it is immutable
➢So why not reuse it?
String s = new String(“Hello"); // DON'T DO THIS!
This statement unnecessarily creates a new String instance each time it is executed
String s = “Hello";
This version reuses the same String instance, each time it is executed
Furthermore, it is guaranteed that the object will be reused by any other code running in the
same virtual machine that happens to contain the same string literal (String keeps a pool of
used string literals)
Item 6: Avoid creating unnecessary objects (cont)
➢ Autoboxing is a source of creating unnecessary objects
➢ Method that calculates the sum of all the positive int values:
private static long sum() {// Very slow! Can you spot the object creation?
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
The variable sum is declared as a Long instead of a long, which means that the program constructs about 231
unnecessary Long instances (roughly one for each time the long i is added to the Long sum). Changing the
declaration of sum from Long to long will tremendously reduce the runtime.
However:
➢ Creating additional objects to enhance the clarity, simplicity, or power of a program is generally a good thing.
➢ Avoiding object creation by maintaining your own object pool is sometimes risky (especially if they are
mutable).
➢ Creating object pools on its own could be heavyweight
Item 7: Eliminate obsolete object references
Garbage collection gives you the false impression that you don’t have to think about memory
➢Another common source of memory leaks is caches. Once you put an object reference into a
cache, it’s easy to forget that it’s there and leave it in the cache long after it becomes irrelevant
➢Consider creating your cache as a WeakHashMap. Entries will be removed automatically after
they become obsolete.
WeakHashMap
A WeakHashMap cooperates with the garbage collector to remove key/value pairs
when the only reference to the key is the one from the hash table entry:
Output:
GC
GC
Finalized object2
// Created HashMap and WeakHashMap objects
Map<String, String> hashmapObject = new HashMap<>();
Map<String, String> weakhashmapObject = new WeakHashMap<>();
// Calling Garbage Collection (Note that gc is a parallel process and it is not guaranteed (but likely)
//that it will execute directly after calling it
System.gc();
static String firstLineOfFile(String path) throws IOException { // try-with-resources – closing one resource
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
static void copy(String src, String dst) throws IOException { // try-with-resources – closing multiple resources
try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0) out.write(buf, 0, n);
}
}
[Optional Reading] Item 9: Prefer try-with-resources to try-finally (cont)
Assume that exceptions are thrown by both the readLine call and the close call, the
latter exception is suppressed in favor of the former
static String firstLineOfFile(String path) throws IOException { // try-finally- for closing a resource
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
}
finally {
br.close();
}
}