루프 내부 또는 외부에서 변수 선언


236

다음은 왜 잘 작동합니까?

String str;
while (condition) {
    str = calculateStr();
    .....
}

그러나 이것은 위험하거나 부정확하다고합니다.

while (condition) {
    String str = calculateStr();
    .....
}

루프 외부에서 변수를 선언해야합니까?

답변:


289

지역 변수의 범위는 항상 가장 작아야합니다.

당신의 예에서 I의 가정이 str되어 하지 의 외부 사용 while내부를 선언하기 때문에, 그렇지 않으면 당신은 질문을 할 수없는 것, 루프를 while반복하는 것은 옵션이 될 수없는 것입니다은 컴파일되지 것이기 때문이다.

따라서, 이후는 str되어 있지 가장 작은 가능한 범위는 루프 밖에 사용 str이다 내에 While 루프.

그래서, 대답은 단호 것을 str절대적으로 while 루프 내에서 선언되어야한다. if, no ands, no buts는 없습니다.

이 규칙을 위반할 수있는 유일한 경우는 어떤 이유로 든 모든 클럭 사이클을 코드에서 짜 내야하는 것이 매우 중요한 경우입니다. 내부 범위의 모든 반복에서 다시 인스턴스화합니다. 그러나 이것은 자바에서 문자열의 불변성으로 인해 예제에 적용되지 않습니다 : str의 새로운 인스턴스는 항상 루프의 시작 부분에 생성되며 마지막에 버려 져야합니다. 거기에서 최적화 할 가능성이 없습니다.

편집 : (아래 답변에 내 의견을 주입)

어쨌든 올바른 작업을 수행하는 모든 방법은 모든 코드를 올바르게 작성하고, 제품의 성능 요구 사항을 설정하고,이 요구 사항에 대해 최종 제품을 측정 한 후 만족하지 않으면 작업을 최적화하는 것입니다. 그리고 일반적으로 발생하는 것은 전체 코드 기반을 다룰 필요없이 프로그램의 성능 요구 사항을 충족시키는 몇 곳에서 멋지고 공식적인 알고리즘 최적화를 제공하는 방법을 찾는 것입니다. 여기저기서 클럭 사이클을 짜기 위해.


2
마지막 단락에 대한 쿼리 : 변경되지 않은 다른 문자열 인 경우 영향을 미칩니 까?
Harry Joy

1
@HarryJoy 예, 물론 StringBuilder를 예로들 수 있습니다. StringBuilder를 사용하여 루프의 각 반복에서 새 문자열을 작성하는 경우 루프 외부에 StringBuilder를 할당하여 사물을 최적화 할 수 있습니다. 그러나 여전히 이것은 바람직한 관행이 아닙니다. 정당한 이유없이이 작업을 수행하면 조기 최적화입니다.
Mike Nakis

7
@HarryJoy 일을하는 올바른 방법은 모든 코드를 올바르게 작성 하고 , 제품의 성능 요구 사항을 설정하고,이 요구 사항에 대해 최종 제품을 측정 한 다음 만족하지 않으면 작업을 최적화하는 것입니다. 그리고 당신은 무엇을 알고 있습니까? 일반적으로 코드 사이클 전체를 여기 저기 짜내기 위해 코드 전체를 살펴보고 해킹하는 대신 트릭을 수행하는 몇 곳에서 멋지고 공식적인 알고리즘 최적화를 제공 할 수 있습니다.
Mike Nakis

2
@ MikeNakis 나는 당신이 매우 좁은 범위에서 생각하고있는 것입니다.
Siten

5
현대 멀티 기가 헤르츠, 멀티 코어, 파이프 라인, 멀티 레벨 메모리 캐시 CPU를 통해 클럭 사이클에 대한 걱정없이 다음과 같은 모범 사례에 집중할 수 있습니다. 더욱이, 최적화는 그것이 필요하다고 결정된 경우 에만 권장 되며, 필요할 때 고도로 지역화 된 조정이 원하는 성능을 달성 할 것이므로 모든 코드를 낭비 할 필요가 없습니다. 성능 이름에 작은 해킹이 있습니다.
Mike Nakis

293

그 두 가지 (유사한) 예제의 바이트 코드를 비교했습니다.

1을 보자 . 예제 :

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

javac Test.java, javap -c Test당신은 얻을 것이다 :

