NullPointerException은 무엇이며 어떻게 해결합니까?


210

널 포인터 예외 ( java.lang.NullPointerException) 란 무엇이며 원인은 무엇입니까?

프로그램이 조기에 종료되지 않도록 예외를 막기 위해 원인을 판별하기 위해 어떤 방법 / 도구를 사용할 수 있습니까?

답변:


3764

참조 변수 (예 : 객체)를 선언하면 실제로 객체에 대한 포인터를 만듭니다. 기본 유형의 변수를 선언하는 다음 코드를 고려하십시오 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에서 동적으로 발생하는 소나 포인터에서 널 포인터 예외를 포착 할 수 있음


558
"이러한 유형의 예외를 피하는 가장 좋은 방법은 객체를 직접 만들지 않았을 때 항상 null을 확인하는 것입니다." 호출자가 null을 전달했지만 메소드에 유효한 인수가 아닌 경우 호출자의 결함이므로 호출자에서 예외를 다시 발생시키는 것이 맞습니다. 잘못된 입력을 자동으로 무시하고 메소드에서 아무것도 수행하지 않으면 문제를 숨길 수 있으므로 조언이 매우 좋지 않습니다 .
Boann

104
이 게시물에 대해 오토 복싱을 사용할 때 프리미티브에 할당해도 NPE가 발생할 수 있다고 설명합니다 int a=b.b가 a 인 경우 NPE를 던질 수 있습니다 Integer. 디버깅이 혼동되는 경우가 있습니다.
Simon Fischer

58
웹 브라우저에서 웹앱에 의해 발생 된 NPE를 캡처 할 수 있습니까? 웹 브라우저에서보기 페이지 소스에 표시되는 것처럼 ..
Sid

76
예, 객체를 호출하기 전에 객체가 null인지 확인하거나 가질 수있는 변수에 액세스를 시도하십시오. 때때로 코드를 구조화하면 널 포인터 예외를 피할 수 있습니다. 예를 들어 상수 문자열로 입력 문자열을 확인할 때 다음과 같이 상수 문자열로 시작해야합니다. if ( "SomeString".equals (inputString)) {} // inputString이 null 인 경우에도 예외는 발생하지 않습니다. 안전을 위해 할 수있는 일이 많이 있습니다.
로즈

78
NullPointerException코드에서 문제 를 피하는 또 다른 방법은 사용 @Nullable@NotNull주석입니다. 다음과 같은 답변 에는 이에 대한 자세한 정보가 있습니다. 이 답변은 특별히 IntelliJ IDE에 관한 것이지만, 의견의 장치와 마찬가지로 다른 도구에도 적용 할 수 있습니다. (BTW이 답변을 직접 편집 할 수는 없습니다. 아마도 저자가 추가 할 수 있습니까?)
Arjan Mels

879

NullPointerException이는 객체를 참조하는 것처럼 메모리에 위치가없는 (널) 참조를 사용하려고 할 때 발생하는 예외입니다. null 참조에서 메서드를 호출하거나 null 참조의 필드에 액세스하려고하면을 트리거합니다 NullPointerException. 이것들이 가장 일반적이지만 다른 방법은 NullPointerExceptionjavadoc 페이지 에 나열되어 있습니다 .

아마도 내가 설명 할 수있는 가장 빠른 예제 코드 NullPointerException는 다음과 같습니다.

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

안의 첫 번째 줄에서 main명시 적으로 Object참조를 설정하고 있습니다obj 동일 null. 이것은 참조가 있지만 객체를 가리키고 있지 않음을 의미합니다. 그 후, 참조를 메소드를 호출하여 객체를 가리키는 것처럼 처리하려고합니다. 이는 NullPointerException참조가 가리키는 위치에서 실행할 코드가 없기 때문에 발생합니다.

(이것은 전문적이지만, 나는 그것이 언급 곰 생각하십시오 참조 null로 포인트가 잘못된 메모리 위치를 가리키는 널 포인터가 그대로 가리키는되지 않았다는 C 포인터와 동일하지 않습니다. 어느 곳 보다 미묘하게 다르다, 유효하지 않은 위치를 가리 킵니다.)


