Static factory methods vs Instance (normal) constructors?

In Effective Java, 2nd edition, Joshua Bloch certainly recommends the former. There are a few reasons I can remember, and doubtless some I can't:

  • You can give the method a meaningful name. If you've got two ways of constructing an instance both of which take an int, but have different meanings for that int, using a normal method makes the calling code much more readable.
  • A corollary of the first - you can have different factory methods with the same parameter list
  • You can return null for "potentially expected failure" cases whereas a constructor will always either return a value or throw an exception
  • You can return a type other than the declared (e.g. return a derived class)
  • You can use it as a factory, to potentially return a reference to the same object several times

The downsides:

  • It's not as idiomatic, currently - developers are more used to seeing "new"
  • If you see "new" you know you're getting a new instance (modulo the oddity I mentioned recently)
  • You need to make appropriate constructors available for subclasses
  • In C# 3, constructor calls are able to set fields/properties in a compact manner with object initializer expressions; the feature doesn't apply to static method calls

I write a constructor when creating the instance has no side effects, i.e. when the only thing the constructor is doing is initializing properties. I write a static method (and make the constructor private) if creating the instance does something that you wouldn't ordinarily expect a constructor to do.

For example:

public class Foo
{
   private Foo() { }

   private static List<Foo> FooList = new List<Foo>();
   public static Foo CreateFoo()
   {
      Foo f = new Foo();
      FooList.Add(f);
      return f;
   }
}

Because I adhere to this convention, if I see

Foo f = Foo.CreateFoo();
Bar b = new Bar();

while reading my code, I have a very different set of expectations about what each of those two lines is doing. That code isn't telling me what it is that makes creating a Foo different from creating a Bar, but it's telling me that I need to look.