public class inside.Test extends java.lang.Object{
public inside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

2를 보자 . 예제 :

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

javac Test.java, javap -c Test당신은 얻을 것이다 :

public class outside.Test extends java.lang.Object{
public outside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

관찰 결과는이 두 예 사이에 차이없음을 보여줍니다 . JVM 사양의 결과입니다 ...

그러나 최상의 코딩 방법의 이름으로 가능한 가장 작은 범위에서 변수를 선언하는 것이 좋습니다 (이 예제에서는 변수가 사용되는 유일한 위치이므로 루프 내부에 있음).


3
'컴파일러 최적화'가 아닌 JVM Soecification의 결과입니다. 메소드에 필요한 스택 슬롯은 모두 메소드 시작시 할당됩니다. 이것이 바이트 코드가 지정되는 방식입니다.
Lorne의 후작

2
@Arhimed는 루프 (또는 '{}'블록) 안에 넣을 이유가 하나 더 있습니다. 다른 범위에서 변수를 초과 선언하면 컴파일러는 스택 프레임에 할당 된 메모리를 다른 범위의 변수에 재사용합니다 .
Serge

1
데이터 객체 목록을 통해 반복되는 경우 대량의 데이터에 차이가 있습니까? 아마 40 만명.
Mithun Khatri

7
당신의 들어 final연인 선언 str으로 final에서 inside패키지의 경우 차이가 없습니다 =)
skia.heliou

27

가장 작은 범위 에서 객체를 선언 하면 가독성이 향상 됩니다.

오늘날의 컴파일러에는 성능이 중요하지 않습니다. (이 시나리오에서는)
유지 관리 측면에서 두 번째 옵션이 더 좋습니다.
가능한 가장 좁은 범위에서 같은 장소에서 변수를 선언하고 초기화하십시오.

Donald Ervin Knuth 는 다음과 같이 말했습니다.

"우리는 시간의 97 % 정도의 작은 효율성을 잊어야합니다. 조기 최적화는 모든 악의 근원입니다"

즉, 프로그래머가 성능 고려 사항 이 코드 의 설계 에 영향을 미치는 상황 . 입니다 디자인이 발생할 수 있습니다 깨끗하지 가 있었을으로 또는 코드가 있기 때문에, 잘못된 코드 복잡 의해 최적화 및 프로그래머가 산만 최적화 .


1
"두 번째 옵션의 성능이 약간 빠릅니다" => 측정 했습니까? 답 중 하나에 따르면 바이트 코드는 동일하므로 성능이 어떻게 다른지 알 수 없습니다.
assylias

죄송하지만 Java 프로그램의 성능을 테스트하는 올바른 방법은 아닙니다 (어쨌든 무한 루프의 성능을 어떻게 테스트 할 수 있습니까?)
assylias

다른 요점에 동의합니다. 성능 차이가 없다고 생각합니다.
assylias

11

str외부 루프도 사용하려면 ; 밖에 선언하십시오. 그렇지 않으면 두 번째 버전이 좋습니다.


11

업데이트 된 답변으로 건너 뛰십시오 ...

성능에 관심이있는 사람들은 System.out을 꺼내고 루프를 1 바이트로 제한하십시오. 이중 (테스트 1/2) 및 문자열 (3/4)을 사용하여 경과 시간 (밀리 초)은 Windows 7 Professional 64 비트 및 JDK-1.7.0_21에서 아래에 제공됩니다. 바이트 코드 (test1 및 test2에 대해 아래에 제공됨)는 동일하지 않습니다. 나는 가변적이고 비교적 복잡한 객체로 테스트하기에는 너무 게으르다.

더블

테스트 1 소요 : 2710 밀리 초

Test2 소요 : 2790 msecs

문자열 (테스트에서 double을 문자열로 대체하십시오)

Test3 소요 : 1200msec

Test4 소요 : 3000msec

바이트 코드 컴파일 및 가져 오기

javac.exe LocalTest1.java

javap.exe -c LocalTest1 > LocalTest1.bc


public class LocalTest1 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        double test;
        for (double i = 0; i < 1000000000; i++) {
            test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }

}

public class LocalTest2 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        for (double i = 0; i < 1000000000; i++) {
            double test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }
}