49
나는 당신이 거기에 쓴 모든 것을 이해했지만, 단지 한동안 코딩하고 '포인터'와 '레퍼런스'가 무엇인지 (그리고 그 문제에 대해 null이 무엇인지) 알고 있기 때문입니다. 그런 설명으로 바로 뛰어 들려고 할 때, 배경이 충분하지 않기 때문에 학생들은 저를 엇갈리게 봅니다.
mmr

33
@ mmr : 피드백 주셔서 감사합니다, 당신은 유효한 지적합니다. 인터넷상에서 누군가의 위치와 설명을 시작하는 것이 안전한 수준을 실제로 판단하기는 어렵습니다. 다시 수정 해 보겠습니다.
Bill the Lizard

22
실제로는 NullPointerException을 얻을 수있는 일반적인 방법은 명시 적으로 이외의 다른 멤버 변수를 초기화 잊는 것 null, 그것을 사용하기 전에 다음과 같이 . 로컬 변수를 사용하면 컴파일러 가이 오류를 잡을 수 있지만이 경우에는 그렇지 않습니다. 어쩌면 그것은 당신의 대답에 유용한 추가를 만들 것입니까?
Ilmari Karonen

6
@ EJP 귀하의 포인트가 유효하다고 생각하므로 대답을보다 명확하고 업데이트하여 'points to null'이라고 말하지 않도록 업데이트했습니다.
Steve Powell

5
@StevePowell 저는 오래 전에 답변을 바꾸고 싶지 않다고 말했습니다. 원저자의 의도를 존중하십시오.
Bill the Lizard

696

NullPointerException은 무엇입니까?

시작하기 좋은 곳은 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 값을 확인하십시오 . 우리는 그것이 snull 이라는 것을 알아 내고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 참조 ).


44
+1 스택 트레이스 과정을 포함하는 예제를 작성하면 좋습니다. NPE 디버깅에 읽는 것이 중요한지 보여주는 것이 중요합니다. (그리고 누군가가 오류에 대한 질문을 게시 할 때 거의 항상 스택 추적을 찾는 이유)
Dennis Meng

16
디버깅에 대해 언급했습니다 ... 어떻게 작동합니까? 나는 한동안 주제를 연구하고 있지만 아무것도 찾을 수 없습니다. 나는 당신과 같은 놀라운 선생님이 나에게 그것을 가르 칠 수 있다고 확신합니다! 정말 고마워! :-)
Ruchir Baronia

15
@RuchirBaronia 디버거를 사용하면 프로그램별로 단계별로 호출하여 어떤 메서드가 호출되고 변수가 어떻게 변경되는지 확인할 수 있습니다. IDE에는이를위한 몇 가지 도구가 있어야합니다. 예를 들어 vogella.com/tutorials/EclipseDebugging/article.html 을 참조하십시오 .
fgb

15
@RuchirBaronia 스택 추적에서 볼 수있는대로 NullPointerExceptions 주위의 메서드에 중단 점을 설정하고 예상 값과 변수 값을 확인합니다. 변수를 사용하지 않아야 할 때 null 값을 알고 있으면 값을 변경하는 코드 주위에 중단 점을 설정할 수 있습니다. 값이 변경 될 때 알려주는 조건부 중단 점도 있습니다.
fgb

6
String 객체를 기본값으로 빈 문자열로 설정하는 것은 좋지 않은 것으로 간주됩니다.
Tiny

501

질문 : 원인 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같습니다.

  • 참조 변수에 지정하거나 참조 변수에서 읽습니다.
  • 배열 요소에 할당하거나 배열 요소에서 읽습니다 (배열 참조 자체가 null이 아닌 경우).
  • 매개 변수로 전달하거나 결과로 리턴하거나
  • ==또는 !=연산자를 사용하여 테스트 하거나 instanceof.

질문 : NPE 스택 추적을 어떻게 읽습니까?

위의 프로그램을 컴파일하고 실행한다고 가정 해보십시오.

$ 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 스레드의 이름을 알려줍니다. 하나의 스레드 (예 :이 스레드)가있는 간단한 프로그램의 경우 "메인"이됩니다. 계속 갑시다 ...
  • 발생 된 예외의 전체 이름을 알려줍니다. 즉 java.lang.NullPointerException.
  • 예외에 관련 오류 메시지가 있으면 예외 이름 뒤에 출력됩니다. NullPointerException오류 메시지가 거의 없기 때문에 이런 점에서 특이합니다.

