variables 자바 - Java에서 지역 변수가 초기화되지 않는 이유는 무엇입니까?




전역변수 필드 (12)

Java 디자이너가 로컬 변수에 기본값을주지 않아야한다고 생각한 이유가 있었습니까? 진실로 인스턴스 변수에 기본값을 주면 로컬 변수에 대해서도 같은 일을 할 수없는 이유는 무엇입니까?

그리고 그것은 또한 이 논평에서 블로그 포스트에 설명 된 바와 같이 문제를 일으킨다.

이 규칙은 finally 블록에서 리소스를 닫으려고 할 때 가장 좌절합니다. try 내부에서 리소스를 인스턴스화하지만 finally 내에서 리소스를 닫으려고하면이 오류가 발생합니다. 시도 밖에서 인스턴스화를 이동하면 시도가 있어야한다는 또 다른 오류가 표시됩니다.

매우 실망합니다.


Answers

나는 2 가지 이유를 생각할 수 있었다.

  1. 대부분의 해답은 지역 변수를 초기화하는 제약 조건을 넣어서 프로그래머가 원하는대로 지역 변수에 값을 할당하고 예상 결과가 계산되도록 보장합니다.
  2. 인스턴스 변수는 로컬 변수 (같은 이름)를 선언하여 숨길 수 있습니다. 예상되는 동작을 보장하기 위해 로컬 변수가 초기화되어야합니다. (비록 이것을 완전히 피할 것인가?)

귀하의 질문에 대한 실제 답변은 메서드 변수가 단순히 스택 포인터에 숫자를 추가하여 인스턴스화되기 때문입니다. 그것들을 0으로 만드는 것은 추가 단계 일 것입니다. 클래스 변수의 경우 힙의 초기화 된 메모리에 저장됩니다.

왜 여분의 조치를 취하지 않습니까? 한발 뒤로 물러서십시오 - 아무도이 경우의 "경고"가 아주 좋은 것이라고 언급하지 않았습니다.

첫 번째 패스에서 변수를 0이나 null로 초기화해서는 안됩니다 (처음 코딩 할 때). 당신이 진짜로 망쳐 놓았을 때 java가 당신에게 말할 수 있기 때문에 실제 값에 할당하거나 전혀 할당하지 마십시오. Electric Monk의 대답을 좋은 예라고 생각하십시오. 첫 번째 경우에는 SomeObject의 생성자가 예외를 던져서 try ()가 실패하면 finally에 NPE가 끝날 것임을 알리는 것이 실제로 놀랍도록 유용합니다. 생성자가 예외를 throw 할 수 없으면 try에 없어야합니다.

이 경고는 모든 경로를 검사하고 어떤 경로에서 변수를 사용한 경우 모든 경로에서 그 경로로 초기화해야한다는 것을 확인하기 때문에 나에게 어리석은 일을하지 않게 해주는 멋진 다중 경로 나쁜 프로그래머 검사기입니다 . 변수를 올바르게 초기화 할 때까지 명시 적으로 변수를 초기화하지 않습니다.

그 위에, "int size"보다는 "int size = 0"을 명시 적으로 말하고 다음 프로그래머가 당신이 0이 될 것이라고 생각하게 만드는 것이 낫지 않습니까?

플립 측면에서 컴파일러가 초기화되지 않은 모든 변수를 0으로 초기화하게하는 유효한 이유가 하나도 없습니다.


최종 인스턴스 / 멤버 변수는 기본적으로 초기화되지 않습니다. 그것들은 최종적이며 나중에 프로그램에서 변경할 수 없기 때문입니다. 그것이 자바가 그들에게 어떤 디폴트 값도주지 않고 프로그래머가 그것을 초기화하도록 강요하는 이유이다.

반면에 비 최종 멤버 변수는 나중에 변경할 수 있습니다. 따라서 컴파일러는 나중에 변경할 수 있기 때문에 초기화되지 않은 상태로 두지 않습니다. 지역 변수에 대해서는 지역 변수의 범위가 훨씬 좁습니다. 컴파일러는 언제 사용되는지 알고 있습니다. 따라서 프로그래머가 변수를 초기화하도록하는 것이 합리적입니다.


지역 변수는 스택에 저장되지만 인스턴스 변수는 힙에 저장되므로 힙에서 발생하는 기본값 대신 스택의 이전 값을 읽을 수있는 기회가 있습니다. 이런 이유로 jvm은 초기화하지 않고 로컬 변수를 사용할 수 없습니다.


Eclipse는 심지어 초기화되지 않은 변수에 대한 경고를 제공하기 때문에 어쨌든 분명합니다. 개인적으로 이것이 기본 동작이라고 생각합니다. 그렇지 않으면 응용 프로그램에서 예기치 않은 값을 사용할 수 있습니다. 컴파일러가 오류를 발생시키지 않고 아무 것도하지 않지만 경고를 표시합니다. 그러면 긁적입니다. 왜 어떤 것들은 그들이해야하는 것처럼 행동하지 않는가에 대한 당신의 머리.


게다가, 아래의 예에서 SomeObject 구조체 내에 예외가 발생했을 수 있습니다.이 경우 'so'변수는 null이 될 것이고 CleanUp에 대한 호출은 NullPointerException을 던집니다

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

제가하는 일은 이것입니다 :

SomeObject so = null;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  if (so != null) {
     so.CleanUp(); // safe
  }
}

링크 된 "문제" 는이 상황을 설명하는 것 같습니다.

SomeObject so;
try {
  // Do some work here ...
  so = new SomeObject();
  so.DoUsefulThings();
} finally {
  so.CleanUp(); // Compiler error here
}

