2013-01-04 5 views
3

Java에서 중첩 된 get 값을 지속적으로 사용하면 성능이 저하됩니까?중첩 된 성능 얻기

String firstname = getOffice().getDepartment().getEmployee().getFirstName(); 
String lastname = getOffice().getDepartment().getEmployee().getLastName(); 
String address = getOffice().getDepartment().getEmployee().getAddress(); 

VS : 예를 들어 덜이있다 '점프'때문에

Employee e = getOffice().getDepartment().getEmployee(); 
String firstname = e.getFirstName(); 
String lastname = e.getLastName(); 
String address = e.getAddress(); 

는 2 버전은 더 빠를까요?

+1

찾고있는 단어가 '연결됨'입니다. 중첩은 다른 사람의 컨텍스트 내에서 하나의 일이 발생하고 있음을 의미합니다. – Perception

답변

9

getXYZ 전화 번호는 입니다.입니다. 기본 필드에 대한 간단한 접근자인 경우 HotSpot (Oracle JVM)이 아닌 필요에 따라 최적화 된 상태가되기 때문에 최적화되지 않습니다. 반면에, 그들이 어떤 종류의 복잡한 작업 (btree 등을 가로 지르는)을한다면, 물론 HotSpot이 호출이 멱등수임을 증명할 수 없다면, 그들은 반복해서 작업을해야 할 것입니다. 코드는 복잡하지 않을 것입니다).

을하지만, 두 번째는 훨씬 더 읽기 쉽고 유지 보수입니다 (당신이 실제 성능 문제를 참조하지 않는 한, 그것에 대해 걱정하지 마십시오/때까지. 그것은 여부가 반복 작업이 또 다른 질문 할을 중요). 그것이 그것을 사용하는 가장 강력한 이유입니다.

4

성능보다는 내가 second as better human understandable code을 참조하십시오. 마이크로 최적화에 대해서는 걱정하지 말고 훌륭하고 깨끗한 코드를 작성하십시오.

0

가능합니다. 그러나 getters가 내부의 일반 게터처럼 보이면 너무 작아서 측정하기가 거의 불가능해질 것입니다.

또한이 코드를 자주 실행하여 핫스팟 컴파일러의 마법을 사용하면 바이트 코드가 실행되어 양쪽 변형을 동일하게 만들 수 있습니다.

결국 실제로 일어날 일을 말하기가 매우 어렵습니다. 성능 문제가있는 경우 테스트를 설정하십시오. 성능이 테스트 비용을 정당화 할 정도로 중요하지 않다면 ... 걱정하지 않아도됩니다.

2

사용자가 생각하는 최적화는 premature optimization입니다. 당신이 정말로해야하지 않는 한 당신은 이것에 대해 생각하지 않아야합니다.

저는 제 2의 가독성에 관한 @ AmitD의 대답에 동의합니다. 방법을 체인하는 것은 다음과 같이 호출 할 때, 당신은 또한 다음과 같은 방법을 쓸 수 있습니다 -

Employee e = getOffice() 
       .getDepartment() 
       .getEmployee(); 
String firstname = e.getFirstName(); 
String lastname = e.getLastName(); 
String address = e.getAddress(); 

더 가독성을 향상 할 수 있습니다.

+2

조기 최적화 참조 용 +1 – Krease

0

바이트 코드 분석을 사용하거나 System.nanoTime을 사용하여 두 가지 접근 방식을 사용하십시오. 나는 두 번째 것이 빠르다고 생각한다. 여기에 나는이 결론 짓입니다 :

public static class A { 
    public B b = new B(); 
} 

public static class B { 
    public E e = new E(); 
} 

public static class E { 
    public String name = "s"; 
    public int age = 1; 
} 

그런 다음 나는 두 가지 간단한 방법을 쓰고 javap -c CLASS_NAME를 사용하여 자바 바이트 코드를 얻을 : 아래로

나는 세 가지 클래스를 썼다.

public static void Test1() { 
    A a = new A(); 
    String str = a.b.e.name; 
    int age = a.b.e.age; 
} 

위의 방법의 바이트 코드는 다음과 같습니다

public static void Test1(); 
    Code: 
     // new A(); 
     0: new   #15 
     3: dup   
     4: invokespecial #17     
     7: astore_0  
     8: aload_0 

     // a.b (it accesses the field and put it on operand stack) 
     9: getfield  #18 

     // b.e 
     12: getfield  #22 

     // b.name 
     15: getfield  #28 

     // pop 'name' from stack 
     18: astore_1  
     19: aload_0 

     // cyle continues  
     20: getfield  #18 
     23: getfield  #22 
     26: getfield  #34 
     29: istore_2  
     30: return 

당신은, 바이트 코드 수준에서이 필드를 사용할 때마다 명확하게 볼 수 있습니다, 그것은 그 값을 넣어 스택에 제출하고 이주기는 계속됩니다. 따라서 a.a1.a2....an은 스택에 모두 n을 보유하기에 충분한 양의 스페이서가있는 경우 n 명령어가됩니다. 그리고 컴파일러는이 같은 사이클을 호출하여 nameage 필드에 모두 액세스했습니다. 인 상기 방법

public static void Test2() { 
     A a = new A(); 
     E e = a.b.e; 
     String str = e.name; 
     int age = e.age; 
    } 

바이트 코드 : 그것은 getfield의 실행을 방지로서

public static void Test2(); 
    Code: 
     // new A(); 
     0: new   #15 
     3: dup   
     4: invokespecial #17 
     7: astore_0  
     8: aload_0  

     // store a.b.e on operand stack once 
     9: getfield  #18 
     12: getfield  #22 
     15: astore_1  
     16: aload_1 

     // get 'name' field 
     17: getfield  #28 
     20: astore_2  
     21: aload_1  
     // get 'age' field 
     22: getfield  #34 
     25: istore_3  
     26: return   

위의 이전 코드보다 4 명령 짧은

이제 여기에서 두 번째 방법이다. 그래서 이전의 것보다 더 빠르다고 생각합니다.

+0

노력에 대한 와우. 그 꽤 눈을 뜨게한다. – delita

+0

그러나 바이트 코드는 그 이야기의 일부일뿐입니다. JVM은 런타임에이를 변경할 수 있습니다. 오라클의 JVM (HotSpot)은 많이 사용되는 부품 (핫스팟)을 식별하고 적극적으로 최적화합니다. 가장 간단하고 쉬운 방법 중 하나는 간단한 접근자를 인라인하는 것입니다. –