Primitives are int, double, boolean, etc. Boxed primitives are the Object version of primitives, i.e. Integer, Double, Boolean. As a general rule, prefer using primitives over boxed primitives.
Gotchas
1.) Do not use the == operator to compare boxed primitives.
Integer a = new Integer(7);
Integer z = new Integer(7);
System.out.println(a == z);
Prints out false because == is doing an identity comparison on the Integer reference memory location. Since object a and object z are two different objects in different areas of memory, the (a == z) test is false.
To do an equality test on boxed primitives, use the equals method.
a.equals(z);
Or unbox the boxed primitive and then do the == test
int x = a;
int y = z;
System.out.println(x == y);
2.) Do not unbox in a loop
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; ++i) {
sum += i;
}
At code sum += i , the boxed primitive sum will be auto-unboxed to perform addition then a Long object created to assign to sum. This caused time and space performance issues.
Fix the above code by changing sum to a primitive long.
3.) Boxed primitives can throw NullPointerException
static Integer i;
public static void main(String... args) {
System.out.println(i == 42);
}
The code i == 42 will throw a NullPointerException because when i gets auto-unboxed to do a comparison with primitive int 42, the variable i is null;
SyntaxHighlighter JS
Showing posts with label effective_java. Show all posts
Showing posts with label effective_java. Show all posts
2013-01-21
2013-01-20
Java Memory Leak: Obsolete reference
In program
public class Stack {
private Object[] elements;
private int size = 0;
private static final int INIT_SIZE = 16;
public Stack() {
elements = new Object[INIT_SIZE];
}
public void push() {
checkSize();
elements[size++] = e;
}
public Object pop() {
if (size == 0) { throws EmptyStackException(); }
Object result = elements[--size];
return result;
}
private void checkSize() {
if (elements.length = size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
The code line
Object result = elements[--size];
is a Java memory leak because even though the size decrements, the obsolete reference to the Object at element[size] still exists in memory.
The fix is to null of the unneeded reference at elements
public Object pop() {
if (size == 0) { throws EmptyStackException(); }
Object result = elements[--size];
elements[size] = null;
return result;
}
Arrays and collections are places where memory leak obsolete references occur often.
public class Stack {
private Object[] elements;
private int size = 0;
private static final int INIT_SIZE = 16;
public Stack() {
elements = new Object[INIT_SIZE];
}
public void push() {
checkSize();
elements[size++] = e;
}
public Object pop() {
if (size == 0) { throws EmptyStackException(); }
Object result = elements[--size];
return result;
}
private void checkSize() {
if (elements.length = size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
The code line
Object result = elements[--size];
is a Java memory leak because even though the size decrements, the obsolete reference to the Object at element[size] still exists in memory.
The fix is to null of the unneeded reference at elements
public Object pop() {
if (size == 0) { throws EmptyStackException(); }
Object result = elements[--size];
elements[size] = null;
return result;
}
Arrays and collections are places where memory leak obsolete references occur often.
2013-01-19
Notes on Nested Classes
Use if class is only used with/by parent class.
Four kinds of nested classes, in order of preference.
Four kinds of nested classes, in order of preference.
- static member classes
* Access to all enclosing class static members, even private.
Can acces other static peer member class fields.
* Same visibility rule as regular static members.
* Can be an interface
* If member class does not require access to enclosing instance, always make member class static. Save time and space on enclosing class construction.
* Example, Map.Entry
* Usage syntax: new Classname.StaticMemberClass() - nonstatic member classes
* Access to all enclosing class static and instance members, even private.
* Same visibility rule as regular instance members.
* Cannot be interface
* No static fields or methods, except for static final.
* Can obtain explicit access to enclosing class instance members via
Classname.this.instanceMember
* Can obtain explicit access to the super class of the enclosing class via
Classname.super.instanceMember
* Usage syntax: classname.new NonStaticMemberClass() - anonymous classes
* Normally used as function objects
* Good if class is short, used once, and right away.
* No constructor but can use instance initializer
* No static fields or methods, except for static final - local classes
* Classes defined inside methods.
* Can only use final fields of enclosing method.
* Access to all enclosing class static and instance members, even private.
* No static fields or methods, except for static final.
2013-01-18
Strategy Pattern: Example
The Arrays.sort method and Comparator interface is a real world example of the Strategy pattern.
The Strategy pattern is composed of an interface defining exactly one method for the functional behavior. The Comparator is an interface defining compare as the functional method.
Concrete implementations (function objects) can be defined for the Strategy interface, e.g. AscendingSortStrategy, DescendingSortStrategy.
class AscendingSortStrategy implements Comparator<Integer> {
private AscendingSortStrategy() { }
public static final AscendingSortStrategy INSTANCE =
new AscendingSortStrategy();
@Override
public int compare(Integer i1, Integer i2) {
final int int1 = i1;
final int int2 = i2
return int1 - int2;
}
}
class DescendingSortStrategy implements Comparator<Integer> {
private DescendingSortStrategy() { }
public static final DescendingSortStrategy INSTANCE =
new DescendingSortStrategy();
@Override
public int compare(Integer i1, Integer i2) {
final int int1 = i1;
final int int2 = i2
return int2 - int1;
}
}
To use, pass the concrete strategy to a method that can accept it.
Integer[] integers = new Integer[] {
new Integer(5), new Integer(1), new Integer(7) ,
new Integer(2)
};
Arrays.sort(integers, AscendingSortStrategy.INSTANCE);
The Strategy pattern is composed of an interface defining exactly one method for the functional behavior. The Comparator is an interface defining compare as the functional method.
Concrete implementations (function objects) can be defined for the Strategy interface, e.g. AscendingSortStrategy, DescendingSortStrategy.
class AscendingSortStrategy implements Comparator<Integer> {
private AscendingSortStrategy() { }
public static final AscendingSortStrategy INSTANCE =
new AscendingSortStrategy();
@Override
public int compare(Integer i1, Integer i2) {
final int int1 = i1;
final int int2 = i2
return int1 - int2;
}
}
class DescendingSortStrategy implements Comparator<Integer> {
private DescendingSortStrategy() { }
public static final DescendingSortStrategy INSTANCE =
new DescendingSortStrategy();
@Override
public int compare(Integer i1, Integer i2) {
final int int1 = i1;
final int int2 = i2
return int2 - int1;
}
}
To use, pass the concrete strategy to a method that can accept it.
Integer[] integers = new Integer[] {
new Integer(5), new Integer(1), new Integer(7) ,
new Integer(2)
};
Arrays.sort(integers, AscendingSortStrategy.INSTANCE);
Arrays.sort(integers, DescendingSortStrategy.INSTANCE);
Object Oriented Principle:
Use interfaces instead of concrete implementation classes.
Object Oriented Principle:
Use interfaces instead of concrete implementation classes.
Having Arrays.sort accept the Comparator interface allows the user flexibility to change the implementation details of the sort by creating new classes while keeping everything else the same.
2013-01-17
Builder Pattern: Too many constructor parameters
Problem:
A class has too many parameters in the constructor. For example,
new VitalSign(98, 120, 80, 42, 23);
Issues:
Use the Builder pattern.
Assume temperature is the only required vital sign.
public class VitalSign {
private final int temperature;
private final int systolic;
private final int diastolic;
private final int pulse;
private final int respiratoryRate;
private VitalSign(Builder b) {
this.temperature = b.temperature;
this.systolic = b.systolic;
this.diastolic = b.diastolic;
this.pulse = b.pulse;
this.respiratoryRate = b.respiratoryRate;
// Put any state validation logic here and throw
// IllegalStateException if violated
}
public static class Builder {
// Required
private final int temperature;
// Optional with defaults
private int systolic = -1;
private int diastolic = -1;
private int pulse = -1;
private int respiratoryRate = -1;
public Builder(final int temp) {
this.temperature = temp;
}
public Builder systolic(final int val) {
this.systolic = val;
return this;
}
public Builder diastolic(final int val) {
this.diastolic = val;
return this;
}
public Builder pulse(final int val) {
this.pulse = val;
return this;
}
To use,
new VitalSign.Builder(98).pulse(42).
systolic(120).diastolic(80).build();
Advantages:
A class has too many parameters in the constructor. For example,
new VitalSign(98, 120, 80, 42, 23);
Issues:
- Difficult to remember what each parameter represents. Problem exacerbated with increasing parameters. Putting wrong value for parameter is a common cause of bugs.
- No way to define optional parameters.
- Adding new parameters mean creating another constructor or adding another parameter to an existing constructor.
Use the Builder pattern.
Assume temperature is the only required vital sign.
public class VitalSign {
private final int temperature;
private final int systolic;
private final int diastolic;
private final int pulse;
private final int respiratoryRate;
private VitalSign(Builder b) {
this.temperature = b.temperature;
this.systolic = b.systolic;
this.diastolic = b.diastolic;
this.pulse = b.pulse;
this.respiratoryRate = b.respiratoryRate;
// Put any state validation logic here and throw
// IllegalStateException if violated
}
// Required
private final int temperature;
// Optional with defaults
private int systolic = -1;
private int diastolic = -1;
private int pulse = -1;
private int respiratoryRate = -1;
public Builder(final int temp) {
this.temperature = temp;
}
public Builder systolic(final int val) {
this.systolic = val;
return this;
}
public Builder diastolic(final int val) {
this.diastolic = val;
return this;
}
public Builder pulse(final int val) {
this.pulse = val;
return this;
}
public Builder respiratoryRate(final int val) {
this.respiratoryRate = val;
return this;
}
public VitalSign build() {
return new VitalSign(this);
}
}
}
this.respiratoryRate = val;
return this;
}
public VitalSign build() {
return new VitalSign(this);
}
}
}
new VitalSign.Builder(98).pulse(42).
systolic(120).diastolic(80).build();
Advantages:
- Construction code easy to understand.
- VitalSign class is immutable. No setters.
- VitalSign.Builder.build method can throw an IllegalStateException if state validation fails. For example, if there is a systolic value but not a diastolic or if temperature is greater than 130.
2013-01-16
Singleton Pattern: Best Java implementation
For Java 5 and beyond, the best singleton implementation is using enum.
public enum Singleton {
INSTANCE;
public void doStuff() { ... }
}
To use the singleton
Singleton.INSTANCE.doStuff();
public enum Singleton {
INSTANCE;
public void doStuff() { ... }
}
To use the singleton
Singleton.INSTANCE.doStuff();
Subscribe to:
Posts (Atom)