Kevin's Blog

IT, Java, Web, Ubuntu

Method Chaining, to use, or not to use

It was a Gavin King’s book from which I first heard about method chaining since it is not that popular style in Java.

Bauer and King in their book entitled ‘Java Persistence with Hibernate’ (2007), point out that method chaining is convenient in some cases and is more popular in Smalltalk than in Java for Smalltalk, unlike Java, does not have void type. Thus when a method is invoked, it normally returns the object itself in which the method is placed.

Although it is used to improve readability and to reduce the amount of source code, I didn’t really like this style as it can be less readable and might make code difficult to debug. How can the technique to improve readability make the code less readable? By less readable, I mean the code may possibly be unpredictable or make the programmer confused in some cases.

Let’s look at some example.

This is a simple JavaBean named Item

package com.lckymn.kevin.test.methodchaining;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public class Item
{
	private int id;
	private String name;

	public Item(int id, String name)
	{
		this.id = id;
		this.name = name;
	}

	public int getId()
	{
		return id;
	}

	public void setId(int id)
	{
		this.id = id;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	@Override
	public String toString()
	{
		return "ID: " + id + "\n" + "Name: " + name + "\n";
	}
}

This is a Storage class designed to use method chaining.

package com.lckymn.kevin.test.methodchaining;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public class Storage
{
	private List<Item> items;

	public Storage()
	{
		this.items = new ArrayList<Item>();
	}

	public Storage put(String name)
	{
		items.clear();
		return and(name);
	}

	public Storage and(String name)
	{
		items.add(new Item(name.hashCode(), name));
		return this;
	}

	public Item get(int index)
	{
		return items.get(index);
	}

	public List<Item> getAll()
	{
		return items;
	}
}

Now, let’s use it.

package com.lckymn.kevin.test.methodchaining;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public final class MethodChainingTest
{
	public static void main(String[] args)
	{
		String name = new Storage().put("A").and("B").and(null).and("D").get(0).getName();
		System.out.println("Name: " + name + "\n");

		System.exit(0);
	}

}

What is this? It looks like instantiating a Storage object yet the end it assigns String value to String variable named name?

It seems confusing. First, instantiate Storage. Then call several methods in it. Finally call the method which returns a String value. However, the Storage class doesn’t even have any method returning the String value. It is the method in the Item class.

OK, move to the other problem that is difficulty in debuging.
The example code above does not have any compile time error yet when it runs the result is

Exception in thread "main" java.lang.NullPointerException
	at com.lckymn.kevin.test.methodchaining.Storage.and(Storage.java:26)
	at com.lckymn.kevin.test.methodchaining.MethodChainingTest.main(MethodChainingTest.java:10)

The tenth line in the MethodChainingTest.main method is this.

		String name = new Storage().put("A").and("B").and(null).and("D").get(0).getName();

The twenty-sixth line in the Storage.and method is this.

		items.add(new Item(name.hashCode(), name));

So this line of the code causes NullPointerException but and() method is called three times in the tenth line of the MethodChainingTest class. Which one of these causes the error? In the example, it is very obvious that the and() method call with null parameter is the one. However, in real-life programme, it is usually much more difficult to find.

So, as already mentioned, I did not like using method chaining. Then again there came a time when it was very convenient and useful to use method chaining. I found it very useful when I was making a XML generator programme for an Ajax application. I made it using Java API for XML Processing (JAXP). It required to generate simple XML based on a given object so it might be too much to use XML data binding frameworks and tools such as Java Architecture for XML Binding (JAXB) and XStream. Although both JAXB and XStream are simple and easy to use and can be used to serialise objects, I wanted to have more control than what the framework provides. JAXP with Simple API for XML (SAX) parsing interface was just suitable for what I needed, yet it is not very pleasant to use the SAX interface. It uses ContentHandler interface when making XML contents and the following code is what it looks like when using it.

contentHandler.startDocument();

AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, null, "type", null, "User");
contentHandler.startElement(null, null, "users", atts);

atts.clear();
atts.addAttribute(null, null, "id", null, "kevin");
atts.addAttribute(null, null, "surname", null, "Lee");
atts.addAttribute(null, null, "givenName", null, "Kevin");
contentHandler.startElement(null, null, "user", atts);
contentHandler.characters("Test value".toCharArray(), 0, "Test value".length());
contentHandler.endElement(null, null, "user");

atts.clear();
atts.addAttribute(null, null, "id", null, "john");
atts.addAttribute(null, null, "surname", null, "Doe");
atts.addAttribute(null, null, "givenName", null, "John");
contentHandler.startElement(null, null, "user", atts);
contentHandler.characters("Blah Blah".toCharArray(), 0, "Blah Blah".length());
contentHandler.endElement(null, null, "user");

atts.clear();
atts.addAttribute(null, null, "id", null, "tom");
atts.addAttribute(null, null, "surname", null, "Smith");
atts.addAttribute(null, null, "givenName", null, "Tom");
contentHandler.startElement(null, null, "user", atts);
contentHandler.characters("12345".toCharArray(), 0, "12345".length());
contentHandler.endElement(null, null, "user");

contentHandler.endElement(null, null, "users");

contentHandler.endDocument();

As all I want was simple XML for an Ajax application, I had to type ‘null‘ many times as parameter values for namespace URI and local name which were definitely unnecessary for my programme. Since the data transfered through network need to be small, XML sent to the front-end Ajax application had better not have the data such as namespace and schema location information and so on.

However, what I all had was, as shown above, the ugly code which repeatedly calls same methods with many ‘null’ parameters. So I tried to find a better way and eventually came up with that it might be a good idea to use method chaining. Even so, there were still the two problems I mentioned.

The method chaining code example that I showed earlier is, in fact, a misuse of method chaining. That can be much better if it is used properly. After all, it is not the technique that makes the code less maintainable but how it is used that makes the code less maintainable.

Think about this. If a knife is used by a murderer, the result of using it would be a dead body while if it is used by a chef, the result would be a delicious meal unless the chef is the murderer. :) (I think I used this sentence when I had my presentation in the third year in my undergraduate days. The subject was about IT and ethics, and I was emphasising that technologies have nothing to do with ethics yet how we use these is important when it comes to ethics).

So, how can those two problems be solved? First of all, please don’t get me wrong. I am not saying that the way I am going to tell here is the best, but it is just what I do. That’s it.

I chose to implement fluent interface yet with my own taste.

Cho, YoungHo (2008) in his article, ‘Applicaiton of Domain-Driven Design 2.Aggregate and Repository #3‘, also says that although FLUENT INTERFACE might violate the principle of COMMAND-QUERY SEPARATION which enforces to separate the method to change the state of an object from the method to query the state, FLUENT INTERFACE using method chaining can enable the interface design to be more readable and easier to use.

If you can understand Korean and are interested in Domain-Driven Design (DDD), his articles about DDD are really worth reading.
http://aeternum.egloos.com/category/Domain-Driven%20Design
It is well written with appropriate example code and supporting theories and principles.

So my tastes are
1. The prefix ‘Fluent’ shall be used to tell it is a fluent interface.
e.g.)
public interface FluentContentHandler
public interface FluentStorage

2. void return type shall be used to stop method chaining if the method should not be used with other methods in the fluent interface or if it has some side-effect when using with other methods so that the programmer should be noticed it by void return type.
e.g.)
void endDoc()
void finish()

3. Otherwise, all the methods shall return the type of interface itself, and the name of the normal methods which return the type of the interface itself shall begin with verb.
e.g.)
FluentContentHandler openElem(String qName)
FluentContentHandler setText(String qName)
FluentSaxAttributes create(String qName, String value)

OR
The name of the method which must be used before the other methods shall begin with a verb.
e.g.)
FluentSaxAttributes create(String qName, String value)
The name of the method which must be used after the method the name of which begins with a verb shall be an appropriate preposition or conjunction.
e.g.)
FluentSaxAttributes with(String qName, String value)
FluentSaxAttributes and(String qName, String value)

4. If other types than the interface itself need to be returned, distinguishable method names shall be used. The name of the methods which return other type than the type of the interface itself shall begin with a preposition followed by a noun.
e.g.)
List toList()
Map toMap()
Collection toCollection()

I believe, these can help me to get over the first matter, and the code would be more readable as expected.

So let’s have a look at the new fluent interfaces for my XML generator programme.

package com.lckymn.kevin.test.xml;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public interface FluentSaxContentHandler
{
	void startDoc() throws SAXException;

	void endDoc() throws SAXException;

	FluentSaxContentHandler openElem(String qName) throws SAXException;

	FluentSaxContentHandler openElem(String qName, FluentSaxAttributes attributes) throws SAXException;

	FluentSaxContentHandler setText(String text) throws SAXException;

	void closeElem(String qName) throws SAXException;
}

The programmer using this interface had better be aware of that startDoc() and endDoc() methods are to start and to end the XML document so use it once and therefore these return void type to warn. Similarly, closeElem() method the type of which is void closes the element with the name given as the parameter so the programmer had better stop method chaining here and open a new element with another method chaining.

package com.lckymn.kevin.test.xml;

import org.xml.sax.helpers.AttributesImpl;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public interface FluentSaxAttributes
{
	FluentSaxAttributes create(String qName, String value);

	FluentSaxAttributes add(String qName, String value);

	AttributesImpl toAttributesImpl();
}

Since the ContentHandler requires AttributesImpl as attributes toAttributesImpl() method needs to return AttributesImpl and therefore its name consists of the preposition ‘to’ and the noun ‘AttributesImpl’.

Now let’s use these.

	contentHandler.startDoc();
		
	contentHandler.openElem("users", atts.create("type", "User"));
		
	contentHandler.openElem("user", atts.create("id", "kevin").add("surname", "Lee").add("givenName", "Kevin")).setText("Test value").closeElem("user");
	contentHandler.openElem("user", atts.create("id", "john").add("surname", "Doe").add("givenName", "John")).setText("Blah Blah").closeElem("user");
	contentHandler.openElem("user", atts.create("id", "tom").add("surname", "Smith").add("givenName", "Tom")).setText("12345").closeElem("user");
		
	contentHandler.closeElem("users");
	
	contentHandler.endDoc();

It looks much simpler and readable than the previous code below.

	contentHandler.startDocument();

	AttributesImpl atts = new AttributesImpl();
	atts.addAttribute(null, null, "type", null, "User");
	contentHandler.startElement(null, null, "users", atts);

	atts.clear();
	atts.addAttribute(null, null, "id", null, "kevin");
	atts.addAttribute(null, null, "surname", null, "Lee");
	atts.addAttribute(null, null, "givenName", null, "Kevin");
	contentHandler.startElement(null, null, "user", atts);
	contentHandler.characters("Test value".toCharArray(), 0, "Test value".length());
	contentHandler.endElement(null, null, "user");

	atts.clear();
	atts.addAttribute(null, null, "id", null, "john");
	atts.addAttribute(null, null, "surname", null, "Doe");
	atts.addAttribute(null, null, "givenName", null, "John");
	contentHandler.startElement(null, null, "user", atts);
	contentHandler.characters("Blah Blah".toCharArray(), 0, "Blah Blah".length());
	contentHandler.endElement(null, null, "user");

	atts.clear();
	atts.addAttribute(null, null, "id", null, "tom");
	atts.addAttribute(null, null, "surname", null, "Smith");
	atts.addAttribute(null, null, "givenName", null, "Tom");
	contentHandler.startElement(null, null, "user", atts);
	contentHandler.characters("12345".toCharArray(), 0, "12345".length());
	contentHandler.endElement(null, null, "user");

	contentHandler.endElement(null, null, "users");

	contentHandler.endDocument();

Yet there is one more problem still left that is difficulty in debugging.

King and Bauer (2007) suggests that “it’s better to write each method invocation on a different line”.

So rewrite the code

	contentHandler.startDoc();

	contentHandler.openElem("users", atts.create("type", "User"));

	contentHandler.openElem("user", atts.create("id", "kevin")
			.add("surname", "Lee")
			.add("givenName", "Kevin"))
			.setText("Test value")
			.closeElem("user");
	contentHandler.openElem("user", atts.create("id", "john")
			.add("surname", "Doe")
			.add("givenName", "John"))
			.setText("Blah Blah")
			.closeElem("user");
	contentHandler.openElem("user", atts.create("id", "tom")
			.add("surname", "Smith")
			.add("givenName", "Tom"))
			.setText("12345")
			.closeElem("user");

	contentHandler.closeElem("users");

	contentHandler.endDoc();

Now not only does it solve the problem in debugging but it is also even more readable. My problem solved! :D
Well, unfortunately there is one more problem. :(

I am using Eclipse and it has a nice automatic formatting feature. So whenever I press SHIFT+CTRL+F, it automatically formats the code opened in the editor based on the format configuration. This means if I use that function, I lose the coding style of writing each method invocation on a different line as Eclipse formatter puts all the method on a different line together on one line. So do I have to reformat by myself after every automatic formatting? It’s really annoying. :(

Fortunately, a few changes in formatter configuration can solve this problem.

Click the ‘Window’ menu -> ‘Preferences’

When the ‘Preferences’ menu pops up
-Expand the ‘Java’ -> Expand the ‘Code Style’ -> Select the ‘Fomatter’

-Click the ‘Edit’ button on the top right-hand side.
Expand the 'Java' -> Expand the 'Code Style' -> Select the 'Fomatter' -> Click the 'Edit' button on the top right-hand side

-The profile window appears -> Select the ‘Line Wrapping’ -> Expand the ‘Function Calls’ -> Select the ‘Qualified invocations’ -> Select the ‘Wrap all elements, except first element if not necessary’ as the ‘Line wrapping policy’ -> Select the ‘Default indentation’ as the ‘Indentation policy’ -> Check the ‘Force split’ -> Click the ‘OK’ button.
Profile window appears -> Select the 'Line Wrapping' -> Expand the 'Function Calls' -> Select the 'Qualified invocations' -> Select the 'Wrap all elements, except first element if not necessary' as the 'Line wrapping policy' -> Select the 'Default indentation' as the 'Indentation policy' -> Check the 'Force split' -> Click the 'OK' button

-Click the ‘OK’ button to apply the changes.

Now, the Eclipse Java formatter formats the code, using method chaining, as what I want.

Finally, how can I improve my first example of method chaining?
The Item class does not need to be changed.

Write the fluent interface, FluentStorage.

package com.lckymn.kevin.test.fluentinterface;

import java.util.List;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public interface FluentStorage
{
	FluentStorage add(String name);
	
	List<Item> toList();
}

Write the class implements it.

package com.lckymn.kevin.test.fluentinterface;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public class FluentListStorage implements FluentStorage
{
	private List<Item> items;

	public FluentListStorage()
	{
		items = new ArrayList<Item>();
	}

	@Override
	public FluentStorage add(String name)
	{
		items.add(new Item(name.hashCode(), name));
		return this;
	}

	@Override
	public List<Item> toList()
	{
		return items;
	}

}

Now use the fluent interface.

package com.lckymn.kevin.test.fluentinterface;

import java.util.List;

/**
 * @author Lee, SeongHyun (Kevin)
 */
public final class MethodChainingTest
{
	public static void main(String[] args)
	{
		FluentStorage fluentStorage = new FluentListStorage().add("A")
				.add("B")
				.add(null)
				.add("D");

		List<Item> items = fluentStorage.toList();
		for (Item item : items)
		{
			System.out.println(item);
		}
		int howMany = items.size();
		System.out.println("There " + (1 < howMany ? "are " + howMany + " items" : "is " + howMany + " item") + " in the storage.");
		System.exit(0);
	}

}

When it runs, it displays the following error messages yet now I know that the fourteenth line causes the error.

Exception in thread "main" java.lang.NullPointerException
	at com.lckymn.kevin.test.fluentinterface.FluentListStorage.add(FluentListStorage.java:21)
	at com.lckymn.kevin.test.fluentinterface.MethodChainingTest.main(MethodChainingTest.java:14)

The fourteenth line is this.

				.add(null)

So change it to

				.add("C")

I could finally have the correct result.

ID: 65
Name: A

ID: 66
Name: B

ID: 67
Name: C

ID: 68
Name: D

There are 4 items in the storage.

So method chaining, to use, or not to use? It’s all up to you. :D

References
Bauer, C. and King, G. 2007, Java Persistence with Hibernate, Manning Publications Co., New York.

Cho, Y. 2008, Applicaiton of Domain-Driven Design 2. Aggregate and Repository #3, viewed 29 June 2009, <http://aeternum.egloos.com/1173825>.

Loading Facebook Comments ...
Loading Disqus Comments ...

4 Comments

  1. Kevin님 안녕하세요. (여기에 한글로 답변 달면 안될 것 같은 압박이… 그러나 어쩔 수 없이 한글로… ^^;)
    Method Chaining에 대한 좋은 글 잘 읽었습니다. 제 글을 인용해서 주셔서 감사합니다. 뿌듯하네요.
    저보다 글을 더 잘 쓰시는 것 같습니다. 거기다 영어로.. 부럽네요 ^^
    SAX를 핸들링하기 위해 Fluent Interface를 가진 Expression Builder를 만들기 위해 Method Chaining을 사용하셨네요.
    Method Chaining을 적용하는데 좋은 참고가 될 것 같습니다.
    좋은 글 또 부탁드릴께요. ^^

    • Kevin

      6 July, 2009 at 2:02 am

      댓글은 제가 알아듣는 말이면 아무거나 상관없습니다…^^;;;
      가끔 제가 모르는 언어로 글 (이 아니라 사실 스팸) 을 남기는 분이 계신데, 요런건 바로 삭제죠…^^;

      감사는 제가 드려야죠. Eternity님께서 좋은글 쓰셔서 인용할수 있게 도와주셨으니까요. :)
      저의 경우는, Eternity님 처럼 체계적이고 도움이 되는글을 쓴게 아니고,
      “그냥 이경우 저는 이런식으로 합니다.” 라는 잡담 형식이라서…
      제글은 거론할 가치가 없습니다.
      영어야 워낙 기술 설명하기에는 간결한 언어라, 이것도 역시 거론할 가치가…^^;;;

      아무튼 과찬이십니다.
      제 주변에서는 method chaining 쓰는걸 많이 보지 못했고,
      (Java쪽은 아니고 주로 JavaScript쪽 jQuery 사용하는 경우에 쓰는건 많이 봤군요.)
      저도 접한 후에도 본문에 설명한 이유로 맘에 안 들어서 안 쓰다가
      쓸모 있는 상황을 발견하게 되었고,
      역시 기술이고 뭐고 사용하는 사람이 어떻게 쓰느냐에 달렸구나 라는걸 느껴서
      그냥 간단하게 느낀걸 써보고자 하다가 차일피일 미뤄졌었는데,
      마침 Eternity님 글에서 체계적으로 언급하신걸 보고 인용해서 글을 쓰게 됐네요.
      그냥 잡담도 Eternity님 글을 인용한 덕에 모양새가 조금 나아져서 다행입니다.
      감사합니다. :)

  2. Varghese Cottagiri

    3 August, 2009 at 3:39 am

    Good write up on Method Chaining. I think that if an API built with Method Chaining in mind is presented to a developer – he/she would invariably start using it just because the number of keystrokes is less, especially in an IDEs one could go selecting method after method from the drop downs.

    • Kevin

      3 August, 2009 at 11:58 pm

      Thanks Varghese Cottagiri.

      Yes, it’s easier to use method chaining with a function like code (content) assist in some IDEs. Although I still don’t like overuse of method chaining, as I said, it can be very useful if a developer uses it carefully or has good reasons for using it. For instance, the append method of StringBuilder returns the StringBuilder itself so it is easy to add more String with chaining the append method call. Another good example can be found in builder pattern used when there are many constructor parameters as Joshua Bloch recommends in his book entitled ‘Effective Java’. The methods in Builder object returns the object itself so the invocations can be chained then finally it returns the desired object so the object can be instantiated with member variables initialised with all the values that the builder object contains.

      I think it has probably become more useful to use method chaining since Java 5 (JDK 1.5) as the return type covariance is implemented in Java 5.

Leave a Reply

© 2014 Kevin's Blog

Theme by Anders NorenUp ↑

%d bloggers like this: