[Java] [Read Effective Java] Chapter 2, Item 1 Consider static factory method instead of constructor

4 minute read

Introduction

If you want to deepen your understanding of Java, read this, so I will read Effective Java while interpreting it myself. I am reading the second edition I was reading. https://www.amazon.co.jp/EFFECTIVE-JAVA-Java-Joshua-Bloch/dp/4621066056/ref=pd_sbs_14_3/355-5139262-7829161?_encoding=UTF8&pd_rd_i=4621066056&pd_rd_r=ac861412-beae-43a8-872a- 8b853aa69980&pd_rd_w=oIuWA&pd_rd_wg=nhmjU&pf_rd_p=7642417c-6494-4d06-a2b0-fcb0e0b3c563&pf_rd_r=HAEC02ASTQVJ4SPSM92Q&psc=1&refRID=HAEC02SMQQJ4

Consider static factory methods instead of constructors

I’m wondering if there are various happy things about replacing the processing that was implemented using the constructor with the static factory method until now.

Sample code

Example 1



public static Boolean valueOf(boolean b){
    return b? Boolean.TRUE: Boolean.FALSE;
}

Example 2



// service provider framework
public interface Service{
    // service specific methods here
}

// service provider interface
public interface Provider{
    Service newService();
}

// Non-instantiable class for service registration and access
public class Service{
    private Service(){} // Suppress instantiation (item 4)

    // Associate the service name with the service
    private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";

    // Provider registration API
    public static void registerDefaultProvider(Provider p){
        registerProvider(DEFAULT_PROVIDER_NAME,p);
    }
    public static void registerProvider(String name,Provider p){
        providers.put(name,p);
    }

    // Service access API
    public static Service newInstance(){
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    public static Service newInstance(String name){
        Provider p = providers.get(name);
        if (p == null)
            throw new IllegalArgumentException(
                    "Nn provider registered with name:" + name
            );
        return p.newService();
    }
    
}

Glossary

constructor

  • A constructor is a process that is executed when creating an instance of a class.
SampleClass instanceA = new SampleClass();

↑ The description of SampleClasss() after new is the call of the constructor

・How to write a constructor: Use the same name as the class name


public class SampleClass {
  //constructor
  public SampleClass(){
    System.out.println("It's a constructor");
  }
}

↑ When you do new with this, “It’s a constructor” is standard output

  • Unlike methods, constructors do not return values (writing a return causes an error)

static

  • A qualifier for creating instance-independent methods and variables

static factory method

  • A static factory method is simply a static method that returns an object. ・In Example 1, the boolean basic data value (b) is converted to a Boolean object.

Design pattern factory method

・Although the names are similar, they are different from static factory methods ・The explanation is omitted here

interface

  • The interface is a description of “variable” or “method type” without writing concrete processing of the method in the class. ・Conditions that “all methods are abstract methods” and “basically have no fields”
  • Since the processing details are not written specifically, it is only necessary to implement the processing details when you want to use them, which is convenient when processing changes may occur in the future (details can be postponed)

4 advantages and 2 disadvantages of static factory methods

Pros 1 Has a name unlike the constructor

・Constructor will be executed arbitrarily when new, but if it is a static factory method, a nice name will be given, so readability will increase

For example, if there is a process that returns a BigInteger that is a probable prime,

  • How to write in the constructor
BigInteger(int, int, Random)
  • How to write with static factory method
BigInteger.probablePrime

…Which one is easier to understand?

Advantage 2 Unlike the constructor, it is not necessary to create a new object each time the method is called

・Obviously, but since it’s static, it’s not instantiated I have to do new to call the constructor ・It’s not good to create many new objects unnecessarily

Advantage 3 Unlike the constructor, it can also return an object of any subtype of the return type of the method

・The constructor does not return a return value, but the static factory method is a method, so it is flexible because it can return. ・I’ll give you a service provider framework like Example 2 (conceal the contents and use it as an API).

Advantage 4 Reduces the hassle of instantiating parameterized types

・The redundant writing can be simplified. For example, if you had to write a constructor like this,

Map<String, List<String>> m =
  new HashMap<String, List<String>>();

You can write this with a static factory method

Map<String, List<String>> m = HashMap.newInstance();

It’s simple

Of course behind the scenes we have implemented a static factory method like this

public static <K, V> HashMap<K, V> newInstance() {
  return new HashMap<K.V>;
}

*Since P.S. Java 7 will perform type analogy, it is not necessary to write a static factory method.

Cons 1 Can’t create a subclass of a class that doesn’t have a public or protected constructor

Cons 2 They are not easily distinguishable from other static methods

  • Unlike the constructor, Javadoc does not recognize it well

Common name for static factory methods

Name Role  
Returns an instance with the same value as the valueOf parameter. It is essentially a type conversion method.
An alternative to of valueOf. A more concise one.
Returns the instance specified by getInstance parameter, but cannot say that they have the same value. In the case of a singleton, getInstance takes no arguments and returns its only instance.
Similar to newInstance getInstance, except that newInstance is returned as each individual instance is a separate instance.
Similar to getType getInstance but used when the factory method is in a different class than the target class. Type indicates the type of object returned from the factory method.
Similar to newType newInstance, but used when the factory method is in a different class than the target class. Type indicates the type of object returned from the factory method.

Continue

[Read Effective Java] Chapter 2, Item 2 “Consider a builder when faced with many constructor parameters” https://qiita.com/Natsukii/items/eb8fec0d8cae567f6647