두 번째 줄은 NPE 진단에서 가장 중요한 것입니다.

at Test.main(Test.java:4)

이것은 우리에게 많은 것들을 알려줍니다.

  • "at Test.main"은 우리가 수업 의 main방법에 있다고 말합니다 Test.
  • "Test.java:4"는 클래스의 소스 파일 이름을 제공하며, 이것이 발생하는 명령문이 파일의 4 행에 있음을 알려줍니다.

위의 파일에서 행을 세면 4 행은 "HERE"주석으로 레이블이 지정된 행입니다.

보다 복잡한 예에서는 NPE 스택 추적에 많은 행이 있습니다. 그러나 두 번째 줄 (첫 번째 "at"줄)이 NPE가 발생한 위치를 알려줄 것입니다 1 .

간단히 말해, 스택 추적은 프로그램의 어떤 진술이 NPE를 던 졌는지 분명하게 알려줍니다.

1-사실이 아닙니다. 중첩 예외라는 것이 있습니다 ...

질문 : 코드에서 NPE 예외의 원인을 어떻게 추적합니까?

어려운 부분입니다. 짧은 대답은 스택 추적, 소스 코드 및 관련 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. 또한 foonull이 아닌 값으로 초기화되었음을 분명히 알 수 있습니다 . 그것은이 설명을 잠정적으로 기각하기에 충분합니다. (이론적으로, 뭔가 다른 수 변경 foonull 있지만 여기서는 일어나지 않습니다.)

두 번째 시나리오는 어떻습니까? 음, 우리는 볼 수 pos있다 1, 그 수단 그렇게 foo[1]해야합니다 null. 이게 가능해?

실제로입니다! 그리고 그것이 문제입니다. 다음과 같이 초기화하면

private static String[] foo = new String[2];

로 초기화되는String[] 두 개의 요소로 a 를 할당합니다 . 그 후, 우리는의 내용을 변경하지 않은 그래서 ... 계속 될 것입니다 .nullfoofoo[1]null


425

마치 객체에 액세스하려고하는 것과 같습니다 null. 아래 예를 고려하십시오.

TypeA objA;

현재이 객체를 선언 했지만 초기화하거나 인스턴스화 하지 않았습니다 . 그리고 속성이나 메서드에 액세스하려고 할 때마다 NullPointerException의미가 있습니다.

아래 예제도 참조하십시오.

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

1
우리가 System.out.println (a.length ()); // NullPointerException이 발생하며이를 건너 뛰기 위해 try catch 블록으로 처리 할 수 ​​있습니다. 감사합니다
비자 야 바르 마 Lanke에게

359

개체가 필요한 경우 응용 프로그램에서 null을 사용하려고하면 null 포인터 예외가 발생합니다. 여기에는 다음이 포함됩니다.

  1. 의 인스턴스 메소드 호출 null객체 합니다.
  2. 필드의 접근 또는 수정 null객체 합니다.
  3. 길이를 복용 null배열 것처럼 옵니다.
  4. 슬롯 액세스 또는 수정 null마치 마치 배열 것처럼 .
  5. 던지기 nullThrowable 값인 것처럼 .

응용 프로그램은이 클래스의 인스턴스를 던져서 null 객체 .

참조 : http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


12
간단하게 유지하십시오. 저는이 답변이 마음
Emiliano

5
@Emiliano-단순히 초기화 된 속성에 액세스해도 NPE가 발생하지 않습니다. 초기화되지 않은 속성 값을 사용하여 >> do <<를 수행하면 NPE가 발생합니다.
Stephen C

1
더 많은 경우를 원한다면 : 1) 블록 null의 대상으로 synchronized사용, 2) a null의 대상으로 사용 switch및 unboxing null.
Stephen C

333