Compiled from "LocalTest1.java"
public class LocalTest1 {
  public LocalTest1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore        5
       7: dload         5
       9: ldc2_w        #3                  // double 1.0E9d
      12: dcmpg
      13: ifge          28
      16: dload         5
      18: dstore_3
      19: dload         5
      21: dconst_1
      22: dadd
      23: dstore        5
      25: goto          7
      28: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      31: lstore        5
      33: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: new           #6                  // class java/lang/StringBuilder
      39: dup
      40: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      43: ldc           #8                  // String Test1 Took:
      45: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: lload         5
      50: lload_1
      51: lsub
      52: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      55: ldc           #11                 // String  msecs
      57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      60: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      63: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: return
}


Compiled from "LocalTest2.java"
public class LocalTest2 {
  public LocalTest2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore_3
       6: dload_3
       7: ldc2_w        #3                  // double 1.0E9d
      10: dcmpg
      11: ifge          24
      14: dload_3
      15: dstore        5
      17: dload_3
      18: dconst_1
      19: dadd
      20: dstore_3
      21: goto          6
      24: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      27: lstore_3
      28: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: new           #6                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      38: ldc           #8                  // String Test1 Took:
      40: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: lload_3
      44: lload_1
      45: lsub
      46: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      49: ldc           #11                 // String  msecs
      51: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

업데이트 된 답변

모든 JVM 최적화와 성능을 비교하는 것은 쉽지 않습니다. 그러나 다소 가능합니다. Google Caliper의 향상된 테스트 및 상세 결과

  1. 블로그에 대한 일부 세부 정보 : 루프 내부 또는 루프 전에 변수를 선언해야합니까?
  2. GitHub 리포지토리 : https://github.com/gunduru/jvdt
  3. 이중 케이스 및 100M 루프 (및 모든 JVM 세부 사항 예)에 대한 테스트 결과 : https://microbenchmarks.appspot.com/runs/b1cef8d1-0e2c-4120-be61-a99faff625b4

1,759.209 전에 선언 내부 2,242.308에 선언

  • 1,759.209ns 이전에 선언 됨
  • 2,242.308 ns 이내 선언

이중 선언을위한 부분 테스트 코드

위 코드와 동일하지 않습니다. 더미 루프 JVM 만 코딩하면 JVM이 건너 뛰므로 적어도 무언가를 할당하고 반환해야합니다. 이는 Caliper 설명서에서도 권장됩니다.

@Param int size; // Set automatically by framework, provided in the Main
/**
* Variable is declared inside the loop.
*
* @param reps
* @return
*/
public double timeDeclaredInside(int reps) {
    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Declaration and assignment */
        double test = i;

        /* Dummy assignment to fake JVM */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

/**
* Variable is declared before the loop.
*
* @param reps
* @return
*/
public double timeDeclaredBefore(int reps) {

    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Actual test variable */
    double test = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Assignment */
        test = i;

        /* Not actually needed here, but we need consistent performance results */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

요약 : 선언 된 BeforeBefore는 더 작은 성능을 나타내며 가장 작은 범위 원칙에 위배됩니다. JVM이 실제로이 작업을 수행해야합니다.


유효하지 않은 테스트 방법이며 결과에 대한 설명을 제공하지 않습니다.
Lorne의 후작

1
@EJP 주제에 관심이있는 사람들에게는 분명해야합니다. 보다 유용한 정보를 제공하기 위해 PrimosK의 답변에서 방법론을 가져 왔습니다. 솔직히이 답변을 개선하는 방법을 모르겠습니다. 편집을 클릭하고 올바르게 수행하는 방법을 알려주십시오.
Onur Günduru

2
1) Java Bytecode는 런타임에 최적화 (재정렬, 축소 등)되므로 .class 파일에 너무 많이 쓰여지는 것을 신경 쓰지 마십시오. 2) 1.000.000.000의 런이있어 2.8 초의 성능 승리를 얻으므로 런당 약 2.8ns는 안전하고 적절한 프로그래밍 스타일입니다. 나를위한 확실한 승자. 3) 예열에 대한 정보를 제공하지 않으므로 타이밍이 매우 쓸모가 없습니다.
하드 코딩 됨

@ 더블 및 100M 루프에 대해서만 캘리퍼를 사용한 더 나은 테스트 / 마이크로 벤치마킹. 다른 사례를 원할 경우 온라인 결과를 자유롭게 편집하십시오.
Onur Günduru

