Java 설계자가 지역 변수에 기본값을 부여해서는 안된다고 생각한 이유가 있었습니까? 진지하게, 인스턴스 변수에 기본값이 주어질 수 있다면 왜 우리는 지역 변수에 대해 똑같이 할 수 없습니까?
또한 블로그 게시물에 대한이 댓글 에서 설명한대로 문제가 발생합니다 .
이 규칙은 finally 블록에서 리소스를 닫으려고 할 때 가장 실망 스럽습니다. try 내에서 리소스를 인스턴스화하지만 finally 내에서 닫으려고하면이 오류가 발생합니다. 인스턴스화를 시도 외부로 이동하면 시도 내에 있어야한다는 또 다른 오류가 발생합니다.
매우 실망 스럽습니다.
답변
지역 변수는 대부분 일부 계산을 수행하기 위해 선언됩니다. 따라서 변수의 값을 설정하는 프로그래머의 결정이며 기본값을 사용해서는 안됩니다. 프로그래머가 실수로 로컬 변수를 초기화하지 않았고 기본값을 사용하면 출력이 예상치 못한 값이 될 수 있습니다. 따라서 지역 변수의 경우 컴파일러는 정의되지 않은 값의 사용을 피하기 위해 프로그래머가 변수에 액세스하기 전에 일부 값으로 초기화하도록 요청합니다.
답변
링크 한 “문제” 가이 상황을 설명하는 것 같습니다.
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();
}
댓글 작성자는 컴파일러가 코드가 “시도 내에 있어야합니다”라고 말하기 때문에 해당 솔루션에 만족하지 않습니다. 이는 일부 코드가 더 이상 처리되지 않는 예외를 발생시킬 수 있음을 의미합니다. 잘 모르겠습니다. 내 코드의 두 버전 모두 예외를 처리하지 않으므로 첫 번째 버전에서 예외와 관련된 모든 것이 두 번째 버전에서 동일하게 작동해야합니다.
어쨌든,이 두 번째 버전의 코드는 그것을 작성 하는 올바른 방법입니다. 첫 번째 버전에서는 컴파일러의 오류 메시지가 정확했습니다. so
변수는 초기화되지 않은 될 수 있습니다. 특히 SomeObject
생성자가 실패하면 so
초기화되지 않으므로을 호출하려고하면 오류가 발생합니다 so.CleanUp
. 섹션이 마무리 하는 리소스를 획득 한 후에 는 항상 try
섹션에 들어가십시오 .finally
try
– finally
애프터 블록 so
초기화가 만 입력 금지에 SomeObject
상관없이 다른 일이 무엇인지는 청소 도착하지 않습니다하는 예입니다. 이 경우 다른 필요가 실행할 수있는 것들,하지만 그들은하지 여부와 관련된 SomeObject
인스턴스 속성이 할당 된 후, 그들은에 가야 다른 try
– finally
아마, 블록 내가 보여준 하나의 랩을.
사용하기 전에 수동으로 변수를 할당하도록 요구하는 것은 실제 문제로 이어지지 않습니다. 그것은 사소한 번거 로움으로 이어지지 만 코드가 더 좋을 것입니다. 당신은 더 제한 범위에 변수가 있고,거야 try
– finally
너무 많이 보호하기 위해 노력하지 않는 블록을.
지역 변수에 기본값이 so
있는 경우 첫 번째 예에서는 null
. 그것은 실제로 아무것도 해결하지 못했을 것입니다. 대신에 컴파일 타임 오류를 얻는 finally
블록, 당신은이 것 NullPointerException
이 숨어 그 힘의 숨기기 다른 예외 코드의 “여기에 몇 가지 작업을 수행”절에서 발생할 수있는 무엇을. (또는 finally
섹션의 예외가 이전 예외에 자동으로 연결됩니까? 기억 나지 않습니다. 그렇더라도 실제 예외와는 다른 예외가있을 것입니다.)
답변
또한 아래 예제에서 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
}
}
답변
최종 인스턴스 / 멤버 변수는 기본적으로 초기화되지 않습니다. 그것들은 최종이며 나중에 프로그램에서 변경할 수 없기 때문입니다. 이것이 Java가 기본값을 제공하지 않고 프로그래머가 초기화하도록하는 이유입니다.
반면에 최종 멤버가 아닌 변수는 나중에 변경할 수 있습니다. 따라서 컴파일러는 나중에 변경할 수 있기 때문에 정확하게 초기화되지 않은 상태로 두지 않습니다. 지역 변수와 관련하여 지역 변수의 범위는 훨씬 좁습니다. 컴파일러는 언제 사용되는지 알고 있습니다. 따라서 프로그래머가 변수를 초기화하도록하는 것은 의미가 있습니다.
답변
귀하의 질문에 대한 실제 대답은 단순히 스택 포인터에 숫자를 추가하여 메서드 변수가 인스턴스화되기 때문입니다. 제로화는 추가 단계입니다. 클래스 변수의 경우 힙의 초기화 된 메모리에 저장됩니다.
추가 조치를 취하지 않으시겠습니까? 한 걸음 물러서십시오. 아무도이 경우 “경고”가 매우 좋은 일이라고 언급하지 않았습니다.
첫 번째 패스 (처음 코딩 할 때)에서 변수를 0 또는 null로 초기화해서는 안됩니다. 실제 값에 할당하거나 전혀 할당하지 마십시오. 그렇지 않으면 java가 당신이 정말로 실수 할 때 알려줄 수 있기 때문입니다. Electric Monk의 답변을 좋은 예로 들어 보겠습니다. 첫 번째 경우에는 SomeObject의 생성자가 예외를 던 졌기 때문에 try ()가 실패하면 결국에는 NPE로 끝날 것이라고 말하는 것이 실제로 놀랍게도 유용합니다. 생성자가 예외를 throw 할 수없는 경우 try에 있지 않아야합니다.
이 경고는 모든 경로를 확인하고 어떤 경로에서 변수를 사용한 경우 해당 경로로 이어지는 모든 경로에서 초기화해야했기 때문에 어리석은 일을하지 않도록 도와주는 멋진 다중 경로 나쁜 프로그래머 검사기입니다. . 이제 올바른 작업인지 결정할 때까지 변수를 명시 적으로 초기화하지 않습니다.
게다가 “int size”보다는 “int size = 0″이라고 명시 적으로 말하고 다음 프로그래머가 0이 될 의도가 있다는 것을 알아 내도록하는 것이 낫지 않습니까?
반대로 컴파일러가 모든 초기화되지 않은 변수를 0으로 초기화하도록하는 하나의 유효한 이유를 찾을 수 없습니다.
답변
주된 목적은 C / C ++와의 유사성을 유지하는 것이라고 생각합니다. 그러나 컴파일러는 문제를 최소한으로 줄일 수있는 초기화되지 않은 변수 사용에 대해 감지하고 경고합니다. 성능 관점에서 보면 컴파일러가 할당 문을 작성할 필요가 없기 때문에 다음 문에서 변수 값을 덮어 쓰더라도 초기화되지 않은 변수를 선언하는 것이 조금 더 빠릅니다.
답변
(질문 이후 너무 오래 새 답변을 게시하는 것이 이상하게 보일 수 있지만 중복 이 나왔습니다.)
저에게 이유 는 이것 때문 입니다. 지역 변수의 목적은 인스턴스 변수의 목적과 다릅니다. 지역 변수는 계산의 일부로 사용됩니다. 인스턴스 변수는 상태를 포함합니다. 값을 할당하지 않고 지역 변수를 사용하는 경우 거의 확실히 논리 오류입니다.
즉, 인스턴스 변수가 항상 명시 적으로 초기화되도록 요구하는 데 완전히 뒤처 질 수 있습니다. 결과가 초기화되지 않은 인스턴스 변수를 허용하는 모든 생성자에서 오류가 발생합니다 (예 : 선언시 초기화되지 않고 생성자에서 초기화되지 않음). 그러나 그것은 Gosling 등의 결정이 아닙니다. al., 90 년대 초반에 들어 왔으니 여기 있습니다. (그리고 나는 그들이 잘못된 전화를 걸었다 고 말하는 것이 아닙니다.)
그래도 지역 변수를 기본값으로 설정할 수는 없습니다 . 예, 우리는 로직을 재확인하기 위해 컴파일러에 의존해서는 안되며, 하나는 그렇지 않습니다.하지만 컴파일러가 하나를 잡을 때 여전히 편리합니다. 🙂