1

Suppose I have an object A which can call getB() call getC() call getD() call doSomething… Now I want to use some methods of the D multiple times in my application i.e.

 A.getB().getC().getD().doSomething1();
 A.getB().getC().getD().doSomething2();
 A.getB().getC().getD().doSomething3();

I know it's best to create a variable d = A.getB().getC().getD() and then use it. But I wonder if there's any performance issue with chaining multiple methods like this.

class A { 
  private B b;
  B getB() { 
    return b;
  }
}
class B {
  private C c;
  C getC() { 
    return c;
  }
}
class C {
  private D d;
  D getD() { 
    return d;
  }
}

class D {
  void doSomething1(){};
  void doSomething2(){};
  void doSomething3(){};
}
Eric
  • 6,563
  • 5
  • 42
  • 66
user2747502
  • 323
  • 3
  • 13

4 Answers4

2

No any performance issue if objects are instantiated once. When you call getB().getC()... you just get link on object that is very fast and simple operation. But, actually, such code does not looks very good.

2

Although you mentioned that you already know it: You should avoid such long method chains, for several reasons:

  • It's an indication of bad OO design (more precisely, it looks like a violation of the Law Of Demeter)
  • It's error-prone. If a line like a.getB().getC().getD().doSomething() throws a NullPointerException, you'll have no fun with debugging this...
  • Let me be a bit subjective here: It looks horrible.

Of course, you have to consider what the methods are doing actually. Although a get-method should usually just return a value, you don't know whether it really does this. Even something like

List<T> getList() {
    // Return an unmodifiable view to the caller
    return Collections.unmodifiableList(internalList);
}

(which certainly is a good practice) may change the outcome.

That being said, and considering that these get-methods are really only plain, stupid Getters:

It does not have an impact on performance in practice. The method calls will be inlined by the JIT.

As an example, consider the following program:

class ChainA {
  private ChainB b = new ChainB();
  ChainB getB() {
    return b;
  }
}
class ChainB {
  private ChainC c = new ChainC();
  ChainC getC() {
    return c;
  }
}
class ChainC {
  private ChainD d = new ChainD();
  ChainD getD() {
    return d;
  }
}

class ChainD {
  private int result = 0;
  int getResult() { return result; }
  void doSomething1(){ result += 1; }
  void doSomething2(){ result += 2; }
  void doSomething3(){ result += 3; }
}

class Chaining
{
    public static void main(String args[])
    {
        for (int n=100; n<10000; n+=100)
        {
            ChainA a0 = new ChainA();
            runChained(a0, n);
            System.out.println(a0.getB().getC().getD().getResult());

            ChainA a1 = new ChainA();
            runUnChained(a1, n);
            System.out.println(a1.getB().getC().getD().getResult());
        }

    }

    private static void runChained(ChainA a, int n)
    {
        for (int i=0; i<n; i++)
        {
            a.getB().getC().getD().doSomething1();
            a.getB().getC().getD().doSomething2();
            a.getB().getC().getD().doSomething3();
        }
    }

    private static void runUnChained(ChainA a, int n)
    {
        ChainD d = a.getB().getC().getD();
        for (int i=0; i<n; i++)
        {
            d.doSomething1();
            d.doSomething2();
            d.doSomething3();
        }
    }

}

It performs the calls like you described them, once as a chained call, and once as an unchained version.

Running it with

java -server -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation -XX:+PrintAssembly Chaining

on a HotSpot-Disassembler-enabled JVM results in the following output (no need to read it, just for reference)

runChained:

