답변:
참조 변수 (예 : 객체)를 선언하면 실제로 객체에 대한 포인터를 만듭니다. 기본 유형의 변수를 선언하는 다음 코드를 고려하십시오 int
.
int x;
x = 10;
이 예제에서 변수 x
는 an int
이며 Java가 변수 를 초기화 0
합니다. 10
두 번째 줄에 값을 할당하면 10
에 의해 참조되는 메모리 위치에 값 이 기록됩니다 x
.
그러나 참조 유형 을 선언하려고하면 다른 일이 발생합니다. 다음 코드를 사용하십시오.
Integer num;
num = new Integer(10);
첫 번째 줄은이라는 변수를 선언 num
하지만 실제로는 기본 값을 포함하지 않습니다. 대신 포인터가 포함됩니다 (유형이 Integer
참조 유형이므로). 무엇을 가리킬 지 아직 말하지 않았기 때문에 Java는 null
" 아무것도 가리키고 있지 않음 "을 의미합니다.
두 번째 줄에서 new
키워드는 유형의 객체를 인스턴스화 (또는 생성)하는 데 사용되며 Integer
포인터 변수 num
는 해당 Integer
객체에 할당됩니다 .
는 NullPointerException
당신이 변수를 선언하지만, 변수 (전화의 내용을 사용하기 전에 변수에 객체와 할당을 작성하지 않은 경우에 발생 역 참조를 ). 실제로 존재하지 않는 것을 가리키고 있습니다.
역 참조는 일반적으로 .
메서드 나 필드에 액세스하거나 [
배열을 인덱싱하는 데 사용할 때 발생합니다 .
num
객체를 만들기 전에 역 참조를 시도 하면 a가 나타납니다 NullPointerException
. 가장 사소한 경우, 컴파일러는 문제를 잡아서 ""라고 알려주지 num may not have been initialized
만, 때로는 객체를 직접 생성하지 않는 코드를 작성할 수도 있습니다.
예를 들어 다음과 같은 방법이있을 수 있습니다.
public void doSomething(SomeObject obj) {
//do something to obj
}
이 경우 객체를 작성하는 obj
것이 아니라 doSomething()
메소드가 호출 되기 전에 작성되었다고 가정합니다 . 다음과 같이 메소드를 호출 할 수 있습니다.
doSomething(null);
이 경우 obj
입니다 null
. 메소드가 전달 된 오브젝트에 대해 무언가를 수행하려는 경우, NullPointerException
프로그래머 오류이므로 프로그래머가 디버깅 목적으로 해당 정보를 필요로하기 때문에이를 발생 시키는 것이 적절 합니다. 다음과 같이 예외 메시지에 객체 변수의 이름을 포함하십시오
Objects.requireNonNull(a, "a");
대안으로, 메소드의 목적이 전달 된 오브젝트에 대해서만 조작하는 것이 아니기 때문에 널 매개 변수가 허용 될 수 있습니다. 이 경우 널 매개 변수 를 확인 하고 다르게 작동 해야합니다 . 설명서에서도이를 설명해야합니다. 예를 들어 doSomething()
다음과 같이 쓸 수 있습니다.
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
마지막으로 스택 추적을 사용하여 예외를 식별하고 원인을 찾는 방법
프로그램이 조기에 종료되지 않도록 예외를 막기 위해 원인을 판별하기 위해 어떤 방법 / 도구를 사용할 수 있습니까?
findbugs가있는 수중 음파 탐지기는 NPE를 감지 할 수 있습니다. JVM에서 동적으로 발생하는 소나 포인터에서 널 포인터 예외를 포착 할 수 있음
int a=b
.b가 a 인 경우 NPE를 던질 수 있습니다 Integer
. 디버깅이 혼동되는 경우가 있습니다.
NullPointerException
코드에서 문제 를 피하는 또 다른 방법은 사용 @Nullable
및 @NotNull
주석입니다. 다음과 같은 답변 에는 이에 대한 자세한 정보가 있습니다. 이 답변은 특별히 IntelliJ IDE에 관한 것이지만, 의견의 장치와 마찬가지로 다른 도구에도 적용 할 수 있습니다. (BTW이 답변을 직접 편집 할 수는 없습니다. 아마도 저자가 추가 할 수 있습니까?)
NullPointerException
이는 객체를 참조하는 것처럼 메모리에 위치가없는 (널) 참조를 사용하려고 할 때 발생하는 예외입니다. null 참조에서 메서드를 호출하거나 null 참조의 필드에 액세스하려고하면을 트리거합니다 NullPointerException
. 이것들이 가장 일반적이지만 다른 방법은 NullPointerException
javadoc 페이지 에 나열되어 있습니다 .
아마도 내가 설명 할 수있는 가장 빠른 예제 코드 NullPointerException
는 다음과 같습니다.
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
안의 첫 번째 줄에서 main
명시 적으로 Object
참조를 설정하고 있습니다obj
동일 null
. 이것은 참조가 있지만 객체를 가리키고 있지 않음을 의미합니다. 그 후, 참조를 메소드를 호출하여 객체를 가리키는 것처럼 처리하려고합니다. 이는 NullPointerException
참조가 가리키는 위치에서 실행할 코드가 없기 때문에 발생합니다.
(이것은 전문적이지만, 나는 그것이 언급 곰 생각하십시오 참조 null로 포인트가 잘못된 메모리 위치를 가리키는 널 포인터가 그대로 가리키는되지 않았다는 C 포인터와 동일하지 않습니다. 어느 곳 보다 미묘하게 다르다, 유효하지 않은 위치를 가리 킵니다.)
null
, 그것을 사용하기 전에 다음과 같이 . 로컬 변수를 사용하면 컴파일러 가이 오류를 잡을 수 있지만이 경우에는 그렇지 않습니다. 어쩌면 그것은 당신의 대답에 유용한 추가를 만들 것입니까?
시작하기 좋은 곳은 JavaDocs 입니다. 그들은 이것을 다루었습니다 :
객체가 필요한 경우 응용 프로그램에서 null을 사용하려고하면 발생합니다. 여기에는 다음이 포함됩니다.
- null 객체의 인스턴스 메서드를 호출합니다.
- 널 오브젝트의 필드에 액세스하거나 수정합니다.
- 배열 인 것처럼 널 길이를 가져옵니다.
- 배열 인 것처럼 널 슬롯에 액세스하거나 수정합니다.
- Throwable 값인 것처럼 null을 던집니다.
응용 프로그램은 null 객체의 다른 불법적 인 사용을 나타 내기 위해이 클래스의 인스턴스를 던져야합니다.
와 함께 null 참조를 사용하려고 하면 JLS에 따라이synchronized
예외가 발생하는 경우도 있습니다 .
SynchronizedStatement: synchronized ( Expression ) Block
- 그렇지 않으면 Expression의 값이 null이면 a
NullPointerException
가 발생합니다.
그래서 당신은 있습니다 NullPointerException
. 어떻게 고치나요? 간단한 예제를 보자 NullPointerException
:
public class Printer {
private String name;
public void setName(String name) {
this.name = name;
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer();
printer.print();
}
}
널값 식별
첫 번째 단계는 예외를 일으키는 값을 정확히 식별하는 것 입니다 . 이를 위해서는 디버깅이 필요합니다. stacktrace 를 읽는 법을 배우는 것이 중요합니다 . 예외가 발생한 위치가 표시됩니다.
Exception in thread "main" java.lang.NullPointerException
at Printer.printString(Printer.java:13)
at Printer.print(Printer.java:9)
at Printer.main(Printer.java:19)
여기서 우리는 예외가 13 행에서 발생한다는 것을 알 수 있습니다 ( printString
메서드에서). 행을보고 logging 문 을 추가 하거나 디버거를 사용하여 null 값을 확인하십시오 . 우리는 그것이 s
null 이라는 것을 알아 내고length
메소드를 하면 예외가 발생합니다. s.length()
메소드에서 메소드를 제거 하면 프로그램이 예외 처리를 중지 함을 알 수 있습니다 .
이 값의 출처를 추적
다음으로이 값의 출처를 확인하십시오. 메소드의 호출자에 따라, 우리는 그 볼 s
에 전달되는 printString(name)
의 print()
방법 및this.name
null입니다.
이 값을 설정해야하는 위치 추적
어디에 this.name
설정되어 있습니까? 에서 setName(String)
방법. 좀 더 디버깅하면이 메소드가 전혀 호출되지 않는다는 것을 알 수 있습니다. 메소드가 호출 된 경우 이러한 메소드가 호출 된 순서 를 확인 하고 set 메소드가 print 메소드 다음 에 호출되지 않는지 확인하십시오 .
이것은 우리에게 해결책을 제공하기에 충분합니다.에 전화하기 printer.setName()
전에에 전화를 추가하십시오 printer.print()
.
변수는있을 수 기본값을 (그리고 setName
이 널 (null)로 설정되는 것을 방지 할 수 있습니다)
private String name = "";
중 하나 print
또는 printString
방법이 있습니다 널 (null)을 확인 , 예를 들면 :
printString((name == null) ? "" : name);
또는 name
항상 null이 아닌 값을 갖도록 클래스를 디자인 할 수 있습니다 .
public class Printer {
private final String name;
public Printer(String name) {
this.name = Objects.requireNonNull(name);
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer("123");
printer.print();
}
}
또한보십시오:
문제를 디버깅하려고했지만 여전히 해결 방법이없는 경우 질문을 게시하여 추가 도움을받을 수 있지만 지금까지 시도한 내용을 포함시켜야합니다. 최소한 질문에 스택 추적 을 포함 시키고 코드에 중요한 줄 번호 를 표시하십시오 . 또한 코드를 먼저 단순화하십시오 ( SSCCE 참조 ).
NullPointerException
(NPE)의 ?당신이 알아야 할 때, 자바 유형으로 구분된다 기본 유형 ( boolean
, int
, 등) 및 참조 형식 . Java의 참조 유형을 사용하면 특수 값을 사용할 수 있습니다null
"객체 없음"이라고하는 Java 방식 인 .
A NullPointerException
는 프로그램 null
이 실제 참조 인 것처럼 사용하려고 할 때마다 런타임에 발생합니다 . 예를 들어 다음과 같이 작성하면
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
"HERE"로 표시된 명령문 length()
은 null
참조 에서 메소드 를 실행하려고 시도하며 , 이로 인해NullPointerException
.
null
값을 사용하여 여러 가지 방법으로 결과를 얻을 수 있습니다 NullPointerException
. 실제로 NPE를 유발하지 않고 할 수있는 것은 다음과 null
같습니다.
==
또는 !=
연산자를 사용하여 테스트 하거나 instanceof
.위의 프로그램을 컴파일하고 실행한다고 가정 해보십시오.
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:4)
$
첫 번째 관찰 : 편집이 성공했습니다! 프로그램의 문제는 컴파일 오류가 아닙니다. 그것은이다 런타임 오류입니다. (일부 IDE에서는 프로그램에서 항상 예외가 발생한다고 경고 할 수 있지만 표준 javac
컴파일러는 그렇지 않습니다.)
두 번째 관찰 : 프로그램을 실행하면 두 줄의 "gobbledy-gook"이 출력됩니다. 잘못된!! 그것은 거칠지 않다. 그것은 스택 트레이스입니다 ... 시간을 들여주의 깊게 읽으면 코드의 오류를 추적하는 데 도움이되는 중요한 정보 를 제공합니다 .
그래서 그것이 말하는 것을 보자.
Exception in thread "main" java.lang.NullPointerException
스택 추적의 첫 번째 줄은 여러 가지를 알려줍니다.
java.lang.NullPointerException
.NullPointerException
오류 메시지가 거의 없기 때문에 이런 점에서 특이합니다.두 번째 줄은 NPE 진단에서 가장 중요한 것입니다.
at Test.main(Test.java:4)
이것은 우리에게 많은 것들을 알려줍니다.
main
방법에 있다고 말합니다 Test
.위의 파일에서 행을 세면 4 행은 "HERE"주석으로 레이블이 지정된 행입니다.
보다 복잡한 예에서는 NPE 스택 추적에 많은 행이 있습니다. 그러나 두 번째 줄 (첫 번째 "at"줄)이 NPE가 발생한 위치를 알려줄 것입니다 1 .
간단히 말해, 스택 추적은 프로그램의 어떤 진술이 NPE를 던 졌는지 분명하게 알려줍니다.
1-사실이 아닙니다. 중첩 예외라는 것이 있습니다 ...
어려운 부분입니다. 짧은 대답은 스택 추적, 소스 코드 및 관련 API 설명서에서 제공 한 증거에 논리적 추론을 적용하는 것입니다.
간단한 예 (위)로 먼저 설명해 보겠습니다. 우리는 스택 트레이스가 우리에게 NPE가 발생한 곳이라고 알려준 라인을 살펴보면서 시작합니다.
int length = foo.length(); // HERE
어떻게 NPE를 던질 수 있습니까?
실제로 한 가지 방법 만 있습니다 . foo
값이있는 경우에만 발생할 수 있습니다 null
. 그런 다음 length()
메소드 를 실행하려고 시도 null
하고 ... BANG!
그러나 NPE가 length()
메소드 호출 내부에 던져지면 어떻게됩니까?
이런 일이 발생하면 스택 추적이 다르게 보일 것입니다. 첫 번째 "at"행은 예외가 java.lang.String
클래스의 일부 행에서 발생했으며 4 행 Test.java
은 두 번째 "at"행이라고합니다.
어디에서 null
왔습니까? 이 경우에는 분명하며이를 해결하기 위해해야 할 일이 분명합니다. (널이 아닌 값을foo
.
자, 좀 더 까다로운 예를 들어 봅시다. 여기에는 논리적 추론 이 필요합니다 .
public class Test {
private static String[] foo = new String[2];
private static int test(String[] bar, int pos) {
return bar[pos].length();
}
public static void main(String[] args) {
int length = test(foo, 1);
}
}
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.test(Test.java:6)
at Test.main(Test.java:10)
$
이제 두 개의 "at"줄이 있습니다. 첫 번째는이 줄입니다.
return args[pos].length();
두 번째는이 줄입니다.
int length = test(foo, 1);
첫 번째 줄을 보면 어떻게 NPE를 던질 수 있습니까? 두 가지 방법이 있습니다.
bar
입니다 null
다음 bar[pos]
NPE가 발생합니다.bar[pos]
되는 null
다음 호출 length()
그것을하면 NPE가 발생합니다.다음으로, 어떤 시나리오에서 실제로 어떤 일이 일어나고 있는지 설명해야합니다. 우리는 첫 번째 것을 탐구하면서 시작할 것입니다 :
어디 bar
에서 왔습니까? test
메소드 호출에 대한 매개 변수이며, 호출 된 방식을 살펴보면 정적 변수 test
에서 온 것임을 알 수 있습니다 foo
. 또한 foo
null이 아닌 값으로 초기화되었음을 분명히 알 수 있습니다 . 그것은이 설명을 잠정적으로 기각하기에 충분합니다. (이론적으로, 뭔가 다른 수 변경 foo
에null
있지만 여기서는 일어나지 않습니다.)
두 번째 시나리오는 어떻습니까? 음, 우리는 볼 수 pos
있다 1
, 그 수단 그렇게 foo[1]
해야합니다 null
. 이게 가능해?
실제로입니다! 그리고 그것이 문제입니다. 다음과 같이 초기화하면
private static String[] foo = new String[2];
로 초기화되는String[]
두 개의 요소로 a 를 할당합니다 . 그 후, 우리는의 내용을 변경하지 않은 그래서 ... 계속 될 것입니다 .null
foo
foo[1]
null
마치 객체에 액세스하려고하는 것과 같습니다 null
. 아래 예를 고려하십시오.
TypeA objA;
현재이 객체를 선언 했지만 초기화하거나 인스턴스화 하지 않았습니다 . 그리고 속성이나 메서드에 액세스하려고 할 때마다 NullPointerException
의미가 있습니다.
아래 예제도 참조하십시오.
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
개체가 필요한 경우 응용 프로그램에서 null을 사용하려고하면 null 포인터 예외가 발생합니다. 여기에는 다음이 포함됩니다.
null
객체 합니다.null
객체 합니다.null
배열 것처럼 옵니다.null
마치 마치 배열 것처럼 .null
Throwable 값인 것처럼 .응용 프로그램은이 클래스의 인스턴스를 던져서 null
객체 .
참조 : http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
null
의 대상으로 synchronized
사용, 2) a null
의 대상으로 사용 switch
및 unboxing null
.
null
포인터가 어디 한 그 점입니다. 당신이 포인터를 역 참조 할 때 p
, 당신은 페이지 "에 저장되어있는 위치에서 나에게 데이터를 제공 '라고."때 p
A는 null
포인터에 저장 위치가 p
되어 nowhere
, 당신이 말하는 것 ""'곳 '위치에서 나에게 데이터를 제공하지 않습니다. 분명히,이 작업을 수행 할 수 없으므로null pointer exception
.
일반적으로 무언가가 제대로 초기화되지 않았기 때문입니다.
NULL
는 null
자바 로 작성됩니다 . 대소 문자를 구분합니다.
발생 방법 및 해결 방법을 설명하기위한 많은 설명이 이미 제공되어 있지만, 이를 피하기 위해 모범 사례 를 따라야 NullPointerException
합니다.
다음을 참조하십시오 : 모범 사례 목록
final
수정자를 잘 활용하는 것이 중요합니다 .
Java에 적용 할 때마다 "최종"수정 자 사용
요약:
final
좋은 초기화를 시행 수정자를 .@NotNull
하고@Nullable
if("knownObject".equals(unknownObject)
valueOf()
이상 toString()
.StringUtils
방법을 사용하십시오 StringUtils.isEmpty(null)
.@Nullable
위에 나열된)을 기반으로 자동 nullity analisys를 제공 하고 잠재적 오류에 대해 경고합니다. 기존 코드 구조를 기반으로 이러한 주석 (예 : IntelliJ가이를 수행 할 수 있음)을 유추 및 생성 할 수도 있습니다.
if (obj==null)
. null 인 경우이를 처리하는 코드를 작성해야합니다.
Java에서 모든 유형 (기본 유형 제외)은 클래스 형식입니다.
객체를 사용하려면 두 단계가 있습니다.
예:
Object object;
object = new Object();
배열 개념과 동일합니다.
Item item[] = new Item[5];
item[0] = new Item();
초기화 섹션을 제공하지 않으면 NullPointerException
발생합니다.
널 포인터 예외는 오브젝트를 초기화하지 않고 사용 중임을 나타내는 표시기입니다.
예를 들어, 아래는 코드에서 사용할 학생 클래스입니다.
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
아래 코드는 널 포인터 예외를 제공합니다.
public class School {
Student student;
public School() {
try {
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
를 사용 student
하고 있지만 아래 표시된 올바른 코드와 같이 초기화하는 것을 잊었습니다.
public class School {
Student student;
public School() {
try {
student = new Student();
student.setId(12);
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
에서 자바 당신이 선언 된 모든 변수는 개체 (또는 원시)에 "참조"가 아니라 실제로 스스로 개체입니다.
하나의 객체 메소드를 실행하려고하면 참조는 살아있는 객체에 해당 메소드를 실행하도록 요청합니다. 그러나 참조가 NULL (nothing, zero, void, nada)을 참조하는 경우 메소드를 실행할 방법이 없습니다. 그런 다음 런타임은 NullPointerException을 발생시켜 알려줍니다.
참조는 "포인팅"을 null로 지정하므로 "Null-> 포인터"입니다.
객체는 VM 메모리 공간에 있으며 액세스하는 유일한 방법은 this
참조를 사용하는 것입니다. 이 예제를 보자 :
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
그리고 코드의 다른 곳에서 :
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
이 중요한 것은 알고 - (경우 위의 예에서 오브젝트의 참조가없는 경우 reference
와 otherReference
다음 개체는 "도달"입니다 null로 두 점). 작업 할 수있는 방법이 없으므로이 개체는 가비지 수집 될 준비가되어 있으며 어느 시점에서 VM은이 개체가 사용하는 메모리를 해제하고 다른 개체를 할당합니다.
또 다른 발생은 NullPointerException
객체 배열을 선언 한 후 즉시 그 안의 요소를 역 참조하려고 시도 할 때 발생합니다.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
비교 순서가 반대로되면이 특정 NPE를 피할 수 있습니다. 즉, 사용.equals
널이 아닌 보장 된 오브젝트에서 사용하십시오.
배열 내부의 모든 요소 는 공통 초기 값으로 초기화됩니다 . 모든 유형의 객체 배열의 경우 모든 요소가null
입니다.
당신은 해야한다 배열의 요소를 초기화 하기 전에 액세스하거나이를 역 참조.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Optional
은 null을 반환하는 것이 었습니다. 키워드는 괜찮습니다. 이를 방지하는 방법을 아는 것이 중요합니다. 이것은 하나의 일반적인 발생과이를 완화하는 방법을 제공합니다.