주석 기자의 불만은 컴파일러가 finally 섹션의 줄을 보면서 초기화되지 않았을 수 있다고 주장하는 so 입니다. 그런 다음 주석은 코드를 작성하는 다른 방법을 언급합니다. 아마도 다음과 같습니다.

// Do some work here ...
SomeObject so = new SomeObject();
try {
  so.DoUsefulThings();
} finally {
  so.CleanUp();
}

주석 작성자는 해당 솔루션에 만족하지 않습니다. 왜냐하면 컴파일러는 코드가 "try 내에 있어야합니다"라고 말하기 때문입니다. 아마 일부 코드가 더 이상 처리되지 않는 예외를 발생시킬 수 있음을 의미합니다. 나는 잘 모르겠다. 내 코드의 어떤 버전도 예외를 처리하지 않으므로 첫 번째 버전에서는 예외와 관련된 모든 것이 두 번째 버전에서도 동일하게 작동해야합니다.

어쨌든이 두 번째 코드는 올바른 방법입니다. 첫 번째 버전에서는 컴파일러의 오류 메시지가 정확했습니다. so 변수는 초기화되지 않을 수 있습니다. 특히 SomeObject 생성자가 실패하면 초기화되지 않으므로 so.CleanUp 을 호출하려고하면 오류가 발생합니다. finally 섹션이 완료되는 자원을 얻은 후에 는 항상 try 섹션 입력하십시오.

so 초기화 후 try - finally 블록은 SomeObject 인스턴스를 보호하기 위해서만 존재합니다. 다른 어떤 일이 발생하더라도 정리가 완료되도록합니다. 실행할 필요가있는 다른 것들이 있지만 SomeObject 인스턴스가 할당 된 속성인지 여부와 관련이 없다면 다른 try - finally 블록에 있어야합니다. 아마 하나의 예제를 래핑 한 것일 것입니다.

사용하기 전에 수동으로 변수를 지정해야 실제 문제가 발생하지 않습니다. 사소한 번거 로움 만 가져 오지만 코드가 더 좋을 것입니다. 범위가 제한적인 변수를 사용하고 너무 많이 보호하려고 시도하지 않는 try 블록을 사용합니다.

로컬 변수에 기본값이 있으면 첫 번째 예에서 null 이되었습니다. 그것은 실제로 아무 것도 해결하지 못했을 것입니다. finally 블록에서 컴파일 타임 오류가 발생하는 대신 코드의 "여기에서 일부 작업을 수행하십시오"섹션에서 발생할 수있는 다른 예외를 숨길 수있는 NullPointerException 숨어있을 수 있습니다. (또는 finally 섹션의 예외는 자동으로 이전 예외와 연계됩니까? 기억이 안납니다. 그렇더라도 실제 예외의 예외가 있습니다.)


기본 목적은 C / C ++과의 유사성을 유지하는 것이 었습니다. 그러나 컴파일러는 문제를 최소화하기 위해 초기화되지 않은 변수를 사용하는 것을 감지하고 경고합니다. 성능 관점에서 컴파일러는 다음 문에서 변수의 값을 덮어 쓰더라도 할당 문을 작성할 필요가 없기 때문에 초기화되지 않은 변수를 선언 할 수있게하려면 약간 빠릅니다.


지역 변수는 주로 계산을 위해 선언됩니다. 따라서 프로그래머가 변수의 값을 설정하기로 결정하고 기본값을 사용하지 않아야합니다. 프로그래머가 실수로 로컬 변수를 초기화하지 않고 기본값을 사용하면 예기치 않은 값이 될 수 있습니다. 따라서 지역 변수의 경우 컴파일러는 정의되지 않은 값의 사용을 피하기 위해 변수에 액세스하기 전에 프로그래머에게 어떤 값으로 초기화하도록 요청할 것입니다.


(질문 후에 오랫동안 새로운 답변을 게시하는 것이 이상하게 보일 수 있지만 duplicate 이 나타납니다.)

나에게 이유 는 다음과 같다. 지역 변수의 목적은 인스턴스 변수의 목적과 다르다. 지역 변수는 계산의 일부로 사용됩니다. 인스턴스 변수는 상태를 포함합니다. 로컬 변수에 값을 지정하지 않고 사용하면 거의 확실하게 논리 오류가 발생합니다.

즉, 인스턴스 변수가 항상 명시 적으로 초기화되도록 요구할 수 있습니다. 결과는 초기화되지 않은 인스턴스 변수를 허용하는 모든 생성자에서 발생합니다 (예 : 선언에서 초기화되지 않고 생성자에서 초기화되지 않음). 그러나 그것은 Gosling, et. 알., 90 년대 초반에 찍은, 그래서 여기에 우리가 있습니다. (그리고 나는 그들이 잘못된 전화를 한 것은 아니다.)

하지만 로컬 변수를 기본값으로 되돌릴 수는 없었 습니다. 예, 우리는 논리를 재확인하기 위해 컴파일러에 의존해서는 안되며 컴파일러가 논리를 재확인 할 때 유용합니다. :-)


대답은 클래스 생성자 또는 클래스 메서드에서 인스턴스 변수를 초기화 할 수 있다는 것입니다. 그러나 로컬 변수의 경우 클래스에서 영원히 유지되는 메서드에서 무엇이든 정의한 경우


Java 9

다른 IntStream.iterateIntStream.takeWhile 메서드 사용 :

int[] a = IntStream.iterate(10, x -> x <= 100, x -> x + 10).toArray();

Out: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]


int[] b = IntStream.iterate(0, x -> x + 1).takeWhile(x -> x < 10).toArray();

Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

자바 10

지역 변수 유형 추론 사용하기 :

var letters = new String[]{"A", "B", "C"};




java variables initialization