Decoding compiled method 0x0000000002885d50:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x0000000055360550} &apos;runChained&apos; &apos;(LChainA;I)V&apos; in &apos;Chaining&apos;
  # parm0:    rdx:rdx   = &apos;ChainA&apos;
  # parm1:    r8        = int
  #           [sp+0x30]  (sp of caller)
  0x0000000002885e80: mov    %eax,-0x6000(%rsp)
  0x0000000002885e87: push   %rbp
  0x0000000002885e88: sub    $0x20,%rsp         ;*synchronization entry
                                                ; - Chaining::runChained@-1 (line 47)

  0x0000000002885e8c: mov    %rdx,%r9
  0x0000000002885e8f: mov    %r8d,%ebx
  0x0000000002885e92: test   %r8d,%r8d
  0x0000000002885e95: jle    0x0000000002885f8a  ;*if_icmpge
                                                ; - Chaining::runChained@4 (line 47)

  0x0000000002885e9b: mov    0xc(%rdx),%r11d    ;*getfield b
                                                ; - ChainA::getB@1 (line 4)
                                                ; - Chaining::runChained@8 (line 49)
                                                ; implicit exception: dispatches to 0x0000000002885f96
  0x0000000002885e9f: mov    0xc(%r11),%r10d    ;*getfield c
                                                ; - ChainB::getC@1 (line 10)
                                                ; - Chaining::runChained@11 (line 49)
                                                ; implicit exception: dispatches to 0x0000000002885f96

    0x0000000002885ea3: mov    0xc(%r10),%edx     ;*getfield d
                                                ; - ChainC::getD@1 (line 16)
                                                ; - Chaining::runChained@14 (line 49)
                                                ; implicit exception: dispatches to 0x0000000002885f96
  0x0000000002885ea7: mov    0xc(%rdx),%r11d    ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runChained@17 (line 49)
                                                ; implicit exception: dispatches to 0x0000000002885f96
  0x0000000002885eab: xor    %r10d,%r10d
  0x0000000002885eae: xor    %esi,%esi
  0x0000000002885eb0: xor    %r8d,%r8d
  0x0000000002885eb3: xor    %ecx,%ecx          ;*aload_0
                                                ; - Chaining::runChained@7 (line 49)

  0x0000000002885eb5: add    %r11d,%esi         ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runChained@17 (line 49)

  0x0000000002885eb8: add    %ecx,%r8d
  0x0000000002885ebb: mov    %esi,%eax
  0x0000000002885ebd: add    $0x6,%eax          ;*iadd
                                                ; - ChainD::doSomething3@6 (line 25)
                                                ; - Chaining::runChained@43 (line 51)

  0x0000000002885ec0: mov    %eax,0xc(%rdx)     ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runChained@43 (line 51)

  0x0000000002885ec3: mov    %r10d,%edi
  0x0000000002885ec6: inc    %edi               ;*iinc
                                                ; - Chaining::runChained@46 (line 47)

  0x0000000002885ec8: cmp    $0x1,%edi
  0x0000000002885ecb: jge    0x0000000002885eee  ;*if_icmpge
                                                ; - Chaining::runChained@4 (line 47)

  0x0000000002885ecd: mov    %r10d,%ecx
  0x0000000002885ed0: shl    %ecx
  0x0000000002885ed2: mov    %r8d,%esi
  0x0000000002885ed5: add    $0x6,%esi
  0x0000000002885ed8: mov    %ecx,%r8d
  0x0000000002885edb: add    $0x2,%r8d
  0x0000000002885edf: shl    $0x2,%r10d
  0x0000000002885ee3: mov    %r10d,%ecx
  0x0000000002885ee6: add    $0x4,%ecx
  0x0000000002885ee9: mov    %edi,%r10d
  0x0000000002885eec: jmp    0x0000000002885eb5
  0x0000000002885eee: mov    %ebx,%r11d
  0x0000000002885ef1: add    $0xfffffff1,%r11d
  0x0000000002885ef5: mov    $0x80000000,%r9d
  0x0000000002885efb: cmp    %r11d,%ebx
  0x0000000002885efe: cmovl  %r9d,%r11d
  0x0000000002885f02: cmp    %r11d,%edi
  0x0000000002885f05: jge    0x0000000002885f3c
  0x0000000002885f07: sub    %r8d,%esi
  0x0000000002885f0a: nopw   0x0(%rax,%rax,1)   ;*aload_0
                                                ; - Chaining::runChained@7 (line 49)

  0x0000000002885f10: mov    %edi,%r8d
  0x0000000002885f13: shl    %r8d
  0x0000000002885f16: mov    %edi,%r9d
  0x0000000002885f19: shl    $0x2,%r9d
  0x0000000002885f1d: add    %r9d,%r8d
  0x0000000002885f20: add    %esi,%r8d          ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runChained@17 (line 49)

  0x0000000002885f23: mov    %r8d,%eax
  0x0000000002885f26: add    $0x60,%eax         ;*iadd
                                                ; - ChainD::doSomething3@6 (line 25)
                                                ; - Chaining::runChained@43 (line 51)

  0x0000000002885f29: add    $0x5a,%r8d
  0x0000000002885f2d: mov    %r8d,0xc(%rdx)
  0x0000000002885f31: mov    %eax,0xc(%rdx)     ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runChained@43 (line 51)

  0x0000000002885f34: add    $0x10,%edi         ;*iinc
                                                ; - Chaining::runChained@46 (line 47)

  0x0000000002885f37: cmp    %r11d,%edi
  0x0000000002885f3a: jl     0x0000000002885f10  ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runChained@17 (line 49)

  0x0000000002885f3c: cmp    %ebx,%edi
  0x0000000002885f3e: jge    0x0000000002885f8a
  0x0000000002885f40: mov    %edi,%r10d
  0x0000000002885f43: shl    $0x2,%r10d
  0x0000000002885f47: mov    %edi,%r11d
  0x0000000002885f4a: shl    %r11d
  0x0000000002885f4d: mov    %r11d,%r8d
  0x0000000002885f50: add    %r10d,%r8d
  0x0000000002885f53: sub    %r8d,%eax
  0x0000000002885f56: xchg   %ax,%ax            ;*aload_0
                                                ; - Chaining::runChained@7 (line 49)

  0x0000000002885f58: add    %r11d,%r10d
  0x0000000002885f5b: add    %eax,%r10d
  0x0000000002885f5e: add    $0x6,%r10d
  0x0000000002885f62: mov    %r10d,0xc(%rdx)    ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runChained@43 (line 51)

  0x0000000002885f66: mov    %edi,%r8d
  0x0000000002885f69: inc    %r8d               ;*iinc
                                                ; - Chaining::runChained@46 (line 47)

  0x0000000002885f6c: cmp    %ebx,%r8d
  0x0000000002885f6f: jge    0x0000000002885f8a
  0x0000000002885f71: mov    %edi,%r10d
  0x0000000002885f74: shl    $0x2,%r10d
  0x0000000002885f78: shl    %edi
  0x0000000002885f7a: add    $0x4,%r10d
  0x0000000002885f7e: mov    %edi,%r11d
  0x0000000002885f81: add    $0x2,%r11d
  0x0000000002885f85: mov    %r8d,%edi
  0x0000000002885f88: jmp    0x0000000002885f58  ;*if_icmpge
                                                ; - Chaining::runChained@4 (line 47)

  0x0000000002885f8a: add    $0x20,%rsp
  0x0000000002885f8e: pop    %rbp
  0x0000000002885f8f: test   %eax,-0x26c5f95(%rip)        # 0x00000000001c0000
                                                ;   {poll_return}
  0x0000000002885f95: retq   
  0x0000000002885f96: mov    $0xffffff86,%edx
  0x0000000002885f9b: mov    %r9,%rbp
  0x0000000002885f9e: mov    %r8d,(%rsp)
  0x0000000002885fa2: nop
  0x0000000002885fa3: callq  0x00000000027b7320  ; OopMap{rbp=Oop off=296}
                                                ;*aload_0
                                                ; - Chaining::runChained@7 (line 49)
                                                ;   {runtime_call}
  0x0000000002885fa8: int3                      ;*aload_0
                                                ; - Chaining::runChained@7 (line 49)

  0x0000000002885fa9: hlt    
  0x0000000002885faa: hlt    
  0x0000000002885fab: hlt    
  0x0000000002885fac: hlt    
  0x0000000002885fad: hlt    
  0x0000000002885fae: hlt    
  0x0000000002885faf: hlt    
  0x0000000002885fb0: hlt    
  0x0000000002885fb1: hlt    
  0x0000000002885fb2: hlt    
  0x0000000002885fb3: hlt    
  0x0000000002885fb4: hlt    
  0x0000000002885fb5: hlt    
  0x0000000002885fb6: hlt    
  0x0000000002885fb7: hlt    
  0x0000000002885fb8: hlt    
  0x0000000002885fb9: hlt    
  0x0000000002885fba: hlt    
  0x0000000002885fbb: hlt    
  0x0000000002885fbc: hlt    
  0x0000000002885fbd: hlt    
  0x0000000002885fbe: hlt    
  0x0000000002885fbf: hlt    
