메서드에서 반환 된 null 값을 확인하는 것이 나쁜 디자인이라는 일부 목소리가 들렸습니다. 이에 대한 몇 가지 이유를 듣고 싶습니다.
의사 코드 :
variable x = object.method()
if (x is null) do something
메서드에서 반환 된 null 값을 확인하는 것이 나쁜 디자인이라는 일부 목소리가 들렸습니다. 이에 대한 몇 가지 이유를 듣고 싶습니다.
의사 코드 :
variable x = object.method()
if (x is null) do something
답변:
null을 반환하지 않는 이유는 확인하지 않아도되므로 코드가 반환 값에 따라 다른 경로 를 따를 필요가 없다는 것 입니다. 널 오브젝트 패턴 을 확인하고 싶을 수도 있습니다. 대한 자세한 정보를 제공 .
예를 들어, 컬렉션을 반환하는 Java에서 메소드를 정의하려는 경우 일반적으로 Collections.emptyList()
클라이언트 코드가 더 깨끗하다는 의미에서 null 대신 빈 컬렉션을 반환하는 것을 선호합니다 . 예 :
Collection<? extends Item> c = getItems(); // Will never return null.
for (Item item : c) { // Will not enter the loop if c is empty.
// Process item.
}
...보다 깨끗한 것 :
Collection<? extends Item> c = getItems(); // Could potentially return null.
// Two possible code paths now so harder to test.
if (c != null) {
for (Item item : c) {
// Process item.
}
}
null
는 "컨테이너"이며 객체에 대한 포인터가 0 개 또는 1 개 있습니다. (그런 Maybe
경우 Haskell의 모델이 어떻게 만들어 졌는지 확실히 알 수 있습니다.)
그 이유가 있습니다.
에 로버트 마틴 클린 코드 그는 널 (null)을 반환하는 것은 나쁜 대신 반환 할 수 있습니다 디자인, 말, 빈 배열이라고 씁니다. 예상 결과가 배열이므로 왜 안됩니까? 추가 조건없이 결과를 반복 할 수 있습니다. 정수이면 해시, 빈 해시이면 0이면 충분합니다. 기타
전제는 문제를 즉시 처리하도록 호출 코드를 강요하지 않는 것입니다. 호출 코드는 그들 자신과 관련이 없을 수도 있습니다. 그렇기 때문에 많은 경우에 예외가 nil보다 낫습니다.
null을 반환하는 좋은 사용법 :
나쁜 용도 : 다음과 같은 예외적 인 상황을 대체하거나 숨기려고합니다.
이러한 경우에 예외를 던지는 것이 더 적합합니다.
그러나 다음과 같은 정상적인 프로그램 작동 조건을 처리하는 데 예외를 사용해서는 안됩니다.
boolean login(String,String)
보인다 .AuthenticationContext createAuthContext(String,String) throws AuthenticationException
예, 객체 지향 세계에서 NULL을 반환하는 것은 끔찍한 디자인 입니다. 간단히 말해서 NULL 사용법은 다음과 같습니다.
: 자세한 설명이 블로그 게시물 확인 http://www.yegor256.com/2014/05/13/why-null-is-bad.html을 . 나의 책에서 더 많은 것은 우아한 객체들 , 섹션 4.1.
bool TryGetBlah(out blah)
하거나 FirstOrNull()
또는 MatchOrFallback(T fallbackValue)
.
isEmpty()
true). 사람들은 두 번째 주장에 대해 성능이 떨어 졌다고 주장합니다. 그러나 Unix Philosophy가 말했듯이 "기계 시간보다 인간의 시간을 소중하게 생각합니다"(즉, 성능이 느리면 개발자가 코드를 디버깅하는 것보다 허위 오류가 발생합니다).
이것이 나쁜 디자인이라고 누가 말합니까?
null 검사는 일반적인 관행이며 권장되는 경우도 있습니다. 필요하지 않을 때 예외를 throw하는 것보다 오류를 정상적으로 처리하는 것이 좋습니다.
지금까지 말씀하신 내용에 의하면 충분한 정보가 없다고 생각합니다.
CreateWidget () 메소드에서 null을 반환하는 것은 좋지 않은 것 같습니다.
FindFooInBar () 메서드에서 null을 반환하는 것이 좋습니다.
Create...
새 인스턴스를 반환 하거나 던집니다 . Get...
예상되는 기존 인스턴스를 반환 하거나 throw합니다 . GetOrCreate...
기존 인스턴스를 반환하거나 존재하지 않는 경우 새 인스턴스를 반환 하거나 throw합니다 . Find...
존재하는 경우, 기존 인스턴스를 반환 하거나null
. 컬렉션 쿼리의 경우- Get...
항상 컬렉션을 반환합니다. 일치하는 항목이 없으면 비어 있습니다.
사용중인 언어에 따라 다릅니다. 값이 없음을 나타내는 관용적 방법이 null을 반환하는 C #과 같은 언어 인 경우 값이 없으면 null을 반환하는 것이 좋습니다. 또는이 경우에 Maybe 모나드를 관용적으로 사용하는 Haskell과 같은 언어에서는 null을 반환하는 것이 좋지 않은 디자인입니다 (가능한 경우).
null
C # 및 Java와 같은 언어 의 정의 가 종종 과부하되어 도메인에서 의미가 있음을 알았습니다 . null
언어 사양에서 키워드 를 찾으면 단순히 "잘못된 포인터"를 의미합니다. 그것은 문제 영역에서 아무것도 의미하지 않습니다.
null
인지 "초기화되지 않은 " 것인지 모르는 경우null
모든 답변을 읽으면이 질문에 대한 답변은 방법의 종류에 따라 다릅니다.
첫째, 예외적 인 상황 (IO 문제 등)이 발생하면 논리적으로 예외가 발생합니다. 정확히 무언가가 예외적 인 경우 아마도 다른 주제에 대한 것일 수 있습니다.
분석법에 결과가 없을 것으로 예상 될 때마다 두 가지 범주가 있습니다.
함수가 null을 반환 할 수 있거나 반환 할 수 없다는 공식적인 방법이있을 때까지는 명명 규칙을 지정하려고합니다. 실패 할 것으로 예상되는 메소드에 대해 Try Something () 규칙
이있는 것처럼 , 종종 메소드 이름을 Safe Something ()으로 지정합니다. 방법이 null 대신 중립적 인 결과를 반환 할 때입니다.
나는 아직 그 이름을 완전히 알지 못했지만 더 나은 것을 만들 수 없었습니다. 그래서 나는 지금 그것을 가지고 달리고 있습니다.
이 분야에서 저를 잘 섬기는 대회가 있습니다
단일 항목 쿼리의 경우 :
Create...
새 인스턴스를 반환 하거나Get...
예상되는 기존 인스턴스를 반환 하거나GetOrCreate...
기존 인스턴스를 반환하거나 존재하지 않는 경우 새 인스턴스를 반환 하거나Find...
존재하는 경우 기존 인스턴스를 반환 하거나null
수집 쿼리의 경우 :
Get...
일치하는 [1] 개의 항목이 없으면 항상 비어있는 컬렉션을 반환합니다.[1] 함수 이름 또는 매개 변수로 주어진 명시 적 또는 암시 적 기준이 제공됩니다.
Get
때 사용 하므로 거기에 없다면 오류가 발생하고 던져집니다-반환 값을 확인할 필요가 없습니다. 나는 그것이 있는지 여부를 정말로 모른다면 사용합니다-그런 다음 반환 값을 확인해야합니다. Find
예외는 예외 상황에 대한 것입니다.
함수가 주어진 객체와 관련된 속성을 찾으려고하고 해당 객체에 그러한 속성이없는 경우 null을 반환하는 것이 적절할 수 있습니다. 객체가 존재하지 않으면 예외를 던지는 것이 더 적절할 수 있습니다. 함수가 속성 목록을 반환하는 것이지만 반환 할 것이 없으면 빈 목록을 반환하는 것이 의미가 있습니다. 모든 속성을 0으로 반환하는 것입니다.
어떤 식 으로든 의미가있는 경우 null을 반환하는 것이 좋습니다.
public String getEmployeeName(int id){ ..}
이와 같은 경우 ID가 기존 엔티티와 일치하지 않으면 null을 반환하는 것이 의미가 있습니다. 정상적인 오류와 일치하는 것이없는 경우를 구별 할 수 있기 때문입니다.
사람들은 이것이 오류 조건을 나타내는 "특별한"반환 값으로 남용 될 수 있기 때문에 이것이 잘못되었다고 생각할 수 있습니다. 이는 좋지 않은 기능에서 오류 코드를 반환하는 것과 약간 같지만 사용자가 반환을 확인해야하기 때문에 혼란 스럽습니다. 적절한 예외를 잡는 대신에 null
public Integer getId(...){
try{ ... ; return id; }
catch(Exception e){ return null;}
}
많은 디자인 결정과 마찬가지로 반드시 나쁜 디자인은 아닙니다.
메소드의 결과가 정상적인 사용에서 좋은 결과를 얻지 못하는 것이라면 null을 반환하는 것이 좋습니다.
object x = GetObjectFromCache(); // return null if it's not in the cache
항상 널이 아닌 결과가 있어야하는 경우 예외를 처리하는 것이 좋습니다.
try {
Controller c = GetController(); // the controller object is central to
// the application. If we don't get one,
// we're fubar
// it's likely that it's OK to not have the try/catch since you won't
// be able to really handle the problem here
}
catch /* ... */ {
}
Optional<>
null을 반환하는 대안은 무엇입니까?
두 가지 경우가 있습니다.
이 경우에는 다음을 수행 할 수 있습니다. Null을 반환하거나 (확인 된) 예외를 throw하거나 항목을 만들어 반환 할 수 있습니다.
이 경우 Null을 반환하거나 빈 목록을 반환하거나 예외를 throw 할 수 있습니다.
나는 null을 반환하는 것이 클라이언트가 null을 확인해야한다는 것을 기억해야하기 때문에 대안보다 좋지 않을 수 있다고 생각합니다. 프로그래머는 잊어 버리고 코드를 작성해야합니다.
x = find();
x.getField(); // bang null pointer exception
Java에서 확인 된 예외 인 RecordNotFoundException을 발생 시키면 컴파일러가 클라이언트에게 사례를 처리하도록 상기시킬 수 있습니다.
빈 목록을 반환하는 검색이 매우 편리하다는 것을 알았습니다. 목록의 모든 내용으로 디스플레이를 채우십시오. 오, 비어 있습니다. 코드는 "작동합니다".
이전 호출이 null인지 확인하기 위해 사실 후에 다른 메소드를 호출하게하십시오. ;-) 이봐, JDBC에 충분 했어
이 스레드의 기본 아이디어는 방어 적으로 프로그래밍하는 것입니다. 즉, 예상치 못한 코드입니다. 다른 답글이 있습니다 :
아담 스키 는 Null Object Pattern (Null 개체 패턴)을 검토 할 것을 제안합니다.
Michael Valenty 는 또한 개발자에게 예상 할 수있는 것을 알려주기위한 명명 규칙을 제안합니다. ZeroConcept 는 NULL의 이유 인 경우 Exception의 올바른 사용을 제안합니다. 다른 사람.
우리가 항상 방어 프로그래밍을하고 싶은 "규칙"을 만들면 이러한 제안이 유효한 것을 볼 수 있습니다.
그러나 우리에게는 두 가지 개발 시나리오가 있습니다.
개발자가 "저작 한"클래스 : 저자
다른 (아마도) 개발자가 "소비 한"클래스 : 개발자
반환 값이있는 메서드에 대해 클래스가 NULL을 반환하는지 여부에 관계없이 개발자는 개체가 유효한지 테스트해야합니다.
개발자가이를 수행 할 수없는 경우 해당 클래스 / 방법은 결정적이지 않습니다. 즉, 객체를 얻기위한 "메소드 호출"이 "광고"(예 : getEmployee)를 수행하지 않으면 계약을 위반 한 것입니다.
수업의 저자로서, 나는 항상 메소드를 만들 때 친절하고 방어 적이며 결정론 적이기를 원합니다.
따라서 NULL 또는 NULL OBJECT (예 : if (employee as NullEmployee.ISVALID))를 확인해야하고 Employees 컬렉션에서 발생할 수있는 경우 null 개체 접근 방식이 더 좋습니다.
그러나 마이클 발레 티 (Michael Valenty)의 getEmployeeOrNull과 같이 null을 반환 해야하는 메서드의 이름을 제안하는 것도 좋습니다.
예외를 던지는 작성자는 개발자가 객체의 유효성을 테스트 할 수있는 선택권을 제거하는 것입니다. 이는 객체 모음에서 매우 나쁘고 개발자가 소비 코드를 분기 할 때 예외 처리를 강요합니다.
클래스를 소비하는 개발자로서 필자는 클래스 / 메소드가 직면 할 수있는 null 상황을 피하거나 프로그램 할 수있는 기능을 제공하기를 희망한다.
따라서 개발자는 메소드에서 NULL에 대해 방어 적으로 프로그래밍합니다. 저자가 항상 객체를 반환하는 계약 (NULL OBJECT가 항상 수행하는 계약)을 제공하고 해당 객체에 객체의 유효성을 테스트하는 메소드 / 프로퍼티가있는 경우 해당 메소드 / 프로퍼티를 사용하여 객체를 계속 사용합니다. 그렇지 않으면 객체가 유효하지 않아 사용할 수 없습니다.
결론은 클래스 / 메소드 작성자가 개발자가 방어 프로그래밍에 사용할 수있는 메커니즘을 제공해야한다는 것입니다. 즉, 방법의 명확한 의도입니다.
개발자는 항상 방어 적 프로그래밍을 사용하여 다른 클래스 / 방법에서 반환 된 객체의 유효성을 테스트해야합니다.
문안 인사
그레그
이것에 대한 다른 옵션은 다음과 같습니다 : 성공 여부를 나타내는 일부 값을 반환 (또는 오류 유형)하지만 성공 / 실패를 나타내는 부울 값이 필요한 경우 실패에 대해 null을 반환하고 성공에 대한 객체는 그렇지 않습니다 덜 정확한 다음 true / false를 반환하고 매개 변수를 통해 객체를 가져옵니다.
다른 접근법은 예외를 사용하여 실패를 표시하지만 여기에는 실제로 더 많은 음성이 있습니다. 예를 들어 이것이 나쁜 습관이라고 말합니다 (예외를 사용하는 것이 편리하지만 많은 단점이 있음).
그래서 개인적으로 무언가 잘못되었다는 표시로 null을 반환하고 나중에 확인하여 실제로 성공했는지 여부를 확인하는 데 나쁜 점은 없습니다. 또한, 맹목적으로 메소드가 NULL을 반환하지 않는다고 생각하고 코드를 기반으로하고 때로는 찾기 어려운 다른 오류가 발생할 수 있습니다 (대부분의 경우 시스템을 중단시킬 수는 있음). 조만간 0x00000000).
의도하지 않은 널 함수는 복잡한 프로그램을 개발하는 동안 발생할 수 있으며 데드 코드와 같이 이러한 발생은 프로그램 구조에 심각한 결함이 있음을 나타냅니다.
null 함수 또는 메소드는 종종 객체 프레임 워크에서 revectorable 함수 또는 재정의 가능한 메소드의 기본 동작으로 사용됩니다.
코드가 다음과 같은 경우 :
command = get_something_to_do()
if command: # if not Null
command.execute()
execute () 메소드가 아무것도하지 않는 더미 객체가 있고 적절한 경우 Null 대신 반환하면 Null 케이스를 확인할 필요가 없으며 대신 수행 할 수 있습니다.
get_something_to_do().execute()
따라서 여기서 문제는 NULL 검사와 예외 검사 사이가 아니라 호출자가 특수한 경우를 다르게 처리 해야하는 경우 (어떤 방식 으로든) 사이입니다.
G'day,
새 객체를 만들 수 없을 때 NULL을 반환하는 것은 많은 API의 표준 사례입니다.
도대체 왜 나쁜 디자인인지 모르겠다.
편집 : 이것은 몇 년 동안 관습이었던 C와 같이 예외가없는 언어의 경우에 해당됩니다.
HTH
'아바 해피,