null포인터가 어디 한 그 점입니다. 당신이 포인터를 역 참조 할 때 p, 당신은 페이지 "에 저장되어있는 위치에서 나에게 데이터를 제공 '라고."때 pA는 null포인터에 저장 위치가 p되어 nowhere, 당신이 말하는 것 ""'곳 '위치에서 나에게 데이터를 제공하지 않습니다. 분명히,이 작업을 수행 할 수 없으므로null pointer exception .

일반적으로 무언가가 제대로 초기화되지 않았기 때문입니다.


2
데이터베이스를 작성하고 있습니까? -> NULLnull자바 로 작성됩니다 . 대소 문자를 구분합니다.
bvdb

3
"NULL 포인터는 아무데도 가리지 않는 포인터" 라고 동의하지 않습니다. 널 포인터는 아무데도 가리 키지 않으며 널값을 가리 킵니다.
TheRealChx101

2
@ TheRealChx101 널 포인터와 널 값에 대한 포인터는 서로 다릅니다. 널 포인터는 널 값을 가리 키지 않습니다. 포인터에 대한 포인터가 있다고 가정하십시오. 포인터 A는 포인터 B를 가리키고 포인터 B는 널입니다. 이 경우 포인터 A는 널값을 가리키고 포인터 B는 널 포인터입니다.
MrZebra

321

발생 방법 및 해결 방법을 설명하기위한 많은 설명이 이미 제공되어 있지만, 이를 피하기 위해 모범 사례 를 따라야 NullPointerException합니다.

다음을 참조하십시오 : 모범 사례 목록

final수정자를 잘 활용하는 것이 중요합니다 . Java에 적용 할 때마다 "최종"수정 자 사용

요약:

  1. 사용 final좋은 초기화를 시행 수정자를 .
  2. 적용 가능한 경우 빈 컬렉션을 반환하는 등 메서드에서 null을 반환하지 마십시오.
  3. 특수 효과를 사용 @NotNull하고@Nullable
  4. null이 아니어야 할 때 전체 응용 프로그램을 통해 null 객체가 전파되는 것을 피하기 위해 신속하게 실패하고 어설 션을 사용하십시오.
  5. 먼저 알려진 객체와 동일하게 사용하십시오. if("knownObject".equals(unknownObject)
  6. 선호 valueOf()이상 toString().
  7. null 안전 StringUtils방법을 사용하십시오 StringUtils.isEmpty(null).
  8. 메소드에서 Java 8 Optional을 리턴 값으로 사용하십시오. Optional 클래스는 널 참조 대신 선택적 값을 나타내는 솔루션을 제공합니다.

4
j2ee 프로젝트에서 Nullpointer 예외는 매우 일반적입니다. 경우에 따라 참조 변수에 null 값이 있으므로 변수 초기화를 올바르게 확인해야합니다. 조건문 중에 항상 플래그 또는 참조에 null이 포함되어 있는지 여부를 확인해야합니다 .- if (flag! = 0) {플래그를 사용하는 ur 코드}
Amaresh Pattanayak

14
일부 IDE (예 : Eclipse)는 사용자 정의 가능한 주석 (예 : @Nullable위에 나열된)을 기반으로 자동 nullity analisys를 제공 하고 잠재적 오류에 대해 경고합니다. 기존 코드 구조를 기반으로 이러한 주석 (예 : IntelliJ가이를 수행 할 수 있음)을 유추 및 생성 할 수도 있습니다.
Jan Chimiak

4
먼저 nullable 객체를 사용하기 전에을 사용하여 null인지 확인해야합니다 if (obj==null). null 인 경우이를 처리하는 코드를 작성해야합니다.
Lakmal Vithanage

4
IMO, 가능한 경우 메소드에서 널 오브젝트 리턴을 피하고 계약에 따라 널 입력 매개 변수가 허용되지 않는 경우 어노테이션을 사용하여 코드에서 'if (obj == null)'의 양을 줄이고 개선하십시오. 코드 가독성.
LG

4
: 당신이 진실 이러한 "모범 사례"동의하기 전에 ...이 읽기 satisfice.com/blog/archives/27
스티븐 C

316

Java에서 모든 유형 (기본 유형 제외)은 클래스 형식입니다.

객체를 사용하려면 두 단계가 있습니다.

  1. 알리다
  2. 초기화

예:

  • 선언: Object object;
  • 초기화 : object = new Object();

배열 개념과 동일합니다.

  • 선언: Item item[] = new Item[5];
  • 초기화 : item[0] = new Item();

초기화 섹션을 제공하지 않으면 NullPointerException발생합니다.


3
예를 들어, 참조를 선언했지만 인스턴스를 가리 키지 않으면 NullPointerException은 해당 메서드를 호출 할 때 발생합니다. 예 : YourClass ref = null; // 또는 ref = anotherRef; // 그러나 anotherRef가 인스턴스를 가리 키지 않았습니다. ref.someMethod (); // NullPointerException이 발생합니다. 일반적으로 다음과 같이 수정하십시오. 메소드를 호출하기 전에 참조가 널인지 판별하십시오. 예 : if (yourRef! = null) {yourRef.someMethod (); }
sunhang

2
또는 예외 캡처를 사용하십시오. 예 : try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang


315

널 포인터 예외는 오브젝트를 초기화하지 않고 사용 중임을 나타내는 표시기입니다.

예를 들어, 아래는 코드에서 사용할 학생 클래스입니다.

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");
        }
    }
}