고마워, 이것은 1)과 3) 지점을 제거합니다. 그러나 시간이 사이클 당 ~ 5ns까지 올라간 경우에도 여전히 무시해야 할 시간입니다. 이론 상으로는 최적화 가능성이 작습니다. 실제로주기 당 수행하는 작업은 일반적으로 훨씬 비쌉니다. 따라서 몇 분 또는 몇 시간 동안 잠재적으로 최대 몇 초가됩니다. 이러한 낮은 수준의 최적화에 시간을 보내기 전에 확인해야 할 가능성이 더 높은 다른 옵션 (예 : 포크 / 조인, 병렬 스트림)이 있습니다.
하드 코드 됨

7

이 문제에 대한 한 가지 해결책은 while 루프를 캡슐화하는 변수 범위를 제공하는 것입니다.

{
  // all tmp loop variables here ....
  // ....
  String str;
  while(condition){
      str = calculateStr();
      .....
  }
}

외부 범위가 끝나면 자동으로 참조 해제됩니다.


6

내부에서는 변수의 범위가 적을수록 더 좋습니다.


5

strafter while 루프 (범위 관련) 를 사용할 필요가 없으면 두 번째 조건 즉

  while(condition){
        String str = calculateStr();
        .....
    }

스택에 객체를 정의하면 conditiontrue 인 경우에만 더 좋습니다 . 즉, 필요한 경우 사용 하십시오


2
첫 번째 변형에서도 조건이 거짓이면 객체가 생성되지 않습니다.
Philipp Wendler

@ Phillip : 그렇습니다. 내 잘못이야. 지금 생각하고 있었는데 어떻게 생각하세요?
Cratylus

1
"스택에서 객체 정의"는 Java 세계에서 다소 이상한 용어입니다. 또한 스택에 변수를 할당하는 것은 일반적으로 런타임에 noop이므로 왜 귀찮게합니까? 프로그래머를 돕기 위해 범위를 정하는 것이 진짜 문제입니다.
Philipp Wendler

3

귀하의 질문에 대답하는 가장 좋은 자료는 다음 게시물입니다.

루프 전 또는 루프에서 변수 선언의 차이점은 무엇입니까?

내 이해에 따르면이 것은 언어에 달려 있습니다. IIRC Java는 이것을 최적화하므로 차이는 없지만 JavaScript (예 :)는 루프에서 매번 전체 메모리 할당을 수행합니다 .Java에서는 특히 프로파일 링이 완료되면 두 번째가 더 빨리 실행될 것이라고 생각합니다.


3

많은 사람들이 지적했듯이

String str;
while(condition){
    str = calculateStr();
    .....
}

이다 NOT 이보다 더 :

while(condition){
    String str = calculateStr();
    .....
}

따라서 재사용하지 않는 경우 변수를 범위 밖에서 선언하지 마십시오.


1
아마 이런 식으로 제외 : 링크
Dainius Kreivys

2

wile 루프 외부에서 문자열 str을 선언하면 while 루프 내부 및 외부에서 참조 할 수 있습니다. while 루프 내에서 문자열 str을 선언하면 while 루프 내 에서만 참조 할 있습니다.




1

str변수는 코드 아래에서 실행 된 후에도 사용 가능하고 메모리의 일부 공간을 예약합니다.

 String str;
    while(condition){
        str = calculateStr();
        .....
    }

str변수는 사용할 수 없습니다 또한 메모리에 할당 된 발표 될 예정이다 str코드 아래에 변수입니다.

while(condition){
    String str = calculateStr();
    .....
}

두 번째 것을 확실히 따르면 시스템 메모리가 줄어들고 성능이 향상됩니다.


0

루프 안에서 선언하면 각 변수의 범위가 제한됩니다. 그것은 모두 변수의 범위에서 프로젝트의 요구 사항에 달려 있습니다.


0

사실, 위에서 언급 한 질문은 프로그래밍 문제입니다. 코드를 어떻게 프로그래밍 하시겠습니까? 어디에서 'STR'에 액세스해야합니까? 로컬 변수로 로컬로 사용되는 변수를 선언하지 않아도됩니다. 내가 믿는 프로그래밍의 기초


-1