[Exception Handler]
[Stub Code]
  0x0000000002885fc0: jmpq   0x00000000028694a0  ;   {no_reloc}
[Deopt Handler Code]
  0x0000000002885fc5: callq  0x0000000002885fca
  0x0000000002885fca: subq   $0x5,(%rsp)
  0x0000000002885fcf: jmpq   0x00000000027b6f40  ;   {runtime_call}
  0x0000000002885fd4: hlt    
  0x0000000002885fd5: hlt    
  0x0000000002885fd6: hlt    
  0x0000000002885fd7: hlt    

runUnChained:

Decoding compiled method 0x00000000028893d0:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x0000000055360628} &apos;runUnChained&apos; &apos;(LChainA;I)V&apos; in &apos;Chaining&apos;
  # parm0:    rdx:rdx   = &apos;ChainA&apos;
  # parm1:    r8        = int
  #           [sp+0x30]  (sp of caller)
  0x0000000002889500: mov    %eax,-0x6000(%rsp)
  0x0000000002889507: push   %rbp
  0x0000000002889508: sub    $0x20,%rsp         ;*synchronization entry
                                                ; - Chaining::runUnChained@-1 (line 57)



  0x000000000288950c: mov    0xc(%rdx),%r11d    ;*getfield b
                                                ; - ChainA::getB@1 (line 4)
                                                ; - Chaining::runUnChained@1 (line 57)
                                                ; implicit exception: dispatches to 0x0000000002889612
  0x0000000002889510: mov    0xc(%r11),%r10d    ;*getfield c
                                                ; - ChainB::getC@1 (line 10)
                                                ; - Chaining::runUnChained@4 (line 57)
                                                ; implicit exception: dispatches to 0x000000000288961d
  0x0000000002889514: mov    0xc(%r10),%ebx     ;*getfield d
                                                ; - ChainC::getD@1 (line 16)
                                                ; - Chaining::runUnChained@7 (line 57)
                                                ; implicit exception: dispatches to 0x0000000002889629
  0x0000000002889518: mov    %r8d,%esi
  0x000000000288951b: test   %r8d,%r8d
  0x000000000288951e: jle    0x0000000002889606  ;*if_icmpge
                                                ; - Chaining::runUnChained@15 (line 58)

  0x0000000002889524: mov    0xc(%rbx),%r10d    ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runUnChained@19 (line 60)
                                                ; implicit exception: dispatches to 0x0000000002889635
  0x0000000002889528: xor    %r8d,%r8d
  0x000000000288952b: xor    %edx,%edx
  0x000000000288952d: xor    %r9d,%r9d
  0x0000000002889530: xor    %r11d,%r11d        ;*aload_2
                                                ; - Chaining::runUnChained@18 (line 60)

  0x0000000002889533: add    %r10d,%edx         ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runUnChained@19 (line 60)

  0x0000000002889536: add    %r11d,%r9d
  0x0000000002889539: mov    %edx,%edi
  0x000000000288953b: add    $0x6,%edi          ;*iadd
                                                ; - ChainD::doSomething3@6 (line 25)
                                                ; - Chaining::runUnChained@27 (line 62)

  0x000000000288953e: mov    %edi,0xc(%rbx)     ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runUnChained@27 (line 62)

  0x0000000002889541: mov    %r8d,%ecx
  0x0000000002889544: inc    %ecx               ;*iinc
                                                ; - Chaining::runUnChained@30 (line 58)

  0x0000000002889546: cmp    $0x1,%ecx
  0x0000000002889549: jge    0x000000000288956e  ;*if_icmpge
                                                ; - Chaining::runUnChained@15 (line 58)

  0x000000000288954b: mov    %r8d,%r11d
  0x000000000288954e: shl    %r11d
  0x0000000002889551: mov    %r9d,%edx
  0x0000000002889554: add    $0x6,%edx
  0x0000000002889557: mov    %r11d,%r9d
  0x000000000288955a: add    $0x2,%r9d
  0x000000000288955e: shl    $0x2,%r8d
  0x0000000002889562: mov    %r8d,%r11d
  0x0000000002889565: add    $0x4,%r11d
  0x0000000002889569: mov    %ecx,%r8d
  0x000000000288956c: jmp    0x0000000002889533
  0x000000000288956e: mov    %esi,%r10d
  0x0000000002889571: add    $0xfffffff1,%r10d
  0x0000000002889575: mov    $0x80000000,%r11d
  0x000000000288957b: cmp    %r10d,%esi
  0x000000000288957e: cmovl  %r11d,%r10d
  0x0000000002889582: cmp    %r10d,%ecx
  0x0000000002889585: jge    0x00000000028895bc
  0x0000000002889587: sub    %r9d,%edx
  0x000000000288958a: nopw   0x0(%rax,%rax,1)   ;*aload_2
                                                ; - Chaining::runUnChained@18 (line 60)

  0x0000000002889590: mov    %ecx,%r11d
  0x0000000002889593: shl    %r11d
  0x0000000002889596: mov    %ecx,%r8d
  0x0000000002889599: shl    $0x2,%r8d
  0x000000000288959d: add    %r8d,%r11d
  0x00000000028895a0: add    %edx,%r11d         ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runUnChained@19 (line 60)

  0x00000000028895a3: mov    %r11d,%edi
  0x00000000028895a6: add    $0x60,%edi         ;*iadd
                                                ; - ChainD::doSomething3@6 (line 25)
                                                ; - Chaining::runUnChained@27 (line 62)

  0x00000000028895a9: add    $0x5a,%r11d
  0x00000000028895ad: mov    %r11d,0xc(%rbx)
  0x00000000028895b1: mov    %edi,0xc(%rbx)     ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runUnChained@27 (line 62)

  0x00000000028895b4: add    $0x10,%ecx         ;*iinc
                                                ; - Chaining::runUnChained@30 (line 58)

  0x00000000028895b7: cmp    %r10d,%ecx
  0x00000000028895ba: jl     0x0000000002889590  ;*getfield result
                                                ; - ChainD::doSomething1@2 (line 23)
                                                ; - Chaining::runUnChained@19 (line 60)

  0x00000000028895bc: cmp    %esi,%ecx
  0x00000000028895be: jge    0x0000000002889606
  0x00000000028895c0: mov    %ecx,%r11d
  0x00000000028895c3: shl    $0x2,%r11d
  0x00000000028895c7: mov    %ecx,%r8d
  0x00000000028895ca: shl    %r8d
  0x00000000028895cd: mov    %r8d,%r9d
  0x00000000028895d0: add    %r11d,%r9d
  0x00000000028895d3: sub    %r9d,%edi
  0x00000000028895d6: xchg   %ax,%ax            ;*aload_2
                                                ; - Chaining::runUnChained@18 (line 60)

  0x00000000028895d8: add    %r8d,%r11d
  0x00000000028895db: add    %edi,%r11d
  0x00000000028895de: add    $0x6,%r11d
  0x00000000028895e2: mov    %r11d,0xc(%rbx)    ;*putfield result
                                                ; - ChainD::doSomething3@7 (line 25)
                                                ; - Chaining::runUnChained@27 (line 62)

  0x00000000028895e6: mov    %ecx,%edx
  0x00000000028895e8: inc    %edx               ;*iinc
                                                ; - Chaining::runUnChained@30 (line 58)

  0x00000000028895ea: cmp    %esi,%edx
  0x00000000028895ec: jge    0x0000000002889606
  0x00000000028895ee: mov    %ecx,%r11d
  0x00000000028895f1: shl    $0x2,%r11d
  0x00000000028895f5: shl    %ecx
  0x00000000028895f7: add    $0x4,%r11d
  0x00000000028895fb: mov    %ecx,%r8d
  0x00000000028895fe: add    $0x2,%r8d
  0x0000000002889602: mov    %edx,%ecx
  0x0000000002889604: jmp    0x00000000028895d8  ;*if_icmpge
                                                ; - Chaining::runUnChained@15 (line 58)

  0x0000000002889606: add    $0x20,%rsp
  0x000000000288960a: pop    %rbp
  0x000000000288960b: test   %eax,-0x26c9611(%rip)        # 0x00000000001c0000
                                                ;   {poll_return}
  0x0000000002889611: retq   
  0x0000000002889612: mov    $0xfffffff6,%edx
  0x0000000002889617: callq  0x00000000027b7320  ; OopMap{off=284}
                                                ;*invokevirtual getB
                                                ; - Chaining::runUnChained@1 (line 57)
                                                ;   {runtime_call}
  0x000000000288961c: int3                      ;*invokevirtual getB
                                                ; - Chaining::runUnChained@1 (line 57)

  0x000000000288961d: mov    $0xfffffff6,%edx
  0x0000000002889622: nop
  0x0000000002889623: callq  0x00000000027b7320  ; OopMap{off=296}
                                                ;*invokevirtual getC
                                                ; - Chaining::runUnChained@4 (line 57)
                                                ;   {runtime_call}
  0x0000000002889628: int3                      ;*invokevirtual getC
                                                ; - Chaining::runUnChained@4 (line 57)

  0x0000000002889629: mov    $0xfffffff6,%edx
  0x000000000288962e: nop
  0x000000000288962f: callq  0x00000000027b7320  ; OopMap{off=308}
                                                ;*invokevirtual getD
                                                ; - Chaining::runUnChained@7 (line 57)
                                                ;   {runtime_call}
  0x0000000002889634: int3                      ;*invokevirtual getD
                                                ; - Chaining::runUnChained@7 (line 57)

  0x0000000002889635: mov    $0xffffff86,%edx
  0x000000000288963a: mov    %ebx,%ebp
  0x000000000288963c: mov    %r8d,(%rsp)
  0x0000000002889640: data32 xchg %ax,%ax
  0x0000000002889643: callq  0x00000000027b7320  ; OopMap{rbp=NarrowOop off=328}
                                                ;*aload_2
                                                ; - Chaining::runUnChained@18 (line 60)
                                                ;   {runtime_call}
  0x0000000002889648: int3                      ;*aload_2
                                                ; - Chaining::runUnChained@18 (line 60)

  0x0000000002889649: hlt    
  0x000000000288964a: hlt    
  0x000000000288964b: hlt    
  0x000000000288964c: hlt    
  0x000000000288964d: hlt    
  0x000000000288964e: hlt    
  0x000000000288964f: hlt    
  0x0000000002889650: hlt    
  0x0000000002889651: hlt    
  0x0000000002889652: hlt    
  0x0000000002889653: hlt    
  0x0000000002889654: hlt    
  0x0000000002889655: hlt    
  0x0000000002889656: hlt    
  0x0000000002889657: hlt    
  0x0000000002889658: hlt    
  0x0000000002889659: hlt    
  0x000000000288965a: hlt    
  0x000000000288965b: hlt    
  0x000000000288965c: hlt    
  0x000000000288965d: hlt    
  0x000000000288965e: hlt    
  0x000000000288965f: hlt    
