Angenommen, ich habe eine Klasse Member
mit einer lastChangePasswordTime:
class Member{
.
.
.
constructor(){
this.lastChangePasswordTime=null,
}
}
Wessen lastChangePasswordTime kann in Abwesenheit sinnvoll sein, da einige Mitglieder ihre Passwörter möglicherweise nie ändern.
Aber laut Wenn Nullen böse sind, was sollte verwendet werden, wenn ein Wert sinnvoll fehlen kann? und https://softwareengineering.stackexchange.com/a/12836/248528 , ich sollte nicht null verwenden, um einen sinnvollen fehlenden Wert darzustellen. Also versuche ich eine Boolesche Flagge hinzuzufügen:
class Member{
.
.
.
constructor(){
this.isPasswordChanged=false,
this.lastChangePasswordTime=null,
}
}
Aber ich denke, es ist ziemlich veraltet, weil:
Wenn isPasswordChanged false ist, muss lastChangePasswordTime null sein, und die Überprüfung von lastChangePasswordTime == null ist fast identisch mit der Überprüfung von isPasswordChanged false. Ich bevorzuge daher, lastChangePasswordTime == null direkt zu überprüfen
Wenn ich hier die Logik ändere, kann es sein, dass ich vergesse, beide Felder zu aktualisieren .
Hinweis: Wenn ein Benutzer Passwörter ändert, würde ich die Zeit folgendermaßen aufzeichnen:
this.lastChangePasswordTime=Date.now();
Ist das zusätzliche Boolesche Feld hier besser als eine Nullreferenz?
std::optional
oder verwendenOption
. In anderen Sprachen müssen Sie möglicherweise selbst einen geeigneten Mechanismus erstellen, oder Sie greifen auf einennull
ähnlichen oder einen ähnlichen Mechanismus zurück, weil er idiomatischer ist.lastChangePasswordTime
kann dort ein nicht initialisierter Zeiger sein und ein Vergleich mit irgendetwas wäre undefiniertes Verhalten. Kein wirklich zwingender Grund, den Zeiger nicht aufNULL
/ zu initialisierennullptr
, insbesondere nicht in modernem C ++ (wo Sie überhaupt keinen Zeiger verwenden würden), aber wer weiß? Ein anderes Beispiel wären Sprachen ohne Zeiger oder mit schlechter Unterstützung für Zeiger. (FORTRAN 77 kommt in den Sinn ...)Antworten:
Ich verstehe nicht, warum, wenn Sie einen bedeutungslosen Wert haben,
null
sollte nicht verwendet werden, wenn Sie absichtlich und vorsichtig sind.Wenn Sie den nullfähigen Wert umschließen möchten, um zu verhindern, dass versehentlich darauf verwiesen wird, würde ich vorschlagen, den
isPasswordChanged
Wert als Funktion oder Eigenschaft zu erstellen, die das Ergebnis einer Nullprüfung zurückgibt. Beispiel:Meiner Meinung nach mache ich das so:
isPasswordChanged
Ihnen genannten Wert beizubehalten .Die Art und Weise, wie Sie die Daten speichern (vermutlich in einer Datenbank), ist dafür verantwortlich, dass die Nullen erhalten bleiben.
quelle
isPasswordChanged
genauso wie Sie vergessen können, zu überprüfen, ob es null ist. Ich sehe hier nichts gewonnen.nulls
sind nicht böse Verwenden Sie sie ohne nachzudenken ist. Dies ist ein Fall, in demnull
genau die richtige Antwort ist - es gibt kein Datum.Beachten Sie, dass Ihre Lösung mehr Probleme verursacht. Was bedeutet es, wenn das Datum auf etwas gesetzt wird, aber das
isPasswordChanged
ist falsch? Sie haben gerade einen Fall von widersprüchlichen Informationen erstellt, den Sie speziell erfassen und behandeln müssen, während einnull
Wert eine klar definierte, eindeutige Bedeutung hat und nicht mit anderen Informationen in Konflikt stehen kann.Also nein, Ihre Lösung ist nicht besser. Unter Berücksichtigung einen
null
Wert ist der richtige Ansatz hier. Menschen, die behaupten, dasnull
sei immer böse, egal in welchem Kontext, verstehen nicht, warum es dasnull
gibt.quelle
null
existiert es, weil Tony Hoare 1965 den Milliarden-Dollar-Fehler begangen hat. Leute, die behaupten, dasnull
sei "böse", vereinfachen das Thema natürlich zu stark, aber es ist eine gute Sache, dass moderne Sprachen oder Programmierstile esnull
ersetzen es mit dedizierten Optionstypen.DateTime
Feld ein Zeiger. Das ganze Konzept vonnull
macht nur Sinn für Zeiger!Abhängig von Ihrer Programmiersprache gibt es möglicherweise gute Alternativen, z. B. einen
optional
Datentyp. In C ++ (17) wäre dies std :: optional . Es kann entweder fehlen oder einen beliebigen Wert des zugrunde liegenden Datentyps haben.quelle
Optional
in Java; Die Bedeutung einer NullOptional
liegt bei Ihnen ...Optional<Date> lastPasswordChangeTime = null;
, aber ich würde nicht einfach deswegen aufgeben. Stattdessen würde ich eine sehr feste Teamregel einführen, dass niemals optionale Werte zugewiesen werden dürfennull
. Optional kauft man sich zu viele nette Features, um darauf einfach zu verzichten. Sie können ganz einfach Standardwerte zuweisen (orElse
oder mit Lazy EvaluationorElseGet
:), Fehler werfen (orElseThrow
), Werte nullsicher transformieren (map
,flatmap
) usw.isPresent
ist meiner Erfahrung nach fast immer ein Codegeruch und ein ziemlich zuverlässiges Zeichen dafür, dass die Entwickler, die diese Optionen verwenden, "den Punkt verfehlen". In der Tat gibt es im Grunde keinen Vorteil gegenüberref == null
, aber es ist auch nicht etwas, das Sie oft verwenden sollten. Selbst wenn das Team instabil ist, kann ein statisches Analysetool das Gesetz festlegen, wie z. B. ein Linter oder FindBugs , die die meisten Fälle abfangen können.null
weil die Sprache Java zu 100% kompatibel ist, aber niemand nutzt es, undOption[T]
ist ganz über den Platz, mit hervorragender Funktions-Programmierunterstützung wiemap
,flatMap
, Pattern - Matching und so weiter, die geht weit, weit jenseits von== null
Schecks. Sie haben Recht, dass sich ein Optionstyp theoretisch wie ein glorifizierter Zeiger anhört, aber die Realität beweist, dass dieses Argument falsch ist.Richtig mit null
Es gibt verschiedene Verwendungsmöglichkeiten
null
. Die gebräuchlichste und semantisch korrekte Methode besteht darin, sie zu verwenden, wenn Sie einen einzelnen Wert haben oder nicht . In diesem Fall ist ein Wert entweder gleichnull
oder etwas Sinnvolles wie ein Datensatz aus einer Datenbank oder so.In diesen Situationen verwenden Sie es dann meistens so (in Pseudocode):
Problem
Und es hat ein sehr großes Problem. Das Problem ist, dass
doSomethingUseful
der Wert zum Zeitpunkt des Aufrufs möglicherweise noch nicht überprüft wurdenull
! Wenn dies nicht der Fall ist, stürzt das Programm wahrscheinlich ab. Und der Benutzer kann möglicherweise nicht einmal gute Fehlermeldungen sehen, die mit so etwas wie "schrecklicher Fehler: Wert gesucht, aber null!" (nach dem Update: obwohl es möglicherweise noch weniger informative Fehler gibtSegmentation fault. Core dumped.
, oder schlimmer noch, keine Fehler und falsche Manipulationen bei Null in einigen Fällen)Das Vergessen, Schecks zu schreiben
null
und mitnull
Situationen umzugehen , ist ein äußerst häufiger Fehler . Aus diesem Grundnull
sagte Tony Hoare, der im Jahr 2009 auf einer Softwarekonferenz namens QCon London erfunden hatte , dass er 1965 den Milliarden-Dollar-Fehler begangen habe: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar- Fehler-Tony-HoareDas Problem vermeiden
Einige Technologien und Sprachen machen es
null
unmöglich, die Überprüfung auf unterschiedliche Weise zu vergessen, wodurch die Anzahl der Fehler verringert wird.Zum Beispiel hat Haskell die
Maybe
Monade anstelle von Nullen. Angenommen, diesDatabaseRecord
ist ein benutzerdefinierter Typ. In Haskell kann ein Wert vom TypMaybe DatabaseRecord
gleichJust <somevalue>
oder gleich seinNothing
. Sie können es dann auf verschiedene Arten verwenden, aber unabhängig davon, wie Sie es verwenden, können Sie keine Operation anwenden,Nothing
ohne es zu wissen.Diese Funktion heißt zum Beispiel
zeroAsDefault
returnx
fürJust x
und0
fürNothing
:Christian Hackl sagt, C ++ 17 und Scala haben ihre eigenen Wege. Vielleicht möchten Sie also herausfinden, ob Ihre Sprache so etwas enthält, und es verwenden.
Nullen sind immer noch weit verbreitet
Wenn Sie nichts Besseres haben, ist die Verwendung
null
in Ordnung. Pass einfach weiter auf. Typdeklarationen in Funktionen helfen Ihnen sowieso etwas.Auch das mag nicht sehr progressiv klingen, aber Sie sollten prüfen, ob Ihre Kollegen
null
etwas anderes verwenden möchten . Sie sind möglicherweise konservativ und möchten aus bestimmten Gründen möglicherweise keine neuen Datenstrukturen verwenden. Zum Beispiel die Unterstützung älterer Sprachversionen. Solche Dinge sollten in den Codierungsstandards des Projekts deklariert und ordnungsgemäß mit dem Team besprochen werden.Auf Ihren Vorschlag
Sie schlagen vor, ein separates boolesches Feld zu verwenden. Aber Sie müssen es trotzdem überprüfen und können immer noch vergessen, es zu überprüfen. Hier gibt es also nichts zu gewinnen. Wenn Sie noch etwas anderes vergessen können, z. B. beide Werte jedes Mal aktualisieren, ist es noch schlimmer. Wenn das Problem des Vergessens, nach etwas zu suchen,
null
nicht gelöst ist, hat es keinen Sinn. Vermeidennull
ist schwierig und Sie sollten es nicht so machen, dass es noch schlimmer wird.Wie man nicht null benutzt
Schließlich gibt es übliche Möglichkeiten, um
null
falsch zu verwenden . Eine Möglichkeit besteht darin, es anstelle von leeren Datenstrukturen wie Arrays und Strings zu verwenden. Ein leeres Array ist ein richtiges Array wie jedes andere! Es ist fast immer wichtig und nützlich, dass Datenstrukturen, die mehreren Werten entsprechen können, leer sein können, dh eine Länge von 0 haben.Aus algebraischer Sicht ist eine leere Zeichenfolge für Zeichenfolgen ähnlich wie 0 für Zahlen, dh Identität:
Mit einer leeren Zeichenfolge können Zeichenfolgen im Allgemeinen zu einem Monoid werden: https://en.wikipedia.org/wiki/Monoid Wenn Sie sie nicht erhalten, ist sie für Sie nicht so wichtig.
Lassen Sie uns nun anhand dieses Beispiels sehen, warum es für die Programmierung wichtig ist:
Wenn wir hier ein leeres Array übergeben, funktioniert der Code einwandfrei. Es wird einfach nichts tun. Übergeben wir
null
hier jedoch ein , kommt es wahrscheinlich zu einem Absturz mit der Fehlermeldung "Kann Null nicht durchlaufen, sorry". Wir könnten es einpacken,if
aber das ist weniger sauber, und Sie könnten vergessen, es zu überprüfenWie gehe ich mit null um?
Was
doSomethingAboutIt()
zu tun ist und insbesondere, ob eine Ausnahme ausgelöst werden soll, ist ein weiteres kompliziertes Problem. Kurz gesagt, es hängt davon ab, obnull
ein akzeptabler Eingabewert für eine bestimmte Aufgabe vorhanden war und was als Antwort erwartet wird. Ausnahmen sind für Ereignisse, die nicht erwartet wurden. Ich werde nicht weiter auf dieses Thema eingehen. Diese Antwort ist schon sehr lang.quelle
horrible error: wanted value but got null!
ist viel besser als die typischerenSegmentation fault. Core dumped.
...Error: the product you want to buy is out of stock
.null
wonull
nicht erlaubt ist, ist ein Programmierfehler, dh ein Fehler im Code. Ein Produkt, das nicht auf Lager ist, ist Teil der normalen Geschäftslogik und kein Fehler. Sie können und sollten nicht versuchen, die Erkennung eines Fehlers in eine normale Nachricht auf der Benutzeroberfläche zu übersetzen. Sofort abstürzen und nicht mehr Code ausführen ist die bevorzugte Vorgehensweise, insbesondere wenn es sich um eine wichtige Anwendung handelt (z. B. eine, die echte Finanztransaktionen ausführt).null
selbst nicht vollständig vom Hintergrund entfernen .Zusätzlich zu all den sehr guten Antworten, die zuvor gegeben wurden, möchte ich hinzufügen, dass Sie jedes Mal, wenn Sie versucht sind, ein Feld auf Null zu setzen, sorgfältig überlegen, ob es sich möglicherweise um einen Listentyp handelt. Ein nullfähiger Typ ist äquivalent eine Liste von 0 oder 1 Elementen, und oft kann dies auf eine Liste von N Elementen verallgemeinert werden. In diesem Fall möchten Sie möglicherweise
lastChangePasswordTime
eine Liste vonpasswordChangeTimes
.quelle
Stellen Sie sich folgende Frage: Für welches Verhalten ist das Feld lastChangePasswordTime erforderlich?
Wenn Sie dieses Feld für eine Methode IsPasswordExpired () benötigen, um zu bestimmen, ob ein Mitglied aufgefordert werden soll, sein Kennwort von Zeit zu Zeit zu ändern, würde ich das Feld auf den Zeitpunkt festlegen, zu dem das Mitglied ursprünglich erstellt wurde. Die Implementierung von IsPasswordExpired () ist für neue und vorhandene Mitglieder identisch.
Wenn Sie eine separate Anforderung haben , dass neu erstellte Mitglieder haben ihr Passwort zu aktualisieren, würde ich hinzufügen , ein boolean Feld namens passwordShouldBeChanged getrennt und setzen Sie ihn auf true bei der Erstellung. Ich würde dann die Funktionalität der IsPasswordExpired () -Methode ändern, um eine Prüfung für dieses Feld einzuschließen (und die Methode in ShouldChangePassword umbenennen).
Machen Sie Ihre Absichten im Code deutlich.
quelle
Erstens ist Nullen, die böse sind, ein Dogma, und wie bei Dogmen üblich, funktioniert es am besten als Richtlinie und nicht als Pass / No-Pass-Test.
Zweitens können Sie Ihre Situation so neu definieren, dass es sinnvoll ist, dass der Wert niemals null sein kann. InititialPasswordChanged ist ein Boolescher Wert, der anfänglich auf false festgelegt wurde. PasswordSetTime ist das Datum und die Uhrzeit, zu der das aktuelle Kennwort festgelegt wurde.
Beachten Sie, dass dies zwar mit geringen Kosten verbunden ist, Sie jedoch IMMER berechnen können, wie lange es her ist, seit ein Passwort zum letzten Mal festgelegt wurde.
quelle
Beide sind "sicher / gesund / korrekt", wenn der Anrufer vor der Verwendung prüft. Das Problem ist, was passiert, wenn der Anrufer nicht überprüft. Was ist besser, eine Variante von Null-Fehler oder die Verwendung eines ungültigen Werts?
Es gibt keine einzige richtige Antwort. Es kommt darauf an, worüber Sie sich Sorgen machen.
Wenn Abstürze wirklich schlimm sind, die Antwort jedoch nicht kritisch ist oder einen akzeptierten Standardwert hat, ist es möglicherweise besser, einen Booleschen Wert als Flag zu verwenden. Wenn die falsche Antwort ein schlimmeres Problem ist als ein Absturz, ist die Verwendung von Null besser.
In den meisten „typischen“ Fällen ist ein schneller Ausfall und das Erzwingen der Überprüfung durch die Anrufer der schnellste Weg, um einen vernünftigen Code zu erhalten. Daher sollte meines Erachtens die Standardeinstellung Null sein. Ich würde jedoch nicht zu viel Vertrauen in die "X ist die Wurzel aller bösen" Evangelisten setzen. Normalerweise haben sie nicht alle Anwendungsfälle vorweggenommen.
quelle