null 참조는 실제로 나쁜 것입니까?


161

프로그래밍 언어에 null 참조를 포함시키는 것이 "십억 달러의 실수"라고 들었습니다. 그런데 왜? 물론 NullReferenceExceptions이 발생할 수 있지만 무엇을해야합니까? 잘못 사용하면 언어의 모든 요소가 오류의 원인이 될 수 있습니다.

그리고 대안은 무엇입니까? 나는 이것을 말하는 대신에 :

Customer c = Customer.GetByLastName("Goodman"); // returns null if not found
if (c != null)
{
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

당신은 이것을 말할 수 있습니다 :

if (Customer.ExistsWithLastName("Goodman"))
{
    Customer c = Customer.GetByLastName("Goodman") // throws error if not found
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!"); 
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

그러나 그것은 어떻게 더 낫습니까? 어느 쪽이든 고객이 존재하는지 확인하는 것을 잊어 버리면 예외가 발생합니다.

더 설명하기 때문에 CustomerNotFoundException이 NullReferenceException보다 디버깅하기가 조금 더 쉽다고 가정합니다. 그게 전부입니까?


54
나는 "고객이 존재하면 고객을 얻는다"라는 접근 방식에주의를 기울여야한다. 그런 코드를 두 줄 작성하자마자 경쟁 조건에 대한 문을 여는 것이다. 확인 후 null 확인 / 캐치 예외가 더 안전합니다.
Carson63000

26
모든 런타임 오류의 원인을 제거 할 수만 있다면 코드가 완벽 할 것입니다! C #에서 NULL 참조가 두뇌를 손상시키는 경우 C에서 유효하지만 NULL이 아닌 포인터를 시도하십시오.;)
LnxPrgr3

일부 언어에서 널 유착 및 안전한 항해 운영자는 생각이 있습니다
JK는.

35
null 자체는 나쁘지 않습니다. 타입 T와 타입 T + 널 사이에 차이가없는 타입 시스템은 나쁘다.
Ingo

27
몇 년 후 내 자신의 질문으로 돌아와서, 나는 이제 완전히 옵션 / 어쩌면 접근법의 개종자입니다.
Tim Goodman

답변:


91

널은 악하다

:이 주제에 InfoQ에 대한 프리젠 테이션이 널 참고 : 억 달러 실수 에 의한 토니 호어은

옵션 종류

함수형 프로그래밍에서 대안이 사용하는 옵션 유형 , 즉 포함 할 수 있습니다 SOME value또는 NONE.

좋은 기사 옵션 유형에 대해 논의하고 Java에 대한 구현을 제공하는 “옵션”패턴 .

또한이 문제에 대해 Java에 대한 버그 보고서를 발견했습니다 .NullPointerExceptions을 방지하기 위해 Java에 Nice Option 유형을 추가하십시오 . 요청 기능은 자바 8에 도입되었다.


5
C #의 Nullable <x>는 비슷한 개념이지만 옵션 패턴을 구현하는 데는 부족합니다. 주요 이유는 .NET System.Nullable이 값 유형으로 제한되어 있기 때문입니다.
MattDavey

27
+1 옵션 유형. Haskell 's Maybe에 익숙해지면 , 널이 이상해 보이기 시작합니다 ...
Andres F.

5
개발자는 어디에서나 오류를 만들 수 있으므로 null 포인터 예외 대신 빈 옵션 예외가 발생합니다. 후자가 전자보다 어떻게 낫습니까?
greenoldman

7
@greenoldman "빈 옵션 예외"와 같은 것은 없습니다. NOT NULL로 정의 된 데이터베이스 열에 NULL 값을 삽입하십시오.
조나스

36
@greenoldman nulls의 문제점은 무엇이든 null 일 수 있으며 개발자는 조심해야한다는 것입니다. String유형이 아닌 정말 문자열. 그것은 A의 String or Null유형입니다. 옵션 유형의 아이디어를 완전히 준수하는 언어는 유형 시스템에서 널값을 허용하지 않으므로 String(또는 다른 것) 이 필요한 유형 서명을 정의 하면 값 이 있어야 함 을 보증 합니다. Option유형은 가지의 유형 수준의 표현을주고있다 거나하지 않을 수도 있습니다 값이를, 그래서 당신은 당신이 명시 적으로 이러한 상황을 처리해야합니다 어디 있는지.
KChaloux

127

문제는 이론적으로 모든 객체가 null 일 수 있으며 사용하려고 할 때 예외를 던지기 때문에 객체 지향 코드는 기본적으로 폭발하지 않은 폭탄의 모음입니다.

정상적인 오류 처리는 기능적으로 널 검사 if명령문 과 동일 할 수 있습니다 . 뭔가 자신이 없습니다 확신 때 어떤 일이 발생 가능성이 널은, 사실, null의 수? 커붐. 다음에 어떤 일이 발생하든, 나는 1) 우아하지 않을 것이고 2) 당신이 그것을 좋아하지 않을 것이라고 기꺼이합니다.

"디버그하기 쉬운"의 가치를 무시하지 마십시오. 성숙한 생산 코드는 화를내는 거대한 생물입니다. 무엇이 잘못되었는지에 대한 통찰력을 제공하고 발굴 시간을 절약 할 수있는 모든 것을 제공합니다.


27
+1 보통 생산 코드에서 오류가 필요해 가 고정 될 수 있도록 가능한 한 빨리 확인 (일반적으로 데이터 오류) 할 수 있습니다. 디버깅이 쉬울수록 좋습니다.

4
이 답변은 OP의 예 중 하나에 적용되는 경우에도 동일합니다. 오류 조건을 테스트하거나 그렇지 않은 경우 오류를 정상적으로 처리하거나 처리하지 않습니다. 다시 말해, 언어에서 null 참조를 제거해도 발생하는 오류 클래스는 변경되지 않으며 오류의 표시를 미묘하게 변경합니다.
dash-tom-bang

19
폭발하지 않은 폭탄의 경우 +1 null 참조의 경우 public Foo doStuff()"물건을 수행하고 Foo 결과 반환"을 의미하는 것은 "물건을 수행하고 Foo 결과를 반환하거나 null을 반환하지만"라는 의미는 없습니다. 결과적으로 확실하게 null 검사를해야합니다. 의미없는 값을 나타 내기 위해 널을 제거하고 값 유형과 같은 특수 유형 또는 패턴을 사용할 수 있습니다.
Matt Olenik

12
@greenoldman, 시맨틱 모델로 프리미티브 유형 (널 또는 정수)을 사용하는 것이 좋지 않다는 점에서 우리의 요점을 설명하는 데 두 가지 예가 있습니다. 음수가 유효한 답이 아닌 유형이있는 경우 해당 의미로 시맨틱 모델을 구현할 새 유형의 유형을 작성해야합니다. 이제 음이 아닌 유형의 모델링을 처리하는 모든 코드가 시스템의 나머지 부분과 분리되어 해당 클래스에 현지화되어 있으며 음수 값을 작성하려는 시도는 즉시 포착 할 수 있습니다.
Huperniketes

9
@greenoldman, 프리미티브 유형이 모델링에 적합하지 않다는 점을 계속 증명합니다. 처음에는 음수가 넘었습니다. 이제 0이 제수 일 때 나누기 연산자가 끝났습니다. 0으로 나눌 수 없다는 것을 알고 있다면 결과가 예쁘지 않을 것으로 예상 할 있으며 테스트를 보장하고 해당 사례에 적합한 "유효한"값을 제공 할 책임이 있습니다. 소프트웨어 개발자는 코드가 작동하는 매개 변수를 알고 적절하게 코딩해야합니다. 공학을 땜질과 구별하는 것입니다.
Huperniketes 2016

50

코드에서 null 참조를 사용하는 데 몇 가지 문제가 있습니다.

첫째, 일반적으로 특수 상태 를 나타내는 데 사용됩니다 . 전문화가 정상적으로 수행 될 때 각 상태에 대해 새 클래스 또는 상수를 정의하는 대신 null 참조를 사용하면 손실이 많고 일반화 된 유형 / 값이 사용 됩니다.

둘째, null 참조가 나타날 때 디버깅 코드가 더 어려워지고이를 참조 하여 생성 된 항목 , 적용되는 상태 및 업스트림 실행 경로를 추적 할 수있는 원인 을 파악하려고 시도 합니다.

셋째, null 참조는 테스트 할 추가 코드 경로를 도입 합니다.

넷째, 반환 값뿐만 아니라 매개 변수의 유효한 상태로 null 참조가 사용되면 방어 프로그래밍 (디자인으로 인해 발생한 상태의 경우)은 다양한 경우에 대비 하여 더 많은 null 참조 검사를 수행해야합니다 .

다섯째, 언어의 런타임은 객체의 메소드 테이블에서 선택기 조회를 수행 할 때 이미 유형 검사 를 수행하고 있습니다. 따라서 객체 유형이 유효한지 여부를 확인한 다음 런타임에서 유효한 객체 유형을 확인하여 해당 메소드를 호출함으로써 노력을 복제합니다.

NullObject 패턴 을 사용하여 런타임 상태 확인활용 하여 해당 상태에 특정한 NOP 메소드를 호출 하고 (일반 상태의 인터페이스에 부합) 코드베이스 전체에서 널 참조에 대한 모든 추가 검사를 제거하지 않습니까?

특별한 상태를 나타내려는 각 인터페이스에 대해 NullObject 클래스를 만들어 더 많은 작업필요 합니다. 그러나 적어도 특수화는 상태가 존재할 수있는 코드가 아닌 각 특수 상태로 격리 됩니다. IOW, 메소드에 대체 실행 경로적기 때문에 테스트 수가 줄어 듭니다 .


7
... 유용한 객체를 채우는 가비지 데이터를 누가 생성했는지 (또는 오히려 변경하거나 초기화하지 않았는지) 알아내는 것이 NULL 참조를 추적하는 것보다 훨씬 쉽습니다? 나는 정적으로 타이핑 된 땅에 갇혀 있지만, 나는 그것을 사지 않습니다.
dash-tom-bang

그러나 쓰레기 데이터는 null 참조보다 훨씬 드 rare니다. 특히 관리되는 언어로.
Dean Harding

5
널 오브젝트의 경우 -1입니다.
DeadMG

4
포인트 (4)와 (5)는 단단하지만 NullObject는 해결책이 아닙니다. 트랩 (논리 (워크 플로우) 오류)이 더 나빠질 수 있습니다. 현재 상황을 정확히 알고 있으면 도움이 될 수 있지만 맹목적으로 (null 대신) 사용하면 비용이 더 많이 듭니다.
greenoldman

1
@ gnasher729, Objective-C의 런타임은 Java 및 다른 시스템과 같이 null 포인터 예외를 throw하지 않지만 대답에 요약 된 이유로 null 참조를 더 잘 사용하지 않습니다. 예를 들어, [self.navigationController.presentingViewController dismissViewControllerAnimated: YES completion: nil];런타임에 navigationController 가 없으면 일련의 no-ops로 처리하지 않으면 뷰가 디스플레이에서 제거되지 않으며 Xcode 앞에 앉아 몇 시간 동안 머리를 긁는 이유를 알아낼 수 있습니다.
Huperniketes

48

널을 기대하지 않는 한 널은 그렇게 나쁘지 않습니다. 당신은 해야 명시 적으로 언어 설계 문제 당신이 널 기다리고있어 코드에 지정해야합니다. 이걸 고려하세요:

Customer? c = Customer.GetByLastName("Goodman");
// note the question mark -- 'c' is either a Customer or null
if (c != null)
{
    // c is not null, therefore its type in this block is
    // now 'Customer' instead of 'Customer?'
    Console.WriteLine(c.FirstName + " " + c.LastName + " is awesome!");
}
else { Console.WriteLine("There was no customer named Goodman.  How lame!"); }

에서 메소드를 호출하려고 Customer?하면 컴파일 타임 오류가 발생합니다. 더 많은 언어가 이것을하지 않는 이유 (IMO)는 변수의 범위에 따라 변수의 유형을 변경하지 않기 때문입니다. 언어가 처리 할 수 ​​있다면, 문제는 완전히 해결 될 수 있습니다. 유형 시스템.

옵션 유형과를 사용 하여이 문제를 처리하는 기능적인 방법도 Maybe있지만 익숙하지는 않습니다. 올바른 코드는 이론적으로 올바르게 컴파일하기 위해 하나의 문자 만 추가하면되기 때문에이 방법을 선호합니다.


11
와우, 정말 멋지다. 컴파일 시간에 더 많은 오류를 잡기 이외에, 그것은 여부를 파악하기 위해 설명서를 확인하는 데에서 저를 여분 GetByLastName이 반환하는 경우 난 그냥 볼 수 있습니다 - 발견되지 않는 경우는 (예외를 던지는 반대) 반환 널 (null) Customer?Customer.
Tim Goodman

14
@JBRWilkinson : 이것은 실제 구현의 예가 아니라 아이디어를 보여주는 요리 된 예일뿐입니다. 나는 실제로 그것이 꽤 깔끔한 생각이라고 생각합니다.
Dean Harding

1
그러나 이것이 null 객체 패턴이 아니라는 것이 맞습니다.
Dean Harding

13
이 하스켈이 부르는처럼 보이는 Maybe- A는 Maybe Customer중입니다 Just c(여기서 cCustomer) 또는 Nothing. 다른 언어에서는 Option이 질문에 대한 다른 답변을 참조하십시오.
MatrixFrog

2
@SimonBarker : 유형이 아닌지 확인할 있습니다 (와 반대 ). 이것이 진정한 이점입니다. 의미있는 값이 없는 변수 / 속성 만 nullable로 선언해야합니다. Customer.FirstNameStringString?
Yogu

20

의 불행한 증상을 다루는 훌륭한 답변이 많이 null있으므로 대체 인수를 제시하고 싶습니다. Null은 유형 시스템의 결함입니다.

유형 시스템의 목적은 프로그램의 다른 구성 요소가 "함께 적합"하도록 보장하는 것입니다. 잘 짜여진 프로그램은 정의되지 않은 행동으로 "전철을 벗어날"수 없습니다.

Java의 가상 방언 또는 원하는 정적 유형 언어에 관계없이 문자열 "Hello, world!"을 모든 유형의 변수에 지정할 수 있습니다 .

Foo foo1 = new Foo();  // Legal
Foo foo2 = "Hello, world!"; // Also legal
Foo foo3 = "Bonjour!"; // Not legal - only "Hello, world!" is allowed

변수를 다음과 같이 확인할 수 있습니다.

if (foo1 != "Hello, world!") {
    bar(foo1);
} else {
    baz();
}

이것에 대해 불가능한 것은 없습니다. 누군가 원한다면 그러한 언어를 디자인 할 수 있습니다. 특별한 가치는 필요하지 않습니다. "Hello, world!"42, 튜플 (1, 4, 9), 또는 말일 수 null있습니다. 근데 왜 이래? 유형의 변수는 s Foo만 보유해야 Foo합니다. 이것이 유형 시스템의 요점입니다! 그 이상 null은 아닙니다 . 더 나쁜 것은, 어떤 유형 의 가치도 아니며, 당신이 할 수있는 일은 없습니다!Foo"Hello, world!"null

프로그래머는 변수가 실제로을 보유한다고 확신 할 수 없으며 Foo프로그램도 마찬가지입니다. 정의되지 않은 동작을 피하려면 변수를 s "Hello, world!"로 사용하기 전에 변수를 확인해야합니다 Foo. 이전 코드에서 문자열 검사를 수행하는 것은 정말 foo1은 사실을 전달하지 않습니다 Foo- bar가능성 안전을 위해,뿐만 아니라 자신의 체크를해야합니다.

패턴 일치와 함께 Maybe/ Option유형 을 사용하는 것과 비교하십시오 .

case maybeFoo of
 |  Just foo => bar(foo)
 |  Nothing => baz()

Just foo조항 내에서 , 귀하와 프로그램 모두 Maybe Foo변수에 실제로 Foo값 이 포함되어 있음을 알고 있습니다. 즉, 정보가 콜 체인으로 전파 bar되므로 검사를 수행 할 필요가 없습니다. 때문에 Maybe Foo에서 구별 유형 Foo, 당신은 포함 할 수있는 가능성을 처리하도록 강제하고 Nothing, 그래서 당신은 당해서 수 없다 의해 NullPointerException. 프로그램에 대해 훨씬 쉽게 추론 할 수 있으며 컴파일러는 유형의 모든 변수에 Foo실제로 Foos 가 포함되어 있음을 알고 null 검사를 생략 할 수 있습니다 . 모두가 이긴다.


Perl 6의 null과 같은 값은 어떻습니까? 항상 입력되는 것을 제외하고는 여전히 널입니다. 여전히 쓸 수있는 문제 입니까 my Int $variable = Int, Intnull 값은 어디에 Int있습니까?
Konrad Borowski

@xfix 나는 펄에 익숙하지 않은 해요,하지만만큼 당신이 강제하는 방법하지 않는 한 this type only contains integers에 반대를 this type contains integers and this other value, 당신은 문제가 당신이 때마다해야합니다 에만 정수를하고자합니다.
Doval

1
패턴 일치의 경우 +1 위의 옵션 유형에 대한 답변 수가 많으면 패턴 일치 기와 같은 간단한 언어 기능이 null보다 작업을 훨씬 직관적으로 만들 수 있다는 사실을 누군가가 언급했을 것입니다.
Jules

1
나는 모나드 바인딩이 패턴 매칭보다 훨씬 더 유용하다고 생각합니다 (물론 패턴 바인딩을 사용하여 어쩌면 bind가 구현 되더라도). haskell과 같은 언어가 라이브러리 함수로 구현하는 것들에 대해 많은 것들 ( ??, ?.등) 에 특별한 구문을 넣는 C #과 같은 언어를 보는 것이 재미 있다고 생각합니다 . 더 깔끔하다고 생각합니다. null/ Nothing전파는 어떤 방식으로도 "특별"하지 않으므로 왜 더 많은 구문을 배워야합니까?
sara

14

(오래된 질문을 위해 반지에 내 모자를 던짐;))

null의 특정 문제는 정적 입력을 중단한다는 것입니다.

가 있으면 Thing t컴파일러에서 호출 할 수 있음을 보장 할 수 있습니다 t.doSomething(). 글쎄, t런타임 에는 UNLESS 가 null입니다. 이제 모든 베팅이 종료되었습니다. 컴파일러는 괜찮다고 말했지만 t실제로는 그렇지 않다는 것을 알게되었습니다 doSomething(). 따라서 컴파일러가 형식 오류를 잡기 위해 신뢰할 수 있기보다는 런타임까지 기다려야 오류를 잡을 수 있습니다. 파이썬을 사용할 수도 있습니다!

따라서 어떤 의미에서 null은 정적 형식 시스템에 동적 형식을 도입하여 예상되는 결과를 가져옵니다.

0으로 나누기 또는 음의 로그 등의 차이점은 i = 0 일 때 여전히 정수입니다. 컴파일러는 여전히 타입을 보장 할 수 있습니다. 문제는 로직이 허용하지 않는 방식으로 로직이 해당 값을 잘못 적용한다는 것입니다. 그러나 로직이 그렇게하면 버그의 정의에 가깝습니다.

(컴파일러 이러한 문제 중 일부를 포착 할 수 있습니다 . BTW. i = 1 / 0컴파일 타임 과 같은 식을 플래그 지정하는 것과 같습니다 . 그러나 실제로 컴파일러가 함수를 따르고 매개 변수가 모두 함수의 논리와 일치하는지 확인할 수는 없습니다)

실질적인 문제는 많은 추가 작업을 수행하고 런타임에 자신을 보호하기 위해 null 검사를 추가한다는 것입니다. 그러나 잊어 버리면 어떻게해야합니까? 컴파일러는 다음을 할당하지 못하게합니다.

문자열 s = 새로운 정수 (1234);

그렇다면 왜 역 참조를 깨뜨리는 값 (널)을 할당해야 s합니까?

코드에서 "값 없음"과 "유형"참조를 혼합하면 프로그래머에게 추가적인 부담이됩니다. 또한 NullPointerException이 발생하면이를 추적하는 데 시간이 더 많이 걸릴 수 있습니다. 오히려 "이 말을 정적 입력에 의존하기보다는 이다 당신이 언어가 말을시키는 것, 예상 뭔가에 대한 참조" "이 잘 될 수 예상 뭔가에 대한 참조."


3
C에서 형식의 변수는 *int을 식별하거나 int, 또는 NULL. 마찬가지로, C ++, 유형의 변수 *Widget중 하나는 식별 Widget, 유형이 일부터 유도 Widget하거나 NULL. Java 및 C #과 같은 파생 상품의 문제점은 스토리지 위치 Widget를 의미하는 것 *Widget입니다. 해결책은 *Widget보유 할 수없는 척하는 NULL것이 아니라 적절한 Widget저장소 위치 유형 을 갖는 것 입니다.
supercat

14

null포인터 도구입니다

적이 아닙니다. 당신은 단지 그것을 사용해야합니다.

널 포인터 버그를 찾아 수정하는 것과 비교하여 일반적인 잘못된 포인터 버그 를 찾아 수정하는 데 걸리는 시간에 대해 잠시 생각해보십시오 . 에 대한 포인터를 쉽게 확인할 수 null있습니다. 널이 아닌 포인터가 유효한 데이터를 가리키는 지 여부를 확인하는 것은 PITA입니다.

여전히 확신이 없으면 시나리오에 멀티 스레딩을 추가 한 다음 다시 생각하십시오.

이야기의 교훈 : 아이들을 물에 던지지 마십시오. 사고의 도구를 비난하지 마십시오. 오래 전에 숫자 0을 발명 한 사람은 그날부터 "아무것도"라고 지명 할 수 있었기 때문에 매우 영리했습니다. null포인터는 너무 멀리와는 없습니다.


편집 : 있지만 NullObject패턴이 null의 경우 참조보다 더 나은 솔루션이 될 것, 그것은 자신의 문제를 소개합니다 :

  • NullObject메소드를 호출 할 때 (이론에 따라)해야하는 참조 는 아무 것도하지 않습니다. 따라서 잘못 할당되지 않은 참조로 인해 미묘한 오류가 발생할 수 있습니다. 이제 참조는 null이 아니고 (yehaa!) 원치 않는 동작을 수행합니다. NPE를 사용하면 문제가 어디에 있는지 분명하게 알 수 있습니다. A를 NullObject어떻게 든 작동하는 (그러나 잘못된), 우리는 오류의 위험이 말 (너무) 감지되지 소개합니다. 이것은 우연히 잘못된 포인터 문제와 유사하지 않으며 비슷한 결과를 초래합니다. 참조는 유효한 데이터처럼 보이지만 데이터 오류를 유발하고 추적하기 어려운 무언가를 가리 킵니다. 솔직히 말해서,이 경우 깜박임없이 즉시 실패하는 NPE를 선호합니다 .논리적으로 / 데이터 오류로 인해 갑자기 길을 잃었습니다. 오류 비용이 감지되는 단계의 함수 인 IBM의 연구를 기억하십니까?

  • 메소드가 호출 NullObject되지 않거나 속성 getter 또는 함수가 호출되거나 메소드가을 통해 값을 반환 할 때 아무 것도하지 않는다는 개념 out. 리턴 값은 int"우리는 아무것도하지 않는다"는 "return 0"을 의미한다고 결정합니다. 그러나 0이 올바른 "아무것도"돌려받지 못한다는 것을 어떻게 확신 할 수 있습니까? 결국, NullObject아무것도하지 않아야하지만 값을 요구하면 어떻게 든 반응해야합니다. 실패는 옵션이 아닙니다 : 우리 NullObject는 NPE를 방지하기 위해를 사용하며 , 다른 예외 (구현되지 않은, 0으로 나누기 등)와 거래하지 않을 것입니까? 그렇다면 무언가를 반환해야 할 때 어떻게 정확하게 아무것도 반환하지 않습니까?

나는 도울 수 없지만 누군가가 NullObject모든 문제에 패턴 을 적용하려고하면 다른 실수를 수행하여 실수를 복구하려고하는 것처럼 보입니다. 의심 할 여지없이 어떤 경우에는 좋고 유용한 해결책 이지만 모든 경우에 반드시 마법의 총알은 아닙니다.


null존재해야하는지에 대한 논증을 제시 할 수 있습니까 ? "문제가 아니며 실수하지 마십시오"라는 언어 결함에 대해 손을 흔드는 것이 가능합니다.
Doval

어떤 값으로 유효하지 않은 포인터를 설정 하시겠습니까?
JensG

글쎄, 당신은 그것들을 전혀 허용해서는 안되기 때문에 어떤 값으로도 설정하지 않습니다. 대신 다른 유형의 변수를 사용 Maybe T하거나 Nothing, 또는 T값을 포함 할 수 있습니다 . 여기서 중요한 것은 사용하기 전에 Maybe실제로 포함되어 있는지 확인 T하고 사용하지 않을 경우 조치를 취해야한다는 것입니다. 그리고 잘못된 포인터를 허용하지 않았으므로 이제는 아닌 것이 아닌 것을 확인하지 않아도됩니다 Maybe.
Doval

1
최근 예 @JensG 컴파일러는 전에 NULL 체크를 할 수 있도록 않는 모든 에 전화 t.Something()? 아니면 이미 확인을했는지 알고 다시 확인하지 않는 방법이 있습니까? t이 방법으로 전달하기 전에 확인을 수행하면 어떻게됩니까? 옵션 유형을 사용하면 컴파일러는 유형을 확인하여 아직 확인을 수행했는지 여부를 알 수 있습니다 t. 그것이 옵션이라면, 당신은 그것을 확인하지 않은 반면, 그것이 풀린 값이라면 당신은 가지고 있습니다.
Tim Goodman

1
값을 요청할 때 null 객체는 무엇을 반환합니까?
JensG

8

Null 참조는 의미가없는 코드를 허용하기 때문에 실수입니다.

foo = null
foo.bar()

유형 시스템을 활용하는 경우 대안이 있습니다.

Maybe<Foo> foo = null
foo.bar() // error{Maybe<Foo> does not have any bar method}

일반적으로 아이디어는 변수를 상자에 넣는 것이며, 상자를 개봉하는 것만 가능합니다. 에펠 탑에서 제안한 것과 같은 컴파일러 도움말을 포함시키는 것이 좋습니다.

Haskell은 처음부터 그것을 가지고 있습니다 ( Maybe), C ++에서는 활용할 수 boost::optional<T>있지만 정의되지 않은 동작을 얻을 수 있습니다 ...


6
"레버리지"-1!
Mark C

8
그러나 많은 공통 프로그래밍 구성이 무의미한 코드를 허용합니다. 0으로 나누는 것은 무의미하지만, 우리는 여전히 나누기를 허용하며, 프로그래머가 제수가 0이 아닌지 확인 (또는 예외 처리)하는 것을 기억하기를 바랍니다.
Tim Goodman

3
"처음부터"라는 말의 의미는 확실하지 않지만 Maybe핵심 언어에는 포함되어 있지 않습니다. 정의는 표준 서문에 data Maybe t = Nothing | Just t있습니다.
fredoverflow

4
@FredOverflow : 전주곡이 기본적으로로드되기 때문에, 나는 "처음부터"고려할 것입니다. Haskell은 언어의 일반적인 규칙으로 정의 할 수있는 놀랍도록 충분한 유형 시스템을 가지고 있습니다. :)
Matthieu M.

2
@TimGoodman 0으로 나누는 것이 모든 숫자 값 유형에 가장 적합한 예는 아니지만 (IEEE 754는 0으로 나누는 결과를 정의 함), 유형의 T값을 다른 유형의 값으로 나누는 대신 예외가 발생하는 경우 T, 작업을 type 값으로 T나눈 type 값으로 제한합니다 NonZero<T>.
kbolino

8

그리고 대안은 무엇입니까?

선택적 유형 및 패턴 일치 C #을 모르기 때문에 Scala # :-)라는 가상의 언어로 된 코드가 있습니다.

Customer.GetByLastName("Goodman")    // returns Option[Customer]
match
{
    case Some(customer) =>
    Console.WriteLine(customer.FirstName + " " + customer.LastName + " is awesome!");

    case None =>
    Console.WriteLine("There was no customer named Goodman.  How lame!");
}

6

널 (null)의 문제점은 언어를 사용하여 방어 적으로 프로그래밍하도록 강요한다는 것입니다. 방어적인 if-block을 사용하는 것보다 훨씬 많은 노력이 필요합니다.

  1. null이 아닌 것으로 예상되는 객체 는 실제로 null이 아니며
  2. 방어 메커니즘은 모든 잠재적 NPE를 효과적으로 처리합니다.

따라서 실제로 null은 비용이 많이 드는 결과입니다.


1
널 처리에 더 많은 노력이 필요한 예제를 포함하면 도움이 될 수 있습니다. 필자의 지나치게 단순화 된 예에서 노력은 거의 동일하다. 나는 당신과 동의하지 않지만, 특정 (의사) 코드 예제가 일반적인 진술보다 명확한 그림을 그리는 것을 알았습니다.
Tim Goodman

2
아, 나는 나 자신을 명확하게 설명하지 않았다. 널 처리가 더 어려운 것은 아닙니다. 잠재적으로 null 참조에 대한 모든 액세스가 이미 안전하게 보호 되도록 보장하는 것은 매우 어렵습니다 (불가능하지는 않지만) . 즉, null 참조를 허용하는 언어에서 임의의 크기의 코드 조각에 몇 가지 큰 어려움과 노력이없는 것이 아니라 null 포인터 예외가 없음을 보장하는 것은 불가능합니다. 그것이 null 참조를 비싼 것으로 만드는 이유입니다. 널 포인터 예외가 없음을 보장하는 것은 매우 비쌉니다.
luis.espinal

4

프로그래밍 언어가 프로그램을 실행하기 전에 프로그램의 정확성을 입증하려고 시도하는 정도의 문제. 정적으로 유형이 지정된 언어에서는 올바른 유형이 있음을 증명합니다. 널 입력 불가능 참조 (선택적 널 입력 가능 참조)로 이동하면 널이 전달되어서는 안되는 많은 경우를 제거 할 수 있습니다. 문제는 nullable이 아닌 참조를 처리하기위한 추가 노력이 프로그램 정확성 측면에서 이점이 있는지 여부입니다.


4

문제는 그리 많지 않습니다. 많은 현대 언어에서 null이 아닌 참조 유형을 지정할 수 없다는 것입니다.

예를 들어 코드는 다음과 같습니다.

public void MakeCake(Egg egg, Flour flour, Milk milk)
{
    if (egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    egg.Crack();
    MixingBowl.Mix(egg, flour, milk);
    // etc
}

// inside Mixing bowl class
public void Mix(Egg egg, Flour flour, Milk milk)
{
    if (egg == null) { throw ... }
    if (flour == null) { throw ... }
    if (milk == null) { throw ... }

    //... etc
}

클래스 참조가 전달되면 방어 프로그래밍을 통해, 특히 테스트중인 재사용 가능한 단위를 빌드 할 때 방금 null을 확인한 경우에도 모든 매개 변수에서 null을 다시 확인하도록 권장합니다. 동일한 참조를 코드베이스에서 10 번까지 쉽게 확인할 수 있습니다!

당신이 물건을 얻을 때 null을 처리 할 때 정상적인 nullable 유형을 가질 수 있다면 null을 검사하지 않고 모든 작은 도우미 함수 및 클래스에 null을 허용하지 않는 유형으로 전달하면 더 좋지 않을까요? 시각?

옵션 솔루션의 요점은 오류 상태를 켤 수는 없지만 null 인수를 암시 적으로 받아 들일 수없는 함수의 디자인을 허용하는 것입니다. 유형의 "기본"구현이 널 입력 가능 여부 또는 널 입력 불가능 여부는 두 도구를 모두 사용할 수있는 유연성보다 덜 중요합니다.

http://twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing-the-billion-dollar-mistake

이는 C #에서 가장 많이 투표 된 기능 2 위로 표시됩니다.-> https://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c


Option <T>의 또 다른 중요한 점은 모나드 (및 따라서 endofunctor)이기 때문에 None각 단계를 명시 적으로 확인하지 않고 선택적 유형을 포함하는 값 스트림에 대해 복잡한 계산을 작성할 수 있다는 것입니다.
sara

3

널은 악하다. 그러나 null이 없으면 더 큰 악이 될 수 있습니다.

문제는 현실 세계에서 종종 데이터가없는 상황이 있다는 것입니다. null이없는 버전의 예는 여전히 폭발 할 수 있습니다. 논리적 실수를하고 Goodman을 확인하는 것을 잊어 버렸거나 Goodman이 확인했을 때와 그녀를 찾았을 때 결혼했을 것입니다. (Moriarty가 코드의 모든 비트를보고 당신을 트립하려고한다고 생각하면 논리를 평가하는 데 도움이됩니다.)

Goodman의 룩업은 그녀가 없을 때 무엇을합니까? null이 없으면 일종의 기본 고객을 반환해야하며 이제는 기본 고객에게 물건을 판매하고 있습니다.

근본적으로, 코드가 무엇이든 올바르게 작동하는지 코드가 더 중요한지 여부가 결정됩니다. 동작이없는 것보다 부적절한 동작을 선호하는 경우 null을 원하지 않습니다. (올바른 선택이 될 수있는 방법의 예를 보려면 Ariane V의 첫 번째 발사를 고려하십시오. 잡히지 않은 / 0 오류로 인해 로켓이 강하게 회전하고 이로 인해 자체 파괴가 발생했습니다. 부스터가 켜진 순간 실제로 더 이상 어떤 목적으로도 계산하지 않으려 고했습니다. 정기 쓰레기를 반환하더라도 궤도를 돌았을 것입니다.)

100에서 99 번 이상 null을 사용하도록 선택합니다. 그러나 나는 그들의 자아 버전에 주목하기 위해 기뻐할 것입니다.


1
이것은 좋은 대답입니다. 프로그래밍에서 null 구문은 문제가 아니며 null 값의 모든 인스턴스입니다. 기본 객체를 만들면 결국 모든 null이 해당 기본값으로 바뀌고 UI, DB 및 그 사이의 모든 곳이 대신 채워져 더 이상 유용하지 않습니다. 그러나 적어도 프로그램이 충돌하지 않기 때문에 밤에는 잠을 자게 될 것입니다.
Chris McCall

2
null값이없는 유일한 모델링 방법 이라고 가정합니다 .
sara

1

가장 일반적인 경우에 최적화하십시오.

항상 null을 확인해야하는 것은 지루한 일입니다. Customer 객체를 잡고 작업 할 수 있기를 원합니다.

일반적인 경우에는 잘 작동합니다. 조회를 수행하고 객체를 가져 와서 사용하십시오.

에서 예외적 인 경우에 당신이 (무작위로) 이름으로 고객을 찾고, 그 기록 / 객체가 존재하는지 모르고, 당신이 실패했음을 어떤 표시를해야 할 것입니다. 이 상황에서 답은 RecordNotFound 예외를 발생시키는 것입니다 (또는 SQL 공급자가이를 대신하도록 허용).

사용자가 입력 한 데이터 (매개 변수)가 신뢰할 수 있는지 여부를 모르는 경우 'TryGetCustomer (name, out customer)'를 제공 할 수도 있습니다. 무늬. int.Parse 및 int.TryParse와의 상호 참조


함수에 들어오고 nullable 유형이기 때문에 들어오는 데이터를 신뢰할 수 있는지 여부를 절대 알 수 없다고 주장합니다. 입력을 완전히 다르게 만들기 위해 코드를 리팩터링 할 수 있습니다. 따라서 가능한 null이 있으면 항상 확인해야합니다. 따라서 모든 변수가 액세스되기 전에 매번 null을 검사하는 시스템으로 끝납니다. 확인되지 않은 경우는 프로그램의 실패율이됩니다.
Chris McCall

0

예외는 평가되지 않습니다!

그들은 이유가 있습니다. 코드가 제대로 실행되지 않으면 exception 이라는 천재 패턴 이 있으며 문제가 있음을 알려줍니다.

null 객체를 사용하지 않으면 해당 예외의 일부가 숨겨집니다. 나는 null 포인터 예외를 잘 유형이 지정된 예외로 변환하는 OP 예제를 살펴 보지 않습니다. 가독성을 높이기 때문에 실제로 좋은 일이 될 수 있습니다. 어떻게 이제까지 당신이 걸릴 때 옵션 형 @Jonas는 지적 솔루션을, 당신은 예외가 숨어있다.

빈 응용 프로그램을 선택하기 위해 버튼을 클릭 할 때 예외가 발생하는 대신 프로덕션 응용 프로그램보다 예외가 발생하지 않습니다. null 포인터 대신에 예외가 발생하고 (많은 프로덕션 응용 프로그램에서 우리는 그러한 메커니즘을 가지고 있음) 실제로 예외를 해결할 수있는 것보다 해당 예외에 대한 보고서를 얻습니다.

예외를 피함으로써 코드를 방탄으로 만드는 것은 좋지 않은 생각입니다. 예외를 수정하여 코드를 방탄으로 만드는 것이 좋습니다.


1
몇 년 전에 질문을 게시했을 때보 다 스칼라에서 정기적으로 옵션을 사용하기 때문에 옵션 유형에 대해 상당히 많이 알고 있습니다. Option의 요점은 Option이 None아닌 무언가에 컴파일 타임 오류 를 할당 하고 마찬가지로 컴파일 타임 오류 Option인지 확인하지 않고 값이있는 것처럼 as를 사용한다는 것입니다. 컴파일 오류는 런타임 예외보다 확실히 좋습니다.
Tim Goodman

예를 들면 : 당신은 말할 수 없다 s: String = None, 당신은 말해야한다 s: Option[String] = None. 그리고 s옵션 인 경우 말할 수 없지만 s.length패턴 일치를 사용하여 값이 있는지 확인하고 동시에 값을 추출 할 수 있습니다.s match { case Some(str) => str.length; case None => throw RuntimeException("Where's my value?") }
Tim Goodman

불행히도 스칼라에서는 여전히 말할 s: String = null 있지만 Java와의 상호 운용성의 가격입니다. 우리는 일반적으로 스칼라 코드에서 그런 종류의 것을 허용하지 않습니다.
Tim Goodman

2
그러나 나는 예외 (적절하게 사용 된)는 나쁜 것이 아니며, 예외를 삼켜 서 "고치는"것은 일반적으로 끔찍한 생각이라는 일반적인 의견에 동의한다. 그러나 옵션 유형의 경우 예외는 컴파일 타임 오류로 예외를 전환하는 것이 좋습니다.
Tim Goodman

@TimGoodman은 스칼라 만 전술입니까, 아니면 Java 및 ActionScript 3와 같은 다른 언어로 사용할 수 있습니까? 전체 예제를 사용하여 답변을 편집 할 수 있다면 좋을 것입니다.
Ilya Gazman

0

Nulls명시 적으로 검사해야하기 때문에 문제가 있지만 컴파일러는 검사를 잊었다는 경고를 표시 할 수 없습니다. 시간이 많이 걸리는 정적 분석 만 가능합니다. 다행히도 몇 가지 좋은 대안이 있습니다.

범위를 벗어난 변수를 가져옵니다. 너무 자주, null프로그래머가 변수를 너무 일찍 선언하거나 너무 오래 유지할 때 자리 표시 자로 사용됩니다. 가장 좋은 방법은 단순히 변수를 제거하는 것입니다. 값을 입력 할 때까지 선언하지 마십시오. 이것은 생각만큼 어렵지 않으며 코드를 훨씬 깨끗하게 만듭니다.

널 오브젝트 패턴을 사용하십시오. 때로는 누락 된 값이 시스템에 유효한 상태입니다. 널 오브젝트 패턴은 여기서 좋은 솔루션입니다. 지속적인 명시 적 검사가 필요하지 않지만 여전히 널 상태를 나타낼 수 있습니다. 일부 사람들이 주장하는 것처럼 "오류 조건에 대한 문서화"는 아닙니다.이 경우 null 상태는 유효한 의미 론적 상태이기 때문입니다. 즉, null 상태 유효한 의미 상태 가 아닌 경우이 패턴을 사용해서는 안됩니다 . 변수를 범위 밖에서 가져와야합니다.

어쩌면 / 옵션을 사용하십시오. 우선,이를 통해 컴파일러는 누락 된 값을 확인해야한다고 경고하지만 한 유형의 명시 적 확인을 다른 유형으로 대체하는 것 이상을 경고합니다. 를 사용하면 Options코드를 연결하고 값이 존재하는 것처럼 계속 진행할 수 있으므로 절대 마지막 순간까지 실제로 확인할 필요가 없습니다. 스칼라에서 예제 코드는 다음과 같습니다.

val customer = customerDb getByLastName "Goodman"
val awesomeMessage =
  customer map (c => s"${c.firstName} ${c.lastName} is awesome!")
val notFoundMessage = "There was no customer named Goodman.  How lame!"
println(awesomeMessage getOrElse notFoundMessage)

두 번째 줄에서 멋진 메시지를 작성하는 고객은 고객을 찾았는지 명시 적으로 확인 하지 않으며 아름다움은 필요하지 않습니다 . 그것은 많은 선 이상, 또는 우리가 명시 적으로이 경우 발생하는 자신을 염려 다른 모듈에있을 수있는 매우 마지막 줄까지 아닙니다 Option이다 None. 뿐만 아니라, 잊어 버린 경우 유형을 확인하지 않았을 것입니다. 그럼에도 불구하고, 그것은 명백한 if진술 없이 매우 자연스러운 방식으로 이루어집니다 .

null유스 케이스에서 운이 좋으면 단위 테스트 연습에서 운이 좋으면 유형이 잘 검사되지만 런타임의 모든 단계에서 명시 적으로 확인 해야하는 런타임 또는 전체 응용 프로그램이 폭발하는 곳 과는 대조적입니다 . 번거롭지 않습니다.


0

NULL의 주요 문제는 시스템을 신뢰할 수 없게 만든다는 것입니다. 1980 년 토링 호아 (Tony Hoare)는 튜링 상 (Turing Award)에 관한 논문에서 다음과 같이 썼다.

따라서 ADA의 창시자 및 디자이너에게 제공하는 최선의 조언은 무시되었습니다. …. 원자력 발전소, 크루즈 미사일, 조기 경보 시스템, 탄도 미사일 방어 시스템과 같이 신뢰성이 중요한 응용 분야에서이 언어를 현재 상태로 사용하지 마십시오. 프로그래밍 언어 오류로 인해 다음에 잃어버린 로켓은 금성으로의 무해한 여행에서 우주 로켓이 아닐 수도 있습니다. 우리의 도시 중 한 곳에서 폭발하는 핵탄두 일 수 있습니다. 신뢰할 수없는 프로그램을 생성하는 신뢰할 수없는 프로그래밍 언어는 안전하지 않은 자동차, 독성 살충제 또는 원자력 발전소 사고보다 환경과 사회에 훨씬 더 큰 위험을 초래합니다. 위험을 높이 지 말고 줄이기 위해주의하십시오.

ADA 언어는 그 이후로 많이 바뀌었지만 그러한 문제는 여전히 Java, C # 및 기타 많은 인기있는 언어에 존재합니다.

고객과 공급 업체간에 계약을 작성하는 것은 개발자의 의무입니다. 예를 들어, Java에서와 같이 C #에서는 읽기 전용 (두 가지 옵션) 을 작성 Generics하여 Null참조 의 영향을 최소화하는 데 사용할 수 있습니다 NullableClass<T>.

class NullableClass<T>
{
     public HasValue {get;}
     public T Value {get;}
}

그런 다음

NullableClass<Customer> customer = dbRepository.GetCustomer('Mr. Smith');
if(customer.HasValue){
  // one logic with customer.Value
}else{
  // another logic
} 

또는 C # 확장 메소드에 두 가지 옵션 스타일을 사용하십시오.

customer.Do(
      // code with normal behaviour
      ,
      // what to do in case of null
) 

차이가 크다. 메소드의 클라이언트로서 당신은 무엇을 기대해야하는지 알고 있습니다. 팀은 다음과 같은 규칙을 가질 수 있습니다.

클래스가 NullableClass 유형이 아닌 경우 인스턴스는 null이 아니어야합니다 .

이 팀은 계약시 디자인 및 컴파일시 정적 검사 (예 : 전제 조건) 를 사용하여이 아이디어를 강화할 수 있습니다 .

function SaveCustomer([NotNullAttribute]Customer customer){
     // there is no need to check whether customer is null 
     // it is a client problem, not this supplier
}

또는 문자열

function GetCustomer([NotNullAndNotEmptyAttribute]String customerName){
     // there is no need to check whether customerName is null or empty 
     // it is a client problem, not this supplier
}

이러한 접근 방식은 응용 프로그램의 안정성 과 소프트웨어 품질을 크게 향상시킬 수 있습니다 . 계약에 의한 설계 는 1988 년에 유명한 Object-Oriented Software Construction 서적과 Eiffel 언어로 Bertrand Meyer에 의해 채워진 Hoare logic 의 사례 이지만 현대 소프트웨어 제작에서는 잘못 사용되지 않습니다.


0

아니.

언어가 다음과 같은 특별한 가치를 설명하지 못함 null 것은 언어의 문제입니다. Kotlin 또는 Swift 와 같은 언어를 살펴보면 작성자가 매번 발생할 때마다 null 값의 가능성을 명시 적으로 처리해야합니다 . 위험은 없습니다.

해당 언어와 같은 언어에서 언어는 -ish 유형 null의 값이 될 수 있지만 나중에이를 인식하기위한 구성을 제공하지 않으므로 예상치 못한 결과가 발생합니다 (특히 다른 곳에서 전달 된 경우). 따라서 충돌이 발생합니다. 그것은 악입니다. 당신이 그것을 다루지 않고 사용 하게하십시오.nullnull


-1

기본적으로 핵심 아이디어는 런타임 대신 null 포인터 참조 문제가 컴파일 타임에 잡히는 것입니다. 따라서 어떤 객체를 취하는 함수를 작성하고 누군가가 null 참조로 그것을 호출하지 않으려면 type system을 사용하여 컴파일러가 함수를 호출하여 함수에 대한 호출이 절대로 발생하지 않도록 보장 할 수 있도록 요구 사항을 지정해야합니다 발신자가 요구 사항을 충족하지 않으면 컴파일하십시오. 예를 들어, 유형을 꾸미거나 옵션 유형 (일부 언어에서는 nullable 유형이라고도 함)을 사용하는 등 여러 가지 방법으로 수행 할 수 있지만 컴파일러 디자이너에게는 훨씬 많은 작업이 필요합니다.

나는 1960 년대와 70 년대에 기계가 자원이 제한되어 있고, 컴파일러를 비교적 단순하게 유지해야했고, 이것이 어떻게 나빠질 지 아무도 몰랐기 때문에이 아이디어를 구현하기 위해 컴파일러 디자이너가이 모든 것을 도입하지 않은 이유를 이해할 수 있다고 생각합니다. 몇 년 동안 줄을.


-1

나는 하나의 간단한 반대 의견이 있습니다 null.

모호성을 도입하여 코드의 의미를 완전히 깰 수 있습니다 .

종종 결과가 특정 유형이 될 것으로 기대 합니다. 이것은 의미 적으로 건전합니다. 예를 들어, 특정 사용자에게 데이터베이스를 요청한 경우 id, 해당 결과는 특정 유형 (= user) 이 될 것으로 예상합니다 . 그러나 해당 ID의 사용자가 없으면 어떻게됩니까? 하나의 (나쁜) 해결책은 null값을 추가하는 것 입니다. 따라서 결과는 모호합니다 . a user또는 is null입니다. 그러나 null예상되는 유형이 아닙니다. 그리고 이것은 코드 냄새 가 시작 되는 곳 입니다.

피하기 null위해 코드를 의미 적으로 명확하게 만듭니다.

방법은 주위에 항상있다 null: 컬렉션에 리팩토링, Null-objects, optionals


-2

값을 계산하기 위해 코드를 실행하기 전에 참조 또는 포인터 유형의 저장 위치에 의미 적으로 액세스 할 수있는 경우 어떤 일이 발생해야하는지에 대한 완벽한 선택은 없습니다. 이러한 위치를 기본적으로 널 포인터 참조로 설정하면 자유롭게 읽고 복사 할 수 있지만 역 참조 또는 색인 작성시 오류가 발생하는 것이 하나의 선택입니다. 다른 선택 사항은 다음과 같습니다.

  1. 위치는 기본적으로 널 포인터로 설정되지만 충돌없이 코드에서 해당 위치를 보거나 널로 판단 할 수 없습니다. 포인터를 널로 설정하는 명시 적 수단을 제공 할 수 있습니다.
  2. 위치는 기본적으로 널 포인터로 설정하고, 포인터를 읽으려고하면 충돌이 발생하지만 포인터가 널을 보유하는지 여부를 테스트하는 비 충돌적인 방법을 제공하십시오. 포인터를 널로 설정하는 명시 적 수단도 제공하십시오.
  3. 표시된 유형의 특정 컴파일러 제공 기본 인스턴스에 대한 포인터를 기본 위치로 지정하십시오.
  4. 지정된 유형의 특정 프로그램 제공 기본 인스턴스에 대한 포인터를 기본 위치로 지정하십시오.
  5. 역 참조 작업이 아닌 널 포인터 액세스 권한이 있으면 프로그램 제공 루틴을 호출하여 인스턴스를 제공하십시오.
  6. 초기화 루틴이 모든 멤버에서 실행될 때까지 (배열 생성자와 같은 것이 기본 인스턴스와 함께 제공되어야 할 때까지) 액세스 할 수없는 컴파일러 임시를 제외하고 스토리지 위치 콜렉션이 존재하지 않도록 언어 의미를 설계하십시오. 인스턴스 또는 함수 쌍을 반환하는 함수-인스턴스를 반환하는 함수와 배열을 구성하는 동안 예외가 발생하면 이전에 생성 된 인스턴스에서 호출되는 함수)

마지막 선택은 특히 언어에 널 입력 가능 유형과 널 입력 불가능 유형이 모두 포함 된 경우 (어떤 유형에 대해서도 특수 배열 생성자를 호출 할 수 있지만 널 입력 불가능 유형의 배열을 작성할 때 호출해야하는 경우), 그러나 null 포인터가 발명 된 시점에는 아마도 불가능했을 것입니다. 다른 선택 중에서, 널 포인터를 복사하지만 역 참조 또는 색인화를 허용하는 것보다 더 매력적인 것은 없습니다. 접근법 # 4는 옵션으로 사용하는 것이 편리 할 수 ​​있으며 구현하기에는 상당히 저렴해야하지만 반드시 유일한 옵션은 아닙니다. 포인터가 기본적으로 특정 특정 객체를 가리 키도록 요구하는 것은 포인터를 읽거나 복사 할 수 있지만 역 참조 또는 색인을 생성 할 수없는 널값에 대한 포인터를 갖는 것보다 훨씬 나쁩니다.


-2

예, NULL은 객체 지향 세계에서 끔찍한 디자인 입니다. 간단히 말해서 NULL 사용법은 다음과 같습니다.

  • 임시 오류 처리 (예외 대신)
  • 모호한 의미
  • 빠른 실패 대신 느리게
  • 컴퓨터 사고 대 객체 사고
  • 변경 가능하고 불완전한 객체

자세한 설명은이 블로그 게시물을 확인하십시오. http://www.yegor256.com/2014/05/13/why-null-is-bad.html

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.