나는 object != null
피하기 위해 많이 사용 합니다 NullPointerException
.
이것에 대한 좋은 대안이 있습니까?
예를 들어 자주 사용합니다.
if (someobject != null) {
someobject.doCalc();
}
A에 대한이 확인 NullPointerException
에 대한 someobject
위의 코드 조각의 객체입니다.
허용되는 답변이 최신 정보가 아닐 수 있습니다 . 최신 접근 방식 은 https://stackoverflow.com/a/2386013/12943 을 참조 하십시오 .
답변
이것은 저에게 중급 개발자가 중간 시점에서 직면하는 경향이있는 합리적으로 일반적인 문제처럼 들립니다. 또한 자체 코드를 작성할 때 null을 반환하여 호출자가 null을 확인 해야하는 것을 나타내는 경향이 있습니다.
다른 방법으로 null 검사가 나타나는 두 가지 경우가 있습니다.
-
계약에있어서 유효한 응답이 null 인 경우 과
-
올바른 응답이 아닌 곳.
(2) 쉽다. 어느 사용 assert
또는 진술 (주장)은 (예를 들어, 실패 할 수 NullPointerException이 ). 어설 션은 1.4에서 추가 된 잘 사용되지 않는 Java 기능입니다. 구문은 다음과 같습니다.
assert <condition>
또는
assert <condition> : <object>
여기서 <condition>
부울 표현식이며 메소드 출력이 오류에 포함 <object>
되는 오브젝트입니다 toString()
.
assert
문은 발생 Error
( AssertionError
조건이 참이 아닌 경우)를. 기본적으로 Java는 어설 션을 무시합니다. 옵션 -ea
을 JVM 에 전달하여 어설 션을 사용할 수 있습니다 . 개별 클래스 및 패키지에 대한 어설 션을 활성화 및 비활성화 할 수 있습니다. 즉, 테스트에서 어설 션의 성능에 영향을 미치지 않는 것으로 나타 났지만 프로덕션 환경에서 어설 션으로 코드의 유효성을 검사하고 비활성화 할 수 있습니다.
이 경우 어설 션을 사용하지 않으면 코드가 실패하기 때문에 어설 션을 사용하면 발생합니다. 단 한가지 차이점은 어설 션을 사용하면 더 의미있는 방식으로 추가 정보를 사용하여 더 빨리 발생할 수 있다는 것입니다. 예상하지 못한 경우 왜 그런 일이 발생했는지 파악하는 데 도움이 될 수 있습니다.
(1) 조금 더 어렵다. 호출하는 코드를 제어 할 수 없으면 문제가 발생한 것입니다. null이 유효한 응답 인 경우 확인해야합니다.
그러나 제어하는 코드 (이 경우는 종종 있음) 인 경우 다른 이야기입니다. 응답으로 널을 사용하지 마십시오. 컬렉션을 반환하는 메서드를 사용하면 쉽습니다. 거의 항상 null 대신 빈 컬렉션 (또는 배열)을 반환합니다.
컬렉션이 아닌 경우 어려울 수 있습니다. 이러한 인터페이스를 예로 들면 다음과 같이 고려하십시오.
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
파서는 원시 사용자 입력을 취하고 무언가에 대한 명령 행 인터페이스를 구현하는 경우해야 할 일을 찾습니다. 적절한 조치가 없으면 계약이 널을 리턴하도록 만들 수 있습니다. 그것은 당신이 말하는 null 점검을 이끈다.
다른 해결책은 null을 반환하지 않고 대신 Null Object 패턴을 사용하는 것 입니다 .
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
비교:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
에
ParserFactory.getParser().findAction(someInput).doSomething();
더 간결한 코드로 이어지기 때문에 훨씬 더 나은 디자인입니다.
즉, findAction () 메소드가 의미있는 오류 메시지 (특히이 경우 사용자 입력에 의존하는 경우)와 함께 예외를 발생시키는 것이 전적으로 적합 할 것입니다. findAction 메소드가 설명없이 간단한 NullPointerException으로 날아가는 것보다 Exception을 던지는 것이 훨씬 좋습니다.
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
또는 시도 / 잡기 메커니즘이 너무 추악하다고 생각되면 아무 것도하지 말고 기본 동작이 사용자에게 피드백을 제공해야합니다.
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}
답변
JetBrains IntelliJ IDEA , Eclipse 또는 Netbeans 와 같은 Java IDE 또는 findbugs와 같은 도구를 사용하거나 사용하려는 경우 주석을 사용하여이 문제를 해결할 수 있습니다.
기본적으로 @Nullable
및 @NotNull
.
다음과 같이 메소드 및 매개 변수에 사용할 수 있습니다.
@NotNull public static String helloWorld() {
return "Hello World";
}
또는
@Nullable public static String helloWorld() {
return "Hello World";
}
두 번째 예제는 컴파일되지 않습니다 (IntelliJ IDEA에서).
helloWorld()
다른 코드에서 첫 번째 함수 를 사용하는 경우 :
public static void main(String[] args)
{
String result = helloWorld();
if(result != null) {
System.out.println(result);
}
}
이제 IntelliJ IDEA 컴파일러는 helloWorld()
함수 가을 반환하지 않기 때문에 검사가 쓸모 없다고 알려줍니다 null
.
매개 변수 사용
void someMethod(@NotNull someParameter) { }
다음과 같이 쓰면 :
someMethod(null);
컴파일되지 않습니다.
사용하는 마지막 예 @Nullable
@Nullable iWantToDestroyEverything() { return null; }
이렇게
iWantToDestroyEverything().something();
그리고 당신은 이것이 일어나지 않을 것이라고 확신 할 수 있습니다. 🙂
컴파일러가 평소보다 더 많은 것을 확인하고 계약을 강화하도록하는 좋은 방법입니다. 불행히도 모든 컴파일러에서 지원하지는 않습니다.
IntelliJ IDEA 10.5 이상에서는 다른 @Nullable
@NotNull
구현에 대한 지원을 추가했습니다 .
보다 유연하고 구성 가능한 @ Nullable / @ NotNull 주석 블로그 게시물을 참조하십시오 .
답변
널값이 허용되지 않는 경우
메소드가 외부에서 호출되면 다음과 같이 시작하십시오.
public void method(Object object) {
if (object == null) {
throw new IllegalArgumentException("...");
}
그런 다음 나머지 방법에서 이것이 object
null이 아님을 알 수 있습니다.
내부 메소드 (API의 일부가 아닌) 인 경우 null이 될 수 없다는 것을 문서화하십시오.
예:
public String getFirst3Chars(String text) {
return text.subString(0, 3);
}
그러나 메소드가 값을 전달하고 다음 메소드가 값을 전달하면 문제가 발생할 수 있습니다. 이 경우 위와 같이 인수를 확인하십시오.
널이 허용되는 경우
이것은 실제로 달려 있습니다. 내가 종종 이런 식으로 뭔가를 발견하면 :
if (object == null) {
// something
} else {
// something else
}
그래서 저는 분기하고 완전히 다른 두 가지 일을합니다. 데이터에 따라 두 가지 다른 작업을 수행해야하기 때문에 추악한 코드 스 니펫이 없습니다. 예를 들어 입력 작업을 수행해야합니까, 아니면 올바른 기본값을 계산해야합니까?
관용구 ” if (object != null && ...
” 를 사용하는 것은 실제로 드 rare니다 .
일반적으로 관용구를 사용하는 위치의 예를 보여 주면 예를 제공하는 것이 더 쉬울 수 있습니다.
답변
와우, 나는 우리가 57 가지 다른 방법을 추천 할 때 또 다른 대답을 추가하는 것을 거의 싫어 NullObject pattern
하지만,이 질문에 관심이있는 사람들은 Java 7에 대해 “null-safe” 를 추가하라는 제안이 있다는 것을 알고 싶어 할 것입니다 handling “ — if-nqual-null 논리를위한 간소화 된 구문.
Alex Miller가 제공 한 예는 다음과 같습니다.
public String getPostcode(Person person) {
return person?.getAddress()?.getPostcode();
}
?.
만 디 레퍼런스가 널이 아닌 경우 좌측 식별자 수단은 그렇지 같은 식의 나머지를 평가 null
. Java Posse 회원 Dick Wall 및 Devoxx 의 유권자 와 같은 일부 사람들 은이 제안을 정말 좋아하지만 실제로 null
는 센티넬 가치로 더 많이 사용하도록 장려한다는 반대 입장도 있습니다.
업데이트 : Java 7의 null 안전 연산자에 대한 공식 제안 이 Project Coin 에 제출되었습니다 . 구문은 위의 예제와 약간 다르지만 같은 개념입니다.
업데이트 : null 안전 연산자 제안서가 Project Coin으로 제안되지 않았습니다. 따라서 Java 7에서는이 구문이 표시되지 않습니다.
답변
정의되지 않은 값이 허용되지 않는 경우 :
잠재적 인 null 역 참조에 대해 경고하도록 IDE를 구성 할 수 있습니다. 예를 들어 Eclipse에서 환경 설정> Java> 컴파일러> 오류 / 경고 / 널 분석을 참조하십시오 .
정의되지 않은 값이 허용되는 경우 :
정의되지 않은 값이 적합한 새 API를 정의 하려면 옵션 패턴을 사용하십시오 (기능적 언어에 익숙 할 수 있음). 다음과 같은 장점이 있습니다.
- 입력 또는 출력이 존재하는지 여부는 API에 명시 적으로 명시되어 있습니다.
- 컴파일러는 “정의되지 않은”경우를 처리하도록합니다.
- 옵션은 모나드 이므로 자세한 null 검사가 필요하지 않습니다. map / foreach / getOrElse 또는 유사한 결합기를 사용하여 값을 안전하게 사용하십시오 (example) .
Java 8에는 내장 Optional
클래스가 있습니다 (권장). 이전 버전, 라이브러리 대안이 있습니다 예를 들어, 구아바 의 Optional
또는 FunctionalJava 의 Option
. 그러나 많은 기능적 스타일 패턴과 마찬가지로 Java에서 옵션 (8 개)을 사용하면 상당히 약간의 상용구가 생겨서 Scala 또는 Xtend와 같이 덜 장황한 JVM 언어를 사용하여 줄일 수 있습니다.
null을 반환 할 수 있는 API를 처리해야하는 경우 Java에서 많은 작업을 수행 할 수 없습니다. Xtend와 Groovy는 Elvis 연산자 ?:
와 null 안전 역 참조 연산자 ?.
를 가지고 있지만 null 참조의 경우 null을 반환하므로 null의 적절한 처리를 “정의”합니다.
답변
이 상황에서만-
equals 메서드를 호출하기 전에 변수가 null인지 확인하지 않음 (아래 문자열 비교 예) :
if ( foo.equals("bar") ) {
// ...
}
A의 발생합니다 NullPointerException
경우 foo
존재하지 않습니다.
다음 String
과 같이 비교하면 피할 수 있습니다 .
if ( "bar".equals(foo) ) {
// ...
}
답변
Java 8에는 java.util.Optional
문제의 일부를 해결 하는 새로운 클래스가 있습니다. 적어도 코드의 가독성을 향상시키고 퍼블릭 API의 경우 API 계약을 클라이언트 개발자에게 명확하게 만들 수 있다고 말할 수 있습니다.
그들은 다음과 같이 작동합니다.
주어진 유형 ( Fruit
)에 대한 선택적 객체 는 메소드의 리턴 유형으로 작성됩니다. 비어 있거나 Fruit
개체를 포함 할 수 있습니다 .
public static Optional<Fruit> find(String name, List<Fruit> fruits) {
for (Fruit fruit : fruits) {
if (fruit.getName().equals(name)) {
return Optional.of(fruit);
}
}
return Optional.empty();
}
이제 주어진 Fruit 인스턴스에 대한 Fruit
( fruits
) 목록을 검색하는이 코드를 살펴보십시오 .
Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
Fruit fruit = found.get();
String name = fruit.getName();
}
map()
연산자를 사용하여 선택적 객체에서 계산을 수행하거나 값을 추출 할 수 있습니다 . orElse()
결 측값을 대체 할 수 있습니다.
String nameOrNull = find("lemon", fruits)
.map(f -> f.getName())
.orElse("empty-name");
물론, null / empty 값에 대한 점검은 여전히 필요하지만 최소한 개발자는 값이 비어있을 수 있음을 인식하고 점검 잊어 버릴 위험이 제한적입니다.
Optional
반환 값이 비어있을 때마다 사용하고 처음부터 일반 객체를 반환 할 수없는 경우 null
(컨벤션)를 사용하여 처음부터 빌드 한 API에서 클라이언트 코드는 간단한 객체 반환 값에 대한 null 검사를 포기할 수 있습니다 …
물론 Optional
메소드 인수로 사용될 수도 있습니다. 경우에 따라 5 또는 10 개의 오버로드 메소드보다 선택적 인수를 나타내는 더 좋은 방법 일 수도 있습니다.
Optional
orElse
기본값을 사용 ifPresent
하고 람다 식과 함께 작동 하는 것과 같은 다른 편리한 방법을 제공합니다 .
이 기사 (이 답변을 작성하는 주요 소스)를 읽고 NullPointerException
문제가 있는 (및 일반적으로 null 포인터) 문제와 (일부) 솔루션에 Optional
대해 잘 설명 된 Java Optional Objects 를 읽으십시오 .