[Exception Handler]
[Stub Code]
  0x0000000002889660: jmpq   0x00000000028694a0  ;   {no_reloc}
[Deopt Handler Code]
  0x0000000002889665: callq  0x000000000288966a
  0x000000000288966a: subq   $0x5,(%rsp)
  0x000000000288966f: jmpq   0x00000000027b6f40  ;   {runtime_call}
  0x0000000002889674: hlt    
  0x0000000002889675: hlt    
  0x0000000002889676: hlt    
  0x0000000002889677: hlt    

By comparing the outputs, it can be seen that they are essentially equal. The calls have been inlined in both cases.

One could now argue that the doSomething methods are so trivial that they have been inlined as well, and the results may be different for more complex doSomething methods. This may be true. But a quick test with a method like

int doSomething(int i)
{
    List<Integer> list = new ArrayList<Integer>(
        Arrays.asList(1,2,3,4,5,6,7,8,9,10));
    Collections.sort(list);
    return list.get(i);
}

shows that the actual inlining of the chained calls still happen, and when the "inner" methods become even more complex, any potential overhead that might occur due to the chained calls will become negligible compared to what is done in the doSomething method.

Eric
  • 6,563
  • 5
  • 42
  • 66
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • This code isn't error-prone if you put each method invocation on its own line. Additionally, if you are using JDK 15 or higher it will tell you which variable is `null`, https://openjdk.org/jeps/358 – Eric Aug 07 '22 at 02:02
0

What is "slow"?

Obviously slower than reading the value of a local variable, but other than that, method calls are very fast and you shouln't be concerned about that.

On the other hand, chaining like A.getB().getC().getD().doSomething1() screams for a refactoring. At least add a new method in class A which returns D or calls doSomething1() directly.

icza
  • 389,944
  • 63
  • 907
  • 827
0

Each method call, operation, assignment, or most anything else is a tick against the processor. The example you provided may run quite fast; but each tick against the processor will start to slow it down. Game developers are very concerned with this because they need to be able to keep their frame rate up; but general and business applications aren't concerned with that as much.

The point: chaining will start affect performance if there's a lot of them or the chained methods have to do a lot of work.

Richard Barker
  • 1,161
  • 2
  • 12
  • 30