Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why LocalDate, LocalTime and Stream objects use a factory method of() instead of a constructor?

Why LocalDate, LocalTime, Stream, etc. objects use a factory method of() instead of a constructor?

I found an explanation of why a factory methods should be used instead of new here. This answer gives a number of reasons, but the only thing that is relevant to Java Date/Time API is the following:

unlike constructors, they are not required to create a new object each time they’re invoked

As LocalDate and LocalTime are immutable, it probably makes sense to use a factory and reuse existing objects instead of creating a new object every time.

Is it the reason why objects like LocalDate and LocalTime are created with a factory method (i.e., LocalDate.of())? Are there any other reasons?

Also, Stream objects are mutable. Why a factory method (Stream.of()) is used to create a Stream?

like image 349
Alex Avatar asked Jul 17 '16 18:07

Alex


2 Answers

Why a factory method (Stream.of()) is used to create a Stream?

Using a factory method means you don't need to know the exact class used. This is a good example as Stream is an interface and you can't create an instance of an interface.

From the source for Stream.of

/**
 * Returns a sequential {@code Stream} containing a single element.
 *
 * @param t the single element
 * @param <T> the type of stream elements
 * @return a singleton sequential stream
 */
public static<T> Stream<T> of(T t) {
    return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

/**
 * Returns a sequential ordered stream whose elements are the specified values.
 *
 * @param <T> the type of stream elements
 * @param values the elements of the new stream
 * @return the new stream
 */
@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}

Note: these methods call other factory methods.

You can see you get different constructions depending on how it is called. You don't need to know this or that the ultimate class created which is a ReferencePipeline.Head

like image 138
Peter Lawrey Avatar answered Sep 25 '22 03:09

Peter Lawrey


+1 to Peter's answer.

Another reason for using factory methods is that they act like "named constructors".

For example, LocalDate has 6 static factory methods (at least, I may not be exhaustive here):

  • of(int year, int/Month month, int dayOfMonth) (two overloads)
  • ofEpochDay(long epochDay)
  • ofYearDay(int year, int dayOfYear)
  • parse(CharSequence text)
  • parse(CharSequence text, DateTimeFormatter formatter)

I think that it is a lot clearer to understand the meanings of the various parameters by having these as separately-named methods, rather than a bunch of constructors with very similar parameter types; you can pretty much guess what the parameters should be for the factory methods, whereas you might actually have to read the Javadoc (shock horror) if they were "unnamed" constructors.

Admittedly, of is the least clear of these names - one might want ofYearMonthDayOfMonth - however, I suspect that this is the most commonly-used factory method, and it's just too cluttered to type that long name all the time.


In case you've not read it, Item 1 of Effective Java 2nd Edition is all about why and when to prefer static factory methods over constructors. The "named constructor" advantage I mention here is actually the first advantage Bloch highlights.

like image 29
Andy Turner Avatar answered Sep 22 '22 03:09

Andy Turner