Effective Java (2nd Edition)

Author: Joshua Bloch
4.4
All Stack Overflow 213
This Year Stack Overflow 16
This Month Stack Overflow 1

Effective Java (2nd Edition)

4.4

Review Date:

Comments

by anonymous   2018-03-19

I would say both NumberFormatException and MyBusinessException are useful but in different cases.

They usually appear at different levels of class hierarchy: for example NumberFormatException is a lower-level exception and you might not want to expose it at a higher level (e.g. user interface) if the user of it has no power to recover from it. In this case it is more elegant to just throw MyBusinessException and display an informative message that explains for example that something in a previous step was badly supplied or some internal processing error occurred and he/she needs to restart the process.

On the other hand, if your function is used at an intermediate-level (e.g. API) and the developer has the means to recover from the exceptional behavior, NumberFormatException is more useful, as it can be dealt with programmatically and the flow of the application might continue with minimal interruption (e.g. supply a default valid number). Alternatively, this can indicate a flaw/bug in the code that should be fixed.

For details about how to follow best practice in using exceptions, read Item 61 - Throw exceptions appropriate to the abstraction from Effective Java by Joshua Bloch.

by anonymous   2018-03-19

The book Effective Java gives two more reasons for "memory leaks":

  • Once you put object reference in Cache and forget that it's there. The reference remains in cache long before becoming irrelevant. Solution is to represent cache as a WeakHashMap
  • in an API where clients register callbacks and don't re-register them explicitly. Solution is to store only weak references to them.
by anonymous   2017-08-20

The best approach is Long.valueOf(str) as it relies on Long.valueOf(long) which uses an internal cache making it more efficient since it will reuse if needed the cached instances of Long going from -128 to 127 included.

Returns a Long instance representing the specified long value. If a new Long instance is not required, this method should generally be used in preference to the constructor Long(long), as this method is likely to yield significantly better space and time performance by caching frequently requested values. Note that unlike the corresponding method in the Integer class, this method is not required to cache values within a particular range.

Generally speaking, it is a good practice to use the static factory method valueOf(str) of a wrapper class like Integer, Boolean, Long, ... since most of them reuse instances whenever it is possible making them potentially more efficient in term of memory footprint than the corresponding parse methods or constructors.


Excerpt from Effective Java Item 1 written by Joshua Bloch:

You can often avoid creating unnecessary objects by using static factory methods (Item 1) in preference to constructors on immutable classes that provide both. For example, the static factory method Boolean.valueOf(String) is almost always preferable to the constructor Boolean(String). The constructor creates a new object each time it’s called, while the static factory method is never required to do so and won’t in practice.

by anonymous   2017-08-20

You should probably use String.hashCode().

If you really want to implement hashCode yourself:

Do not be tempted to exclude significant parts of an object from the hash code computation to improve performance -- Joshua Bloch, Effective Java

Using only the first five characters is a bad idea. Think about hierarchical names, such as URLs: they will all have the same hash code (because they all start with "http://", which means that they are stored under the same bucket in a hash map, exhibiting terrible performance.

Here's a war story paraphrased on the String hashCode from "Effective Java":

The String hash function implemented in all releases prior to 1.2 examined at most sixteen characters, evenly spaced throughout the string, starting with the first character. For large collections of hierarchical names, such as URLs, this hash function displayed terrible behavior.

by anonymous   2017-08-20

It's extremely bad practice to let equals() or hashCode() throw exceptions (I'd encourage you to read Effective Java for the details).

Also, your methods are unnecessarily complex. Ever since Java 7, this is pretty much the canonical way of writing these methods:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }else if (o instanceof MyClass) {
        // some will argue that the line above should have a
        // .getClass() check instead of an instanceof check.
        // those people also need to read Effective Java :-)
        MyClass that = (MyClass) o;
        return Objects.equals(this.classA, that.classA)
            && Objects.equals(this.classB, that.classB)
    } else {
        return false;
    } 
}

@Override
public int hashCode() {
    return Objects.hash(classA, classB);
}
by anonymous   2017-08-20

1. What you should be more concerned with here, is not efficiency, but scope. Generally, you should strive to keep your variables as locally scoped as possible. This means, if you only need x within the loop, you should define it within the loop.

You get a number of benefits with keeping your variables as locally scoped as possible:

  • Your code will be much more readable to someone else
  • You won't accidentally assign to, or use the value of a variable you defined further up in your code that is still in scope, thus minimizing errors in your program
  • Most importantly, the garbage collector will free up any memory used by the variable as soon as it goes out of scope, keeping your program's performance high, and memory usage low.

You can read up more on variable scope and best practices from Josh Bloch's excellent book, "Effective Java" (scope is discussed in items 13 and 45). You might also want to read item 55, which discusses why it is important to optimize judiciously.

2. For the second part of your question, see The Skeet's answer here.

Here's an example:

public static void main(String[] args) {
    for(int i=0; i<getSize(); i++) {
        System.out.println("i: " + i);
    }
}

private static int getSize() {
    int size = new Random().nextInt(10);
    System.out.println("size: " + size);
    return size;
}

This outputs:

size: 2
i: 0
size: 4
i: 1
size: 4
i: 2
size: 8
i: 3
size: 0

Notice how getSize() is called for every iteration of the loop. In your example, calling .length won't make a huge difference, as the JIT runtime will know how to optimize this call. But imagine getSize() was a more complex operation, like counting the number of rows in a database table. Your code will be super slow as every iteration of the loop will call getSize(), resulting in a database roundtrip.

This is when you would be better off evaluating the value before hand. You can do this and still retain minimal scope for size, like this:

public static void main(String[] args) {
    for(int size = getSize(), i=0; i<size; i++) {
        System.out.println("i: " + i);
    }
}


