Effective Java: Programming Language Guide (Java Series)

Author: Joshua Bloch
4.5
All Stack Overflow 15

Effective Java: Programming Language Guide (Java Series)

4.5

Review Date:

Comments

by anonymous   2017-08-20

No, your Animal class is not immutable, because it allows subclassing.

Why not?

See this example subclass:

public class ExceptionalAnimal extends Animal {

    public ExceptionalAnimal() {
        super(null);
    }


    @Override
    public String getName() {
        throw new AssertionError("Oops.. where did that come from?");
    }
}

Why does this matter?

Immutability is commonly used to guarantee:

  1. That the state of an object doesn't change after construction
  2. That objects are thread-safe
  3. That objects behave in a certain way

If a class allows subclassing, none of these guarantees can be relied upon. If you have a method accepting an Animal as a parameter, anyone can pass in a subclass that breaks these guarantees.

Fix: No public or protected constructors

One often used technique is to not have any public or protected constructors. This prevents subclassing from outside your package and inside your package you could still have your own internal subclasses. Which you cannot if the class is final.

The immutable collection classes from Google's Guava library use this technique. From the Javadoc:

Although this class is not final, it cannot be subclassed as it has no public or protected constructors. Thus, instances of this type are guaranteed to be immutable.

A client can create ImmutableLists with the static of() and copyOf methods.

See also Effective Java, Item 4: Enforcing noninstantiability with a private constructor.

Be aware that guaranteeing immutability by having no public or protected constructors is easier to break than making the class final. For example Mockito will let you mock these cases by default:

ImmutableList notSoImmutable = mock(ImmutableList.class)
when(notSoImmutable.size()).thenThrow(new AssertionError("Oops.. where did that come from?"));

On package private classes

As your Animal class is package private it is not possible to create subclasses of it outside of its package. So assuming that in its package you only create subclasses of Animal that respect it's contract, the class is actually immutable.

For my answer I assumed that Animal is public. If you were interested specifically in package private classes, please ignore my answer ;-)

by anonymous   2017-08-20

The main issue with large list of parameters is readability and the danger that you will mix up parameters. You can tackle these issues with Builder pattern as described in Effective Java. It makes code more readable (especially languages that don't support named and optional parameters):

public class AddressBuilder {
    private Point _point;
    private String _houseNumber;

    // other parameters

    public AddressBuilder() {
    }

    public AddressBuilder WithPoint(Point point) {
        _point = point;
        return this;
    }

    public AddressBuilder WithHouseNumber(String houseNumber) {
        _houseNumber = houseNumber;
        return this;
    }

    public Address Build() {
        return new Address(_point, _houseNumber, ...);
    }
}

Address address = new AddressBuilder()
    .WithHouseNumber("123")
    .WithPoint(point)
    .Build();

The advantages:

  • parameters are named so it is more readable
  • harder to mix up house number with region
  • can use your own order of parameters
  • optional parameters can be omitted

One disadvantage I can think of is that forgetting to specify one of the arguments (not calling WithHouseNumber for example) will result in a run time error, instead of compile time error when using constructor. You should also consider using more Value Objects like PostalCode for example (as oppose to passing a string).

On a related note, sometimes business requirements call for changing part of the Value Object. For example, when address was originally entered, the street number might have been misspelled and needs to be corrected now. Since you modeled Address as an immutable object there is not setter. One possible solution to this problem is to introduce a 'Side-Effect-Free function' on the Address Value Object. The function would return a copy of the object itself with the exception of a new street name:

public class Address {
    private readonly String _streetName;
    private readonly String _houseNumber;

    ... 

    public Address WithNewStreetName(String newStreetName) {
        // enforce street name rules (not null, format etc)

        return new Address(
            newStreetName
            // copy other members from this instance
            _houseNumber);
    }

    ... 
}
by anonymous   2017-08-20

Enum is the best to do this as Joshua Bloch said in Effective Java,you will have more control using Enum like if you want to print all constants,you can. with class constants you can not have type safety.read this for further help