7
이것은 좋은 예이지만, 다른 모든 답변으로 아직 다루지 않은 질문에 무엇이 추가되는지 물어볼 수 있습니까?
신비주의

13
여기서 "초기화되지 않음"이라는 단어를 사용하는 것은 부적절합니다. 표시 한 예제는 실제로 "초기화 됨"이며 null로 초기화됩니다. 초기화되지 않은 변수의 경우 컴파일러가 사용자에게 불평합니다.
Adrian Shum

2
NPE 초기화되지 않은 필드를 사용하고 있음을 나타내는 지표 일 수 있습니다 . 다른 일을하고 있다는 표시 일 수 있습니다. 이와 같은 단일 원인으로 지나치게 단순화해도 NPE 문제를 해결하는 데 도움이되지 않습니다. 실제 원인이이 문제가 아닌 경우.
Stephen C

309

에서 자바 당신이 선언 된 모든 변수는 개체 (또는 원시)에 "참조"가 아니라 실제로 스스로 개체입니다.

하나의 객체 메소드를 실행하려고하면 참조는 살아있는 객체에 해당 메소드를 실행하도록 요청합니다. 그러나 참조가 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...

이 중요한 것은 알고 - (경우 위의 예에서 오브젝트의 참조가없는 경우 referenceotherReference다음 개체는 "도달"입니다 null로 두 점). 작업 할 수있는 방법이 없으므로이 개체는 가비지 수집 될 준비가되어 있으며 어느 시점에서 VM은이 개체가 사용하는 메모리를 해제하고 다른 개체를 할당합니다.


280

또 다른 발생은 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));
}

클래스 수준이 아닌 인스턴스 수준에서 초기화되지 않은 객체에 대한 작업은 NullPointerException을 발생시킵니다. 작업은 인스턴스별로 이루어져야합니다. 초기화되지 않은 객체에서 정적 메서드를 호출한다고 말하는 작업이 클래스 수준에 있으면 NullPointerException 예외가 발생하지 않습니다. 원시 래퍼 클래스 객체조차도 NullPointerException을 발생시킵니다.
Shailendra Singh

1. NullPointerException은 RuntimeException입니다. 즉, 프로그램이 실행될 때 나타나고 컴파일 타임에 나타나지 않습니다.! :(하지만 대부분의 IDE가이를 발견하는 데 도움이됩니다. 2. 대 입문에서 키워드 'null'의 사용을 최소화하십시오. :) 참조 URL :
tomj0101

@ tomj0101 왜 당신이 그 의견을 말했는지에 대해서는 확실하지 않습니다 ...하지만 두 번째로, 이전의 패턴 Optional은 null을 반환하는 것이 었습니다. 키워드는 괜찮습니다. 이를 방지하는 방법을 아는 것이 중요합니다. 이것은 하나의 일반적인 발생과이를 완화하는 방법을 제공합니다.
Makoto

NullPointerException은 런타임 예외로, 예외를 포착하지 않고 대신 피하는 것이 좋습니다.
Shomu

2
@ Shomu : 어느 시점에서 잡을 것을 제안합니까?
Makoto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.