이 두 예제는 같은 결과를 낳습니다. 그러나 첫 번째는 strwhile 루프 외부 에서 변수 사용을 제공합니다 . 두 번째는 아닙니다.


-1

이 질문의 거의 모든 사람에 대한 경고 : 다음은 루프 내에서 Java 7을 사용하는 컴퓨터에서 쉽게 200 배 느릴 수있는 샘플 코드입니다 (메모리 소비도 약간 다릅니다). 그러나 그것은 범위뿐만 아니라 할당에 관한 것입니다.

public class Test
{
    private final static int STUFF_SIZE = 512;
    private final static long LOOP = 10000000l;

    private static class Foo
    {
        private long[] bigStuff = new long[STUFF_SIZE];

        public Foo(long value)
        {
            setValue(value);
        }

        public void setValue(long value)
        {
            // Putting value in a random place.
            bigStuff[(int) (value % STUFF_SIZE)] = value;
        }

        public long getValue()
        {
            // Retrieving whatever value.
            return bigStuff[STUFF_SIZE / 2];
        }
    }

    public static long test1()
    {
        long total = 0;

        for (long i = 0; i < LOOP; i++)
        {
            Foo foo = new Foo(i);
            total += foo.getValue();
        }

        return total;
    }

    public static long test2()
    {
        long total = 0;

        Foo foo = new Foo(0);
        for (long i = 0; i < LOOP; i++)
        {
            foo.setValue(i);
            total += foo.getValue();
        }

        return total;
    }

    public static void main(String[] args)
    {
        long start;

        start = System.currentTimeMillis();
        test1();
        System.out.println(System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        test2();
        System.out.println(System.currentTimeMillis() - start);
    }
}

결론 : 지역 변수의 크기에 따라 큰 변수는 아니지만 차이가 클 수 있습니다.

때로는 외부 또는 내부 루프가 중요합니다.


1
물론 두 번째는 더 빠르지 만 다른 일을하고 있습니다 : test1은 큰 배열로 많은 Foo-Object를 생성하지만 test2는 그렇지 않습니다. test2는 동일한 Foo 객체를 반복해서 재사용하므로 멀티 스레드 환경에서 위험 할 수 있습니다.
하드 코드 됨

다중 스레드 환경에서 위험한가 ??? 이유를 설명하십시오. 지역 변수에 대해 이야기하고 있습니다. 메소드를 호출 할 때마다 작성됩니다.
rt15

Foo-Object를 데이터를 비동기 적으로 처리하는 오퍼레이션으로 전달하는 경우 데이터를 변경하는 동안 오퍼레이션이 Foo 인스턴스에서 계속 작동 중일 수 있습니다. 부작용을 갖기 위해 멀티 스레드가 필요하지 않습니다. 인스턴스 재사용은 매우 위험하다 그래서 때 당신은 여전히 인스턴스가 누구인지 알 수없는
변경 금지

추신 : setValue 메소드는 bigStuff[(int) (value % STUFF_SIZE)] = value;(2147483649L의 값을보십시오)
하드 코딩

부작용에 대해 말하기 : 방법의 결과를 비교 했습니까?
하드 코딩

-1

물체의 크기도 중요하다고 생각합니다. 내 프로젝트 중 하나에서 응용 프로그램이 메모리 부족 예외를 발생시키는 대형 2 차원 배열을 선언하고 초기화했습니다. 대신 선언을 루프 밖으로 이동하고 모든 반복이 시작될 때 배열을 지 웁니다.


-2

메소드가 널을 리턴 하면 str에서 메소드를 호출하려고 할 위험이 NullPointerException있습니다 .calculateStr()

보다 일반적으로, 널값을 갖는 변수를 사용하지 마십시오 . 그건 그렇고, 클래스 속성에 강합니다.


2
이것은 질문과 관련이 없습니다. NullPointerException (향후 함수 호출시)의 확률은 변수 선언 방법에 따라 달라지지 않습니다.
Desert Ice

1
"그렇게하는 가장 좋은 방법은 무엇입니까?"라는 질문이 있기 때문에 그렇게 생각하지 않습니다. 더 안전한 코드를 선호합니다.
Rémi Doolaeghe

1
(A)의 제로 위험이 있습니다 NullPointerException.에 시도이 코드 경우 return str;는 컴파일 오류가 발생하는 것입니다.
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.