private static int getSize() {
    int size = new Random().nextInt(10);
    System.out.println("size: " + size);
    return size;
}

size: 5
i: 0
i: 1
i: 2
i: 3
i: 4

Notice how getSize() is only called once, and also, the size variable is only available inside the loop and goes out of scope as soon as the loop completes.

by anonymous   2017-08-20

In recent years, inheritance is often treated like code-smell, because it can lead to different problems: https://dzone.com/articles/is-inheritance-dead

If we talk in pure performance term, an empty array takes about 8 bytes in RAM (4 bytes store length and 4 bytes a reference, but it is a little platform-dependent: How much space array occupies). So, even if you have a thousand of such objects, one array field will take approximately 1_000 * 8 bytes ~ 8 KBytes in RAM.

As you probably know, nowadays phones usually contain > 1 GByte of RAM. However, don't forget that your app usually can take from 60 to 192 MBytes of RAM (Detect application heap size in Android).

In any case, it is more than enough not to count every little field that you are adding to your class.

However, going back to my first statement, I suggest you to think about solving the problem using composition instead of inheritance, as it is suggested in Effective Java

Update
About performance, I would suggest you to read this topic: The performance impact of using instanceof in Java Are you sure that you need such type of premature optimization? Or is it more a theoretical question than practical?

by anonymous   2017-08-20

If you throw exceptions that are too low-level catch them few calls above, and pack as more general and meaningful exception with user friendly message what went wrong, and throw them once again to highest possible level, where you stop your app and view them somehow (e.g. on label) to user.

from Effective Java (item 61):

It is disconcerting when a method throws an exception that has no apparent connection to the task that it performs. This often happens when a method propagates an exception thrown by a lower-level abstraction. Not only is this disconcerting, but it pollutes the API of the higher layer with implementation details. If the implementation of the higher layer changes in a subsequent release, the exceptions that it throws will change too, potentially breaking existing client programs.

To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction. This idiom is known as exception translation:

// Exception Translation
try {
   // Use lower-level abstraction to do our bidding
   ...
} catch(LowerLevelException e) {
   throw new HigherLevelException(...);
}

While exception translation is superior to mindless propagation of exceptions from lower layers, it should not be overused. Where possible, the best way to deal with exceptions from lower layers is to avoid them, by ensuring that lower-level methods succeed. Sometimes you can do this by checking the validity of the higher-level method’s parameters before passing them on to lower layers.

If it is impossible to prevent exceptions from lower layers, the next best thing is to have the higher layer silently work around these exceptions, insulating the caller of the higher-level method from lower-level problems. Under these circumstances, it may be appropriate to log the exception using some appropriate logging facility such as java.util.logging. This allows an administrator to investigate the problem, while insulating the client code and the end user from it.

In summary, if it isn’t feasible to prevent or to handle exceptions from lower layers, use exception translation, unless the lower-level method happens to guarantee that all of its exceptions are appropriate to the higher level. Chaining provides the best of both worlds: it allows you to throw an appropriate higher-level exception, while capturing the underlying cause for failure analysis (Item 63).

by anonymous   2017-08-20

The use of try/catch blocks in normal program flow incurs a performance hit. It's better to use the if/then statements in the first example.

https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why

This is mentioned in Effective Java. Exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow.

by anonymous   2017-08-20

As far as I can tell there is nothing special here, is just classical constructor chaining and polymorphism applied to virtual method invocations.

When you instantiate your anonymous class, it will automatically invoke its default constructor (which is automatically given by the compiler), before its default constructor succeeds it must first invoke its parent class default constructor, which in turn will invoke the init() method, which, since it has been overridden by your anonymous class, polymorphically, ends up calling the init method in the child class, which initializes the model to your SubModel instance.

Joshua Bloch has a few interesting arguments against this pattern in his famous book Effective Java, in the section "Item 17: Design and document for inheritance or else prohibit" he wrote:

“There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected. To make this concrete, here's a class that violates this rule:”

He then proceeds to give an example which you would do well to study:

“Here's a subclass that overrides the overrideMe, method which is erroneously invoked by Super's sole constructor:”

public class Super {
    // Broken - constructor invokes an overridable method
    public Super() {
        overrideMe();
    }

    public void overrideMe() {
    }
}

public final class Sub extends Super {
    private final Date date; // Blank final, set by constructor

    Sub() {
        date = new Date();
    }

    // Overriding method invoked by superclass constructor
    @Override public void overrideMe() {
        System.out.println(date);
    }

    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.overrideMe();
    }
}

“You might expect this program to print out the date twice, but it prints out null the first time, because the overrideMe method is invoked by the Super constructor before the Sub constructor has a chance to initialize the date field. Note that this program observes a final field in two different states! Note also that if overrideMe had invoked any method on date, the invocation would have thrown a NullPointerException when the Super constructor invoked overrideMe. The only reason this program doesn't throw a NullPointerException as it stands is that the println method has special provisions for dealing with a null argument.”

So, as you can see, and as Joshua Bloch explained so well, the risks lurk in the shadows: in the possibilities of what you can do in the overridden method, where you have license to touch instance variables that the constructor chain has not yet had a chance to initialize. The point is that you should not be allowed to touch the object state until it has been fully initialized by the constructor chain.

You might say that in your particular case that does not happen, since you are not illegally altering state and your overridden method is protected, not public, but the problem is that any person touching this code needs a very clear understanding of all these things happening under the hood, happening in places other than your current code. During maintenance it is easy to make a serious mistake, particularly when you or some other developer, comes back here to make changes, possibly months or even years after this was originally defined, and having lost context of all these dangers somebody introduces a bug that will be really hard to find and fix.