15

Joshua Bloch's Effective Java describes a Builder Pattern that can be used to build objects with several optionally customizable parameters. The naming convention he suggests for the Builder functions, which "simulates named optional parameters as found in Ada and Python," doesn't seem to fall in line with Java's standard naming convention. Java functions tend to rely on a having a verb to start the function and then a noun-based phrase to describe what it does. The Builder class only has the name of the variable that's to be defined by that function.

Are there any APIs within the Java standard libraries that makes use of the Builder Pattern? I want to compare the suggestions in the book to an actual implementation within the core set of Java libraries before pursuing its use.

Aditya W
  • 652
  • 8
  • 20
Fostah
  • 11,398
  • 10
  • 46
  • 55
  • 1
    You can find example in this SE question: http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns-in-javas-core-libraries?rq=1 – Aditya W Jul 04 '16 at 15:44

7 Answers7

18

I'm not sure about within the core JDK, but good examples can be found in Guava. MapMaker is probably the best example I can think of off the top of my head. For example, from the docs:

ConcurrentMap<Key, Graph> graphs = new MapMaker()
    .concurrencyLevel(32)
    .softKeys()
    .weakValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeComputingMap(
        new Function<Key, Graph>() {
          public Graph apply(Key key) {
            return createExpensiveGraph(key);
          }
        });

Yes, this sort of thing can go against the grain of "standard" Java naming, but it can also be very readable.

For situations where you're not returning "this" but a new object (typically with immutable types) I like a "with" prefix - Joda Time uses that pattern extensively. That's not the builder pattern, but an alternative and related construction form.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Is this usage of "with" prefix a more commonly used convention? I always use a with prefix for builder classes returning `this`. I think this is also semantically suggested by the "with": the instance with a property = modify it. – kap May 29 '20 at 12:31
  • @kap: Yes, the "with" prefix is a fairly common convention, and I don't think it makes sense for "with" to modify something else, personally. Note that this is sufficiently common that in C# 9 it's becoming part of the *language* (in terms of what's generated for record types): https://github.com/dotnet/csharplang/blob/master/proposals/records.md – Jon Skeet May 29 '20 at 13:07
  • @kap: java.time uses this pretty extensively too, e.g. `LocalDate.withMonth` etc. – Jon Skeet May 29 '20 at 13:08
7

Locale class has an example of the Builder pattern. https://docs.oracle.com/javase/7/docs/api/java/util/Locale.Builder.html

Usage:

Locale locale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
Tanya Kogan
  • 141
  • 2
  • 3
5

Pretty good example from Java 8 Core API is Calendar, for example you can use:

Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
                        .setWeekDate(2013, 1, MONDAY).build();

Another good example from Java 7 is Locale, use:

Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();

The builder pattern is most useful in the context of immutable objects. Interestingly there are many mutable builders in Java, StringBuilder being the most common one. Mutable builders from Java 8:

  • Stream.Builder
  • IntStream.Builder
  • LongStream.Builder
  • DoubleStream.Builder
Anil Bhaskar
  • 3,718
  • 4
  • 33
  • 51
5

The only builder most accurate to the Effective java book is StringBuilder. The only difference I see from the example is that this builder is not an inner class of String.

All the methods return the builder object to chain. and the toString() method is the build() method.

John Brown
  • 59
  • 1
  • 1
  • 1
    `StringBuilder` is not an implementation of Builder Pattern, just because it's name says builder, It does not return a new `Object`, instead does opposite. Peace. – Anil Bhaskar Nov 17 '17 at 16:39
  • @AnilBhaskar Could you elaborate why `StringBuilder` doesn't follow the builder pattern? In this implementation, at least, a new (defensive) `String` is created. https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/lang/StringBuilder.java#L403 – Ellen Spertus Nov 23 '20 at 05:15
4

SAXParser seems to be a good example:

  • SAXParser - Director
  • ContentHandler - Builder

The typical usage of SAXParser is identical with Builder:

// Create Director
SAXParser parser = new org.apache.xerces.parsers.SAXParser();  
// Create Concrete Builder (our own class)
IndentingContentHandler handler = new IndentingContentHandler();
// Set Builder to Director
parser.setContentHandler(handler);
// Build
parser.parse(new InputSource(new FileReader(fileName));
// Get indented XML as String from handler
String indentedXML = handler.getResult();
cngzz1
  • 143
  • 2
  • 9
jk_
  • 5,448
  • 5
  • 25
  • 23
1

ProcessBuilder is very much an instance of the builder pattern, but not quite using the java naming conventions.

 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory(new File("myDir"));
 Process p = pb.start();

In the SQL package, PreparedStatement could be considered an instance of the builder pattern:

 PreparedStatement stmt = conn.prepareStatement(getSql());
 stmt.setString(1, ...);
 stmt.setString(2, ...);
 ResultSet rs = stmt.executeQuery();
 ...
 stmt.setString(2, ...);
 rs = stmt.executeQuery();
 ...
Sarah Happy
  • 273
  • 1
  • 5
0

It's only defined (not implemented) in the standard library, however, the JDBC DataSource objects remind me of the builder pattern. You create a DataSource object and then you set a number of properties and then you make a connection.

Here's a code example...

DataSource ds = (DataSource)ctx.lookup("jdbc/AcmeDB");
ds.setServerName("my_database_server");
ds.setDescription("the data source for inventory and personnel");
Connection con = ds.getConnection("genius", "abracadabra");
Pace
  • 41,875
  • 13
  • 113
  • 156