Fluent APIs are 1% faster

Using fluent APIs without a guilty conscience

Fluent APIs are pretty common these days and make our lifes so much easier and the code far better to read. Even the JDK came up with some first fluent APIs many years ago, and we all are used to them meanwhile, like e. g. the well-known StringBuilder API.

Today I came up with the crazy idea to measure whether it will have any impact on performance when using a Fluent API instead of a non-fluent one. So I hacked together a short benchmark using Oracle Java Microbenchmarking Harness and gave it a shot.

The result is that actually Fluent APIs run about 1% faster than non-fluent APIs. Also the binary code is a bit smaller, hence less bytes have to be transferred, stored, loaded, etc. This might not sound dramatic, but hey, you not only get it for free, you even get it at the “cost” of better readability and short code.

Certainly my benchmark is anything but flawless, and the conclusion is not really statistically firm, as I measured more code than just the change from non-fluent to fluent API, and as the statistical error is about the same size of the measured difference. But hey, does anybody really conclude from that flaws that this means that using Fluent API (hence sparing code) would not have any postive effect? 😉

If my target would be massive performance improvements, certainly this will not be the #1 item to fix. For me the conclusion is that if there is a Fluent API, I will simply use it by default, unless some really good reasons conflict with that, as it makes the source better to read, the byte code shorter, and has no negative side effects – and does not make the program slower.

Fluent API Benchmark Setup

Non-Fluent API

public class MyBenchmark {
  @Benchmark public void testMethod() {
    StringBuilder sb = new StringBuilder();
    sb.append("a");
    sb.append("b");
    sb.append("c");
  }
}

The appending part look like this in byte code:

aload_1
ldc #4
invokevirtual #5
pope
aload_1
ldc #6
invokevirtual #5
pop
aload_1
ldc #7
invokevirtual #5
pop

The class file has a size of 652 Bytes.

JMH says the benchmark measured 38,250,987.105 operations per second.

Fluent API

public class MyBenchmark {
  @Benchmark public void testMethod() {
    StringBuilder sb = new StringBuilder();
    sb.append("a").append("b").append("c");
  }
}

The interesting section is consideraly shorter now in byte code as no more aload_1 and pop are found for the subsequent (fluent) invocations:

aload_1
ldc #4
invokevirtual #5
ldc #6
invokevirtual #5
ldc #7
invokevirtual #5

The class file has a size of 640 Bytes, which is 12 Bytes (1.84%) shorter.

JMH says this version yields 378,78,930.655 operations per second, which is 372,056.450 ops/s faster (0,973%).

Advertisements

About Markus Karg

Java Guru with +30 years of experience in professional software development. I travelled the whole world of IT, starting from Sinclair's great ZX Spectrum 48K, Commodore's 4040, over S/370, PCs since legendary XT, CP/M, VM/ESA, DOS, Windows (remember 3.1?), OS/2 WARP, Linux to Android and iOS... and still coding is my passion, and Java is my favourite drug!
This entry was posted in Java, Programming and tagged , . Bookmark the permalink.