Überprüfen Sie zwei Argumente in Java, entweder beide nicht null oder beide elegant null

160

Ich habe Spring Boot verwendet, um ein Shell-Projekt zu entwickeln, mit dem E-Mails gesendet werden, z

sendmail -from foo@bar.com -password  foobar -subject "hello world"  -to aaa@bbb.com

Wenn die Argumente fromund passwordfehlen, verwende ich einen Standardabsender und ein Standardkennwort, z . B. [email protected]und 123456.

Wenn der Benutzer das fromArgument übergibt , muss er auch das passwordArgument übergeben und umgekehrt. Das heißt, entweder sind beide nicht null oder beide sind null.

Wie überprüfe ich das elegant?

Jetzt ist mein Weg

if ((from != null && password == null) || (from == null && password != null)) {
    throw new RuntimeException("from and password either both exist or both not exist");
}
zhuguowei
quelle
14
Beachten Sie außerdem, dass die sorgfältige Verwendung von Leerzeichen das Lesen von Code erheblich erleichtert. Das Hinzufügen von Leerzeichen zwischen den Operatoren in Ihrem aktuellen Code würde die Lesbarkeit der IMO erheblich verbessern.
Jon Skeet
8
Bitte definieren Sie "Eleganz".
Renaud
Sie benötigen einen separaten Satz von Argumenten für die Anmeldeinformationen für die SMTP-Authentifizierung und für die E-Mail-Adresse des Absenders des Umschlags. Die FromE-Mail-Adresse ist nicht immer der SMTP-Authentifizierungsname.
Kaz
3
Es kann wirklich nicht viel optimierter werden, es ist eine Zeile lesbaren Codes und nichts kann durch Überoptimierung erreicht werden.
Diynevala
3
Randnotiz: Wenn dies ein Shell-Skript ist, werden die Passwörter dann nicht im Shell-Verlauf gespeichert?
Berühre meinen Körper

Antworten:

331

Es gibt eine Möglichkeit, den Operator ^( XOR ) zu verwenden:

if (from == null ^ password == null) {
    // Use RuntimeException if you need to
    throw new IllegalArgumentException("message");
}

Die ifBedingung ist wahr, wenn nur eine Variable null ist.

Aber ich denke, normalerweise ist es besser, zwei ifBedingungen mit unterschiedlichen Ausnahmemeldungen zu verwenden. Sie können nicht mit einer einzigen Bedingung definieren, was schief gelaufen ist.

if ((from == null) && (password != null)) {
    throw new IllegalArgumentException("If from is null, password must be null");
}
if ((from != null) && (password == null)) {
    throw new IllegalArgumentException("If from is not null, password must not be null");
}

Es ist besser lesbar und viel einfacher zu verstehen, und es erfordert nur ein wenig zusätzliche Eingabe.

cooler Typ
quelle
152
Gibt es einen Grund, warum xor auf zwei Bools gegenüber zwei Bools vorzuziehen ist !=?
Eric Lippert
1
Wow, ich habe nicht bemerkt, dass XOR auf Boolean das gleiche ist wie !=. Verblüfft. Und das ist eine sehr hohe Anzahl von Upvotes im Kommentar. Und um diesem Kommentar Qualität zu verleihen, denke ich auch, dass es besser ist, unterschiedliche Fehlermeldungen für unterschiedliche Fehlerfälle zu geben, da der Benutzer besser weiß, wie er den Fehler korrigieren kann.
halb
1
Für 2 Elemente ist das in Ordnung. Wie geht das mit> 2 Elementen?
Anushree Acharjee
Ich möchte eine Fehlermeldung anzeigen, wenn eines der Elemente> 0 ist. Standardmäßig sind alle auf 0 gesetzt. Wenn alle> 0 sind, ist dies ein gültiges Szenario. Wie macht man das?
Anushree Acharjee
Dies würde eine raffinierte Interviewfrage stellen. Ich frage mich, wie viel Prozent der Programmierer das wissen. Aber ich stimme nicht zu, dass es nicht klar genug ist und eine Aufteilung in zwei ifKlauseln rechtfertigt - die Nachricht in der Ausnahme dokumentiert es gut (ich habe die Frage bearbeitet, aber sie wird erst angezeigt, wenn sie angenommen wurde)
Adam
286

Nun, es hört sich so an, als würden Sie versuchen zu überprüfen, ob die "Null" -Zustand der beiden gleich ist oder nicht. Du könntest benutzen:

if ((from == null) != (password == null))
{
    ...
}

Oder machen Sie es mit Hilfsvariablen expliziter:

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}
Jon Skeet
quelle
18
Du bist einer meiner SO-Helden @Kaz, aber nichts sagt "entweder dies oder das, aber nicht beide gleich" ^. :-)
David Bullock
6
@ DavidBullock: Wenn es um Boolesche Werte geht, sagt nichts "entweder dies oder das, aber nicht beide gleich" wie ... "nicht beide gleich"; XOR ist nur ein anderer Name für die Funktion "ungleich" über Boolesche Werte.
Kaz
5
@Kaz Es ^heißt nur "Hey, meine Operanden sind Boolesche Werte" auf eine Weise, die !=dies nicht tut. (Obwohl dieser Effekt leider durch die Notwendigkeit verringert wird, nach "Meine Operanden sind möglicherweise numerisch und ich bin zu diesem Zeitpunkt möglicherweise kein Vergleichsoperator" zu suchen, ist dies ein Nachteil.) Ihr Heldenstatus unvermindert, obwohl Sie nicht mit mir übereinstimmen :-)
David Bullock
3
Nachdem Sie die Anforderungen des Problems und dann Ihre Lösung gelesen haben, ist der Code sinnvoll und lesbar. Aber als Entwickler von 4 Jahren (noch in der Schule) würde es Kopfschmerzen bereiten, diesen Code zu lesen und dann herauszufinden, welche "Geschäftsanforderungen" vorhanden waren. Aus diesem Code verstehe ich nicht sofort " fromund passwordbeide müssen null sein oder beide dürfen nicht null sein". Vielleicht bin das nur ich und meine Unerfahrenheit, aber ich bevorzuge die besser lesbare Lösung wie in der Antwort von @ stig-hemmer, auch wenn sie weitere 3 Codezeilen kostet. Ich glaube , ich einfach nicht sofort bekommen bool != bool - es ist nicht intuitiv.
Chris Cirefice
2
@DavidBullock Der ^Operator ist ein bitweiser Operator. es bedeutet eigentlich nicht, dass seine Operanden boolesch sind. Der boolesche xor-Operator ist xor.
Brilliand
222

Ich persönlich bevorzuge lesbar gegenüber elegant.

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}
Stig Hemmer
quelle
52
+1 für die besseren Nachrichten. Dies ist wichtig, niemand mag handwaving „etwas schief gelaufen ist “ -Fehler Nachrichten, so dass niemand sollte dazu führen , solche Nachrichten. In der Praxis sollte man jedoch eine spezifischere Ausnahme bevorzugen (insbesondere eine IllegalArgumentExceptionanstelle einer nackten RuntimeException)
Marco13
6
@matt es sieht so aus, als ob Ihre Kritik nicht am Code, sondern am Text der Ausnahmen liegt. Ich denke jedoch, dass der Wert dieser Antwort in der Struktur der if-Anweisungen liegt, nicht im Inhalt der Fehlermeldungen. Dies ist die beste Antwort, da dadurch die Funktionalität verbessert wird. OP könnte die Ausnahmetexte leicht durch beliebige Zeichenfolgen ersetzen.
Dan Henderson
4
@matt Der Vorteil ist, dass es möglich wird, zu unterscheiden, welcher der beiden ungültigen Zustände aufgetreten ist, und die Fehlermeldung anzupassen. Anstatt also zu sagen, dass Sie eines dieser beiden Dinge falsch gemacht haben, können Sie sagen, dass Sie dies getan haben oder dass Sie das getan haben (und dann, falls gewünscht, Lösungsschritte bereitstellen). Die Auflösung mag in beiden Fällen gleich sein, aber es ist nie eine gute Idee zu sagen, "Sie haben eines dieser Dinge falsch gemacht". Quelle: In einer Umgebung, in der ich diese Funktionalität nicht bereitstellen konnte, habe ich viele Fragen von Benutzern beantwortet, die die erste Bedingung in meinem Fehlertext erfüllt haben.
Dan Henderson
4
@DanHenderson> Es ist nie eine gute Idee zu sagen "Sie haben eines dieser Dinge falsch gemacht." Ich bin nicht einverstanden. Passwort / Benutzername Es ist sicherer zu sagen, dass Benutzername und Passwort nicht übereinstimmen.
Matt
2
@DanHenderson Aus Sicherheitsgründen ist es möglicherweise besser, nicht zwischen dem Fall zu unterscheiden, in dem sich der Benutzername im Verzeichnis befindet, oder nicht, da ein Angreifer sonst gültige Benutzernamen herausfinden könnte. Das Mischen von null / nicht null ist jedoch (in diesem Fall) immer ein Verwendungsfehler, und das Anzeigen einer detaillierteren Fehlermeldung führt nicht zu mehr Informationen als der ursprünglich angegebene Benutzer.
Siegi
16

Fügen Sie diese Funktionalität in eine 2-Argument-Methode mit der Signatur ein:

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

Dies spart Platz in der eigentlichen Methode, an der Sie interessiert sind, und macht sie lesbarer. An leicht ausführlichen Methodennamen ist nichts auszusetzen, und an sehr kurzen Methoden ist nichts auszusetzen.

Traubenfuchs
quelle
14
Kein Platz gespart ((from == null) != (password == null)), das ist auch sehr einfach zu verstehen. Mit nicht nützlichen Methoden stimmt etwas nicht.
edc65
3
Es gibt eine Zeile für die if-Anweisung, die zweite Zeile für die throw-Anweisung und die dritte Zeile für die schließende Klammer: Alle werden durch eine Zeile ersetzt. Eine weitere Zeile wird gespeichert, wenn Sie den schließenden Klammern eine neue Zeile geben!
Traubenfuchs
10
Wenn Sie den Code lesen, haben Sie einen Methodennamen, den Sie verstehen müssen, um mit Bedingungen zu jonglieren.
Traubenfuchs
1
definitiv +1, ziehen Sie es immer vor, heruntergekommene Implementierungsdetails und Operatoren mit beschreibenden Methoden und Variablennamen zu abstrahieren, die INTENTION klar machen. Logik enthält Fehler. Kommentare sind noch schlimmer. Ein Methodenname zeigt die Absicht und isoliert die Logik, damit Fehler leichter gefunden und behoben werden können. Diese Lösung erfordert nicht, dass der Leser irgendeine Syntax oder Logik kennt oder darüber nachdenkt. Sie ermöglicht es uns, uns stattdessen auf die GESCHÄFTSANFORDERUNGEN zu konzentrieren (was wirklich wichtig ist)
Sara
1
Sie würden auf unnötige Probleme stoßen, wenn Sie hier eine beschreibende Ausnahmemeldung haben möchten.
Honza Brabec
11

Unter der Objects.isNull(Object)Annahme eines statischen Imports wäre eine Java 8-Lösung zu verwenden :

if (isNull(from) != isNull(password)) {
    throw ...;
}

Für Java <8 (oder wenn Sie es nicht mögen Objects.isNull()) können Sie einfach Ihre eigene isNull()Methode schreiben .

Didier L.
quelle
6
Mag es nicht. from == null != password == nullHält alles auf dem gleichen Frame des Stapels, Objects.isNull(Object)drückt aber unnötig zwei Frames und knallt sie. Objects.isNull (Object) ist vorhanden, weil 'Diese Methode existiert, um als Prädikat verwendet zu werden' (dh in Streams).
David Bullock
5
Eine einfache Methode wie diese wird normalerweise schnell von der JIT beschrieben, sodass die Auswirkungen auf die Leistung höchstwahrscheinlich vernachlässigbar sind. Wir könnten in der Tat über die Verwendung von diskutieren Objects.isNull()- Sie können Ihre eigenen schreiben, wenn Sie es vorziehen -, aber was die Lesbarkeit betrifft, denke ich, dass die Verwendung isNull()besser ist. Darüber hinaus benötigen Sie zusätzliche Klammern, damit der einfache Ausdruck kompiliert werden kann : from == null != (password == null).
Didier L.
2
Ich stimme dem JIT'ing zu (und der Reihenfolge der Operationen ... ich war faul). Trotzdem (val == null)ist es so sehr die Möglichkeit , mit Null zu vergleichen, dass es mir schwer fällt, über zwei Aufrufe der großen Fettmethode hinwegzukommen, die mich ins Gesicht starren, selbst wenn die Methode ziemlich funktional, inlinierbar und gut ist. genannt. Das bin aber nur ich. Ich habe vor kurzem entschieden, dass ich ein bisschen seltsam bin.
David Bullock
4
Ehrlich gesagt, wen interessiert ein einzelner Stapelrahmen? Der Stapel ist immer nur dann ein Problem, wenn Sie sich mit (möglicherweise unendlicher) Rekursion befassen oder wenn Sie eine 1000-stufige Anwendung mit einem Objektdiagramm von der Größe der Sahara-Wüste haben.
Sara
9

Hier ist eine allgemeine Lösung für eine beliebige Anzahl von Nullprüfungen

public static int nulls(Object... objs)
{
    int n = 0;
    for(Object obj : objs) if(obj == null) n++;
    return n;
}

public static void main (String[] args) throws java.lang.Exception
{
    String a = null;
    String b = "";
    String c = "Test";

    System.out.println (" "+nulls(a,b,c));
}

Verwendet

// equivalent to (a==null & !(b==null|c==null) | .. | c==null & !(a==null|b==null))
if (nulls(a,b,c) == 1) { .. }

// equivalent to (a==null | b==null | c==null)
if (nulls(a,b,c) >= 1) { .. }

// equivalent to (a!=null | b!=null | c!=null)
if (nulls(a,b,c) < 3) { .. }

// equivalent to (a==null & b==null & c==null)
if (nulls(a,b,c) == 3) { .. }

// equivalent to (a!=null & b!=null & c!=null)
if (nulls(a,b,c) == 0) { .. }
Khaled.K
quelle
2
Guter Ansatz, aber Ihr erster "äquivalenter" Kommentar ist schrecklich falsch (abgesehen von dem Rechtschreibfehler, der in allen Kommentaren vorhanden ist)
Ben Voigt
@ BenVoigt Vielen Dank für den Hinweis, jetzt behoben
Khaled.K
9

Da Sie etwas Besonderes tun möchten (Standardeinstellungen verwenden), wenn sowohl Absender als auch Kennwort fehlen, behandeln Sie dies zuerst.
Danach sollten Sie sowohl einen Absender als auch ein Passwort haben, um eine E-Mail zu senden. eine Ausnahme auslösen, wenn eine fehlt.

// use defaults if neither is provided
if ((from == null) && (password == null)) {
    from = DEFAULT_SENDER;
    password = DEFAULT_PASSWORD;
}

// we should have a sender and a password now
if (from == null) {
    throw new MissingSenderException();
}
if (password == null) {
    throw new MissingPasswordException();
}

Ein zusätzlicher Vorteil ist, dass, sollte einer Ihrer Standardeinstellungen null sein, dies ebenfalls erkannt wird.


Trotzdem denke ich im Allgemeinen , dass die Verwendung von XOR zulässig sein sollte, wenn dies der Operator ist, den Sie benötigen. Es ist ein Teil der Sprache, nicht nur ein Trick, der aufgrund eines arkanen Compiler-Fehlers funktioniert.
Ich hatte einmal einen Kuh-Orker, der den ternären Operator zu verwirrend fand, um ihn zu benutzen ...

SQB
quelle
1
Downvoted, weil ich eine zufällige Auswahl getroffen habe, um eine Ihrer Antworten zu testen, und den versprochenen xkcd-Link nicht finden kann! Schäm dich!
Dhein
@Zaibis Zu meiner Verteidigung ist es nur ein Hobby, kein Vollzeitjob. Aber ich werde sehen, ob ich einen finden kann ...
SQB
8

Ich möchte eine andere Alternative vorschlagen, wie ich diesen Code tatsächlich schreiben würde:

if( from != null )
{
    if( password == null )
        error( "password required for " + from );
}
else
{
    if( password != null )
        warn( "the given password will not be used" );
}

Für mich scheint dies der natürlichste Weg zu sein, diesen Zustand auszudrücken, der es für jemanden, der ihn in Zukunft möglicherweise lesen muss, leicht verständlich macht. Außerdem können Sie hilfreichere Diagnosemeldungen geben und das unnötige Kennwort als weniger schwerwiegend behandeln, und es ist einfach zu ändern, was für einen solchen Zustand eher wahrscheinlich ist. Das heißt, Sie stellen möglicherweise fest, dass die Angabe eines Kennworts als Befehlszeilenargument nicht die beste Idee ist, und möchten möglicherweise das Lesen des Kennworts aus der Standardeingabe optional zulassen, wenn das Argument fehlt. Oder Sie möchten das überflüssige Kennwortargument stillschweigend ignorieren. Änderungen wie diese würden nicht erfordern, dass Sie das Ganze neu schreiben.

Außerdem werden nur die Mindestanzahl von Vergleichen ausgeführt, sodass es nicht teurer ist als die "eleganteren" Alternativen. Obwohl die Leistung hier sehr unwahrscheinlich ist, ist das Starten eines neuen Prozesses bereits viel teurer als eine zusätzliche Nullprüfung.

x4u
quelle
Ich kommentiere etwas im Gespräch, daher könnte ich dem anderen mit einem "// wir haben eine Null von" folgen. Die Kürze des Beispiels macht dies wirklich geringfügig. Ich mag die Klarheit der Logik und die Reduzierung der Tests, die dies darstellt.
The Nate
Dies funktioniert einwandfrei, aber das Verschachteln, wenn Aussagen weniger klar und unübersichtlich erscheinen. Das ist jedoch nur eine persönliche Meinung, daher bin ich froh, dass diese Antwort als weitere Option hier ist
Kevin Wells
Was die Eleganz betrifft, ist dies wahrscheinlich eine der am wenigsten eleganten Möglichkeiten, dies zu tun.
Dramzy
7

Ich denke, ein korrekter Weg, um damit umzugehen, besteht darin, drei Situationen zu betrachten: Sowohl 'von' als auch 'Passwort' werden bereitgestellt, keine werden bereitgestellt, eine Mischung aus beiden wird bereitgestellt.

if(from != null && password != null){
    //use the provided values
} else if(from == null && password == null){
    //both values are null use the default values
} else{
   //throw an exception because the input is not correct.
}

Es hört sich so an, als ob die ursprüngliche Frage den Fluss unterbrechen möchte, wenn es sich um eine falsche Eingabe handelt, aber dann müssen sie später einen Teil der Logik wiederholen. Vielleicht könnte eine gute Wurfaussage sein:

throw new IllegalArgumentException("form of " + form + 
    " cannot be used with a "
    + (password==null?"null":"not null") +  
    " password. Either provide a value for both, or no value for both"
);
matt
quelle
2
Dieser Code ist falsch, nicht weil er nicht funktioniert, sondern weil er sehr schwer zu verstehen ist. Das Debuggen dieser Art von Code, der von jemand anderem geschrieben wurde, ist nur ein Albtraum.
NO_NAME
2
@NO_NAME Ich verstehe nicht, warum es schwer zu verstehen ist. Das OP stellte drei Fälle bereit: Wenn sowohl Formular als auch Passwort bereitgestellt werden, wenn keiner bereitgestellt wird, und der gemischte Fall, der eine Ausnahme auslösen sollte. Beziehen Sie sich auf die mittlere Bedingung, um zu überprüfen, ob beide null sind?
Matt
2
Ich stimme @NO_NAME zu, dass der mittlere Fall zu viel Analyse erfordert, um einen Blick darauf zu werfen. Wenn Sie nicht die oberste Zeile analysieren, erhalten Sie nicht, dass null etwas mit der Mitte zu tun hat. Die Gleichheit von von und Passwort ist in diesem Fall nur ein Nebeneffekt, wenn man nicht null ist.
jimm101
1
@ jimm101 Ja, ich konnte sehen, dass dies ein Problem ist. Der Leistungsvorteil wäre für eine ausführlichere Lösung minimal / nicht erkennbar. Ich bin mir nicht sicher, ob das das Problem ist. Ich werde es aktualisieren.
Matt
2
@matt Es gibt möglicherweise keinen Leistungsvorteil - es ist nicht klar, was der Compiler tun würde und was der Chip in diesem Fall aus dem Speicher ziehen würde. Viele Programmierzyklen können bei Optimierungen gebrannt werden, die eigentlich nichts bringen.
jimm101
6

Hier ist ein relativ unkomplizierter Weg, bei dem kein Xor oder langwieriges Wenn erforderlich ist. Es erfordert jedoch, dass Sie etwas ausführlicher sind, aber auf der anderen Seite können Sie die von mir vorgeschlagenen benutzerdefinierten Ausnahmen verwenden, um eine aussagekräftigere Fehlermeldung zu erhalten.

private void validatePasswordExists(Parameters params) {
   if (!params.hasKey("password")){
      throw new PasswordMissingException("Password missing");
   }
}

private void validateFromExists(Parameters params) {
   if (!params.hasKey("from")){
      throw new FromEmailMissingException("From-email missing");
   }
}

private void validateParams(Parameters params) {

  if (params.hasKey("from") || params.hasKey("password")){
     validateFromExists(params);
     validatePasswordExists(params);
  }
}
Arnab Datta
quelle
1
Sie sollten keine Ausnahmen anstelle einer Kontrollflussanweisung verwenden. Noch wichtiger ist, dass es nicht nur ein Leistungseinbruch ist, sondern auch die Lesbarkeit Ihres Codes beeinträchtigt, da es den mentalen Fluss unterbricht.
ein Phu
1
@anphu Nein. Nur nein. Die Verwendung von Ausnahmen erhöht die Lesbarkeit des Codes, da if-else-Klauseln entfernt werden und der Codefluss klarer wird. docs.oracle.com/javase/tutorial/essential/exceptions/…
Arnab Datta
1
Ich denke, Sie verwechseln etwas, das wirklich außergewöhnlich ist, mit etwas, das routinemäßig geschieht und als Teil der normalen Ausführung betrachtet werden könnte. Das Java-Dokument verwendet Beispiele, die außergewöhnlich sind, dh nicht genügend Speicher beim Lesen einer Datei. Die Begegnung mit ungültigen Parametern ist keine Ausnahme. "Verwenden Sie keine Ausnahmen für den normalen Kontrollfluss." - blogs.msdn.com/b/kcwalina/archive/2005/03/16/396787.aspx
ein phu
Zunächst einmal: Wenn fehlende / richtige Argumente keine Ausnahme sind, warum gibt es dann überhaupt die IllegalArgumentException? Zweitens: Wenn Sie wirklich glauben, dass ungültige Argumente keine Ausnahme sind, sollte es auch keine Validierung geben. Mit anderen Worten, versuchen Sie einfach, die Aktion auszuführen. Wenn etwas schief geht, lösen Sie eine Ausnahme aus. Dieser Ansatz ist in Ordnung, aber der Leistungsverlust, über den Sie sprechen, tritt hier auf, nicht in dem von mir vorgeschlagenen Ansatz. Java-Ausnahmen sind beim Auslösen nicht langsam. Es ist die Stapelverfolgung, deren Wiederherstellung einige Zeit in Anspruch nimmt.
Arnab Datta
Der Kontext ist der Schlüssel. Im OP-Kontext (sendmail app) ist es üblich und wird erwartet, dass Sie entweder den Benutzernamen oder das Passwort vergessen. In einem Raketenführungsalgo sollte ein Nullkoordinatenparameter eine Ausnahme auslösen. Ich habe nicht gesagt, keine Parameter zu validieren. Im Kontext von OP sagte ich, verwenden Sie keine Ausnahme, um die Anwendungslogik zu steuern. Das Abwickeln der Stacktrace ist der perfekte Hit, von dem ich spreche. Mit Ihrem Ansatz fangen Sie schließlich entweder die PasswordMissingException / FromEmailMissingException ab, dh entspannen Sie sich, oder lassen Sie sie schlimmer noch unbehandelt. .
ein Phu
6

Niemand scheint den ternären Operator erwähnt zu haben :

if (a==null? b!=null:b==null)

Funktioniert gut zum Überprüfen dieser bestimmten Bedingung, verallgemeinert sich jedoch nicht weit über zwei Variablen hinaus.

gbronner
quelle
1
Sieht gut aus , aber schwerer zu verstehen als ^, !=mit zwei bools oder zwei ifs
coolguy
@coolguy Ich vermute, dass der ternäre Operator weitaus häufiger vorkommt als der XOR-Operator (ganz zu schweigen von der "mentalen Überraschung", wenn Sie XOR in Code sehen, der keine Bitoperationen ausführt), und diese Formulierung vermeidet tendenziell den Schnitt und fügen Sie Fehler ein, die das Doppelte plagen, wenn.
Gbronner
Nicht empfohlen. Dies wird nicht zwischen (a! = Null && b == null) und (a == null && b! = Null) unterscheiden. Wenn Sie den ternären Operator verwenden wollen:a == null ? (b == null? "both null" : "a null while b is not") : (b ==null? "b null while a is not")
Arnab Datta
5

Wie ich Ihre Absichten sehe, besteht nicht die Notwendigkeit, immer beide exklusiven Nullen zu überprüfen, sondern zu prüfen, ob passwordgenau dann null ist, wenn fromnicht null ist. Sie können das angegebene passwordArgument ignorieren und Ihren eigenen Standard verwenden, wennfrom null ist.

In Pseudo geschrieben muss so sein:

if (from == null) { // form is null, ignore given password here
    // use your own defaults
} else if (password == null) { // form is given but password is not
    // throw exception
} else { // both arguments are given
    // use given arguments
}
JordiVilaplana
quelle
4
Das einzige Problem dabei ist, dass der Benutzer, wenn er passwordohne fromAngabe liefert , möglicherweise beabsichtigt hat, das Kennwort zu überschreiben, aber das Standardkonto beibehält. Wenn der Benutzer dies tut, handelt es sich um eine ungültige Anweisung, die ihm mitgeteilt werden sollte. Das Programm sollte nicht so fortfahren, als ob die Eingabe gültig wäre, und versuchen Sie, das Standardkonto mit einem Kennwort zu verwenden, das der Benutzer nicht angegeben hat. Ich schwöre bei solchen Programmen.
David Bullock
4

Ich bin überrascht, dass niemand die einfache Lösung erwähnt hat, eine Klasse zu erstellen fromund passwordFelder zu erstellen und einen Verweis auf eine Instanz dieser Klasse zu übergeben:

class Account {
    final String name, password;
    Account(String name, String password) {
        this.name = Objects.requireNonNull(name, "name");
        this.password = Objects.requireNonNull(password, "password");
    }
}

// the code that requires an account
Account from;
// do stuff

Hier from kann null oder nicht null sein, und wenn es nicht null ist, haben beide Felder nicht null Werte.

Ein Vorteil dieses Ansatzes besteht darin, dass der Fehler, ein Feld, aber nicht das andere Feld auf Null zu setzen, dort ausgelöst wird, wo das Konto ursprünglich abgerufen wurde, und nicht, wenn der Code, der das Konto verwendet, ausgeführt wird. Zum Zeitpunkt der Ausführung des Codes, der das Konto verwendet, ist es unmöglich, dass die Daten ungültig sind.

Ein weiterer Vorteil dieses Ansatzes ist besser lesbar, da er mehr semantische Informationen liefert. Es ist auch wahrscheinlich, dass Sie den Namen und das Kennwort an anderen Stellen zusammen benötigen, sodass sich die Kosten für die Definition einer zusätzlichen Klasse über mehrere Verwendungen amortisieren.

Setzen Sie Monica wieder ein
quelle
Es funktioniert nicht wie erwartet, da new Account(null, null)eine NPE ausgelöst wird, obwohl das Konto mit dem Nullnamen und dem Kennwort noch gültig ist.
HieuHT
Die Idee ist, null zu übergeben, wenn Name und Passwort null sind, unabhängig davon, ob das Konto in der realen Welt existiert oder nicht.
Stellen Sie Monica
Was ich von OP bekomme, ist, dass entweder beide nicht null sind oder beide null sind. Ich habe mich nur gefragt, wie Sie ein Kontoobjekt mit dem Namen und dem Kennwort null erstellen können.
HieuHT
@HieuHT Sorry mein letzter Kommentar war unklar. Wenn Name und Passwort null sind, würden Sie nullanstelle von ein verwenden Account. Sie würden nicht nullan den AccountKonstruktor übergeben.
Stellen Sie Monica