Sprawdź dwa argumenty w Javie, albo oba nie mają wartości null, albo oba elegancko


161

Spring boot wykorzystałem do stworzenia projektu powłoki służącego do wysyłania e-maili, np

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

Jeśli fromipassword brakuje argumentów , używam domyślnego nadawcy i hasła, np. noreply@bar.comI123456 .

Więc jeśli użytkownik przekaże plik from argument, musi również przekazaćpassword argument i odwrotnie. Oznacza to, że albo oba są niezerowe, albo oba są zerowe.

Jak to elegancko sprawdzić?

Teraz moja droga jest

if ((from != null && password == null) || (from == null && password != null)) {
    throw new RuntimeException("from and password either both exist or both not exist");
}

14
Na marginesie, zwróć uwagę, jak ostrożne używanie białych znaków sprawia, że ​​kod jest dużo łatwiejszy do odczytania - samo dodanie spacji między operatorami w bieżącym kodzie znacznie zwiększyłoby czytelność IMO.
Jon Skeet

8
Zdefiniuj „elegancję”.
Renaud

Potrzebny jest oddzielny zestaw argumentów dla poświadczeń uwierzytelniania SMTP i dla adresu e-mail nadawcy w kopercie. FromAdres e-mail nie zawsze jest nazwą uwierzytelnianie SMTP.
Kaz

3
Naprawdę nie można go bardziej zoptymalizować, jest to jedna linia czytelnego kodu i nic nie można zyskać poprzez nadmierną optymalizację.
diynevala,

3
Uwaga dodatkowa: jeśli jest to skrypt powłoki, czy hasła nie zostaną zapisane w historii powłoki?
dotknij mojego ciała

Odpowiedzi:


331

Istnieje sposób wykorzystania operatora ^( XOR ):

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

Plik ifWarunek będzie prawdziwa, jeśli tylko jedna zmienna ma wartość null.

Ale myślę, że zwykle lepiej jest użyć dwóch if warunków z różnymi komunikatami o wyjątkach. Nie możesz zdefiniować, co poszło nie tak, używając jednego warunku.

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");
}

Jest bardziej czytelny i dużo łatwiejszy do zrozumienia i wymaga tylko trochę dodatkowego wpisywania.


152
Czy jest powód, dla którego xor na dwóch boolach jest lepszy niż !=na dwóch?
Eric Lippert

1
Wow, nie zdawałem sobie sprawy, że XOR na boolean to to samo co !=. Mindblown. A to bardzo duża liczba głosów za w komentarzu. I żeby dodać jakość do tego komentarza, tak, uważam też, że podanie innego komunikatu o błędzie dla różnych przypadków błędu jest lepsze, ponieważ użytkownik będzie wiedział lepiej, jak poprawić błąd.
justhalf

1
Na 2 elementy jest w porządku. Jak to zrobić z> 2 elementami?
Anushree Acharjee

Chcę wyświetlić komunikat o błędzie, jeśli którykolwiek z elementów jest> 0. Domyślnie wszystkie są ustawione na 0. Jeśli wszystkie są> 0, jest to prawidłowy scenariusz. Jak to zrobić?
Anushree Acharjee

To byłoby fajne pytanie do wywiadu. Zastanawiam się, jakie% programistów to wie. Ale nie zgadzam się, że nie jest to wystarczająco jasne i uzasadnia podział na 2 ifklauzule - wiadomość w wyjątku ładnie to dokumentuje (redagowałem pytanie, ale pojawi się dopiero po akceptacji)
Adam

286

Cóż, wygląda na to, że próbujesz sprawdzić, czy warunek „nieważności” tych dwóch jest taki sam, czy nie. Możesz użyć:

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

Lub wyjaśnij to bardziej za pomocą zmiennych pomocniczych:

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}

18
Jesteś jednym z moich bohaterów SO @Kaz, ale nic nie mówi „ani to, ani tamto, ale nie oba takie same” ^. :-)
David Bullock

6
@DavidBullock: Jeśli chodzi o wartości logiczne, nic nie mówi „ani to, ani tamto, ale nie oba takie same” jak ... ”nie oba takie same”; XOR to po prostu inna nazwa funkcji „nie równa się” w porównaniu z parametrami logicznymi.
Kaz

5
@Kaz To po prostu ^mówi „Hej, moje operandy są wartościami logicznymi” w sposób, który !=tego nie robi. (Chociaż ten efekt jest niestety osłabiony przez potrzebę sprawdzenia, czy „moje operandy mogą być numeryczne, a ja mogę nie być operatorem relacyjnym w tym momencie”, co przyznaję, jest wadą). Twój status bohatera nie zmniejszył się, mimo że się ze mną nie zgadzasz :-)
David Bullock,

3
Po przeczytaniu wymagań problemu, to Twoje rozwiązanie, kod ma sens i jest czytelny. Ale jako programista od 4 lat (wciąż w szkole), przeczytanie tego kodu, a następnie próba ustalenia, jakie „wymagania biznesowe” zostały wprowadzone, byłaby bólem głowy. Z tego kodu nie rozumiem od razu, że „ fromi passwordoba muszą mieć wartość null lub obie nie mogą być puste”. Być może to tylko ja i mój brak doświadczenia, ale wolę bardziej czytelne rozwiązanie, jak w odpowiedzi @ stig-hemmer, nawet jeśli kosztuje to kolejne 3 linie kodu. Chyba po prostu nie rozumiem od razu bool != bool- to nie jest intuicyjne.
Chris Cirefice,

2
@DavidBullock ^Operator jest operatorem bitowym; w rzeczywistości nie oznacza to, że jego operandy są logiczne. Operatorem boolowskim xor jest xor.
Brilliand

222

Osobiście wolę czytelny niż elegancki.

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}

52
+1 dla lepszych wiadomości. To jest ważne, nikt nie lubi handwaving „coś poszło źle” -error wiadomości, więc nikt nie powinien powodować takie wiadomości. Jednak w praktyce należy preferować bardziej szczegółowy wyjątek (szczególnie IllegalArgumentExceptionzamiast nagiego RuntimeException)
Marco13

6
@matt wygląda na to, że twoja krytyka nie dotyczy kodu, ale tekstu wyjątków. Myślę jednak, że zasługa tej odpowiedzi leży w strukturze instrukcji if, a nie w treści komunikatów o błędach. To najlepsza odpowiedź, ponieważ poprawia funkcjonalność; OP może z łatwością zastąpić tekstami wyjątków dowolne ciągi znaków.
Dan Henderson,

4
@matt Zaletą jest to, że można rozróżnić, które z dwóch nieprawidłowych stanów wystąpiły, i dostosować komunikat o błędzie. Więc zamiast mówić „zrobiłeś jedną z tych dwóch rzeczy źle”, możesz powiedzieć „zrobiłeś to” lub „zrobiłeś tamto” (a następnie przejdź do opisu kroków rozwiązania, jeśli chcesz). Rozdzielczość może być taka sama w obu przypadkach, ale nigdy nie jest dobrym pomysłem powiedzenie „jedną z tych rzeczy zrobiłeś źle”. Źródło: w środowisku, w którym nie byłem w stanie zapewnić tej funkcjonalności, odpowiedziałem na wiele pytań od użytkowników, którzy spełnili pierwszy warunek w moim tekście błędu.
Dan Henderson,

4
@DanHenderson> nigdy nie jest dobrym pomysłem powiedzenie „jedną z tych rzeczy zrobiłeś źle”. Nie zgadzam się. Hasło / nazwa użytkownika Bezpieczniej jest po prostu powiedzieć, że nazwa użytkownika i hasło nie są zgodne.
Matt

2
@DanHenderson Z punktu widzenia bezpieczeństwa lepiej nie rozróżniać między przypadkiem, w którym nazwa użytkownika znajduje się w katalogu, czy nie, ponieważ w przeciwnym razie osoba atakująca mogłaby znaleźć prawidłowe nazwy użytkownika. Jednak mieszanie wartości null / not null jest (w tym przypadku) zawsze błędem użytkowania, a wyświetlenie bardziej szczegółowego komunikatu o błędzie nie powoduje wycieku więcej informacji niż podane przez użytkownika w pierwszej kolejności.
siegi

16

Umieść tę funkcjonalność w metodzie 2-argumentowej z podpisem:

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

Oszczędza to miejsce w rzeczywistej metodzie, którą jesteś zainteresowany i czyni ją bardziej czytelną. Nie ma nic złego w lekko rozwlekłych nazwach metod i nie ma nic złego w bardzo krótkich metodach.


14
Brak oszczędności miejsca w porównaniu z ((from == null) != (password == null))tym jest bardzo łatwy do zrozumienia. Coś jest nie tak z nieprzydatnymi metodami.
edc65

3
Jest jeden wiersz dla instrukcji if, drugi wiersz dla instrukcji throw, a trzeci wiersz dla zamykającego nawiasu: wszystko zastąpione jednym wierszem. Jeszcze jedna linia zapisana, jeśli nadasz nawiasom zamykającym nową linię!
Traubenfuchs

10
Czytając kod, masz jedną nazwę metody, którą musisz zrozumieć, a żonglowanie warunkami.
Traubenfuchs

1
zdecydowanie +1, zawsze wolę odrzucić nieczytelne szczegóły implementacji i operatory za pomocą metod opisowych i nazw zmiennych, które sprawiają, że INTENTION jest jasny. logika zawiera błędy. komentarze są jeszcze gorsze. nazwa metody pokazuje intencje i izoluje logikę, dzięki czemu łatwiej jest znaleźć i naprawić błędy. to rozwiązanie nie wymaga od czytelnika znajomości ani myślenia o jakiejkolwiek składni lub logice, zamiast tego pozwala nam skupić się na WYMAGANIACH BIZNESOWYCH (co jest naprawdę ważne)
sara

1
Gdybyś chciał mieć tutaj jakiś opisowy komunikat o wyjątku, napotkałbyś niepotrzebne kłopoty.
Honza Brabec

11

Należy użyć rozwiązania Java 8 Objects.isNull(Object), zakładając import statyczny:

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

W przypadku języka Java <8 (lub jeśli nie lubisz używać Objects.isNull()), możesz łatwo napisać własnyisNull() metodę.


6
Nie podoba mi się to. from == null != password == nullutrzymuje to wszystko w tej samej ramce stosu, ale używając Objects.isNull(Object)niepotrzebnie wypycha i zdejmuje dwie klatki. Objects.isNull (Object) istnieje, ponieważ „Ta metoda istnieje do użycia jako predykat” (tj. W strumieniach).
David Bullock,

5
Prosta metoda, taka jak ta, zwykle jest szybko wprowadzana przez JIT, więc wpływ na wydajność jest najprawdopodobniej pomijalny. Moglibyśmy rzeczywiście debatować nad użyciem Objects.isNull()- jeśli wolisz, możesz napisać własne - ale jeśli chodzi o czytelność, myślę, że używanie isNull()jest lepsze. Ponadto potrzebne są dodatkowe nawiasy aby proste kompilacji wyrażenie: from == null != (password == null).
Didier L

2
Zgadzam się co do JIT (i kolejności operacji ... byłem leniwy). Mimo (val == null)to , jest tak bardzo ułatwieniem dostarczonym w celu porównania z null, trudno mi przejść przez dwa duże, grube wywołania metody, które patrzą mi prosto w twarz, nawet jeśli metoda jest dość funkcjonalna, wbudowana i dobrze ... o imieniu. Ale to tylko ja. Ostatnio zdecydowałem, że jestem mildy dziwna.
David Bullock,

4
szczerze, kogo obchodzi jedna ramka stosu? stos jest problemem tylko wtedy, gdy masz do czynienia z (prawdopodobnie nieskończoną) rekurencją lub jeśli masz 1000-warstwową aplikację z grafem obiektowym wielkości pustyni Sahara.
sara,

9

Oto ogólne rozwiązanie dla dowolnej liczby sprawdzeń zerowych

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));
}

Używa

// 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) { .. }

2
Dobre podejście, ale Twój pierwszy komentarz „odpowiednik” jest okropnie błędny (poza błędem w pisowni, który występuje we wszystkich komentarzach)
Ben Voigt,

@BenVoigt Dziękuję za powiadomienie, naprawione teraz
Khaled.K

9

Ponieważ chcesz zrobić coś specjalnego (użyj wartości domyślnych), gdy nie ma nadawcy i hasła, zajmij się tym najpierw.
Następnie powinieneś mieć zarówno nadawcę, jak i hasło, aby wysłać wiadomość e-mail; zgłoś wyjątek, jeśli brakuje któregokolwiek z nich.

// 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();
}

Dodatkową korzyścią jest to, że jeśli którekolwiek z ustawień domyślnych ma wartość null, zostanie również wykryte.


Powiedziawszy to, generalnie uważam, że użycie XOR powinno być dozwolone, gdy jest to operator, którego potrzebujesz. Jest to część języka, a nie tylko sztuczka, która działa z powodu tajemniczego błędu kompilatora.
Miałem kiedyś krowoszka, dla którego operator trójskładnikowy był zbyt zagmatwany, by go używać ...


1
Ocena negatywna, ponieważ wybrałem losowo jedną z Twoich odpowiedzi i nie mogę znaleźć obiecanego linku do xkcd! wstydź się!
dhein

@Zaibis W mojej obronie to tylko hobby, a nie praca na pełny etat. Ale zobaczę, czy uda mi się znaleźć ...
SQB

8

Chciałbym zasugerować inną alternatywę, w której faktycznie napisałbym ten fragment kodu:

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

Wydaje mi się, że jest to najbardziej naturalny sposób wyrażenia tego warunku, który ułatwia zrozumienie dla kogoś, kto być może będzie musiał go przeczytać w przyszłości. Pozwala również na przekazywanie bardziej pomocnych komunikatów diagnostycznych i traktowanie niepotrzebnego hasła jako mniej poważnego oraz ułatwia modyfikację, która jest raczej prawdopodobna w takim stanie. Tzn. Może się okazać, że podanie hasła jako argumentu wiersza poleceń nie jest najlepszym pomysłem i może zechcieć pozwolić na odczytanie hasła ze standardowego wejścia opcjonalnie, jeśli brakuje argumentu. Lub możesz po cichu zignorować zbędny argument dotyczący hasła. Takie zmiany nie wymagałyby przepisywania całości.

Poza tym wykonuje tylko minimalną liczbę porównań, więc nie jest droższy niż bardziej „eleganckie” alternatywy. Chociaż wydajność jest tutaj bardzo mało prawdopodobna, ponieważ rozpoczęcie nowego procesu jest już znacznie droższe niż dodatkowe sprawdzenie zerowe.


Komentuję nieco konwersacyjnie, więc mógłbym za tym napisać „// mamy null from”. Zwięzłość przykładu sprawia, że ​​jest to naprawdę niewielkie. Podoba mi się przejrzystość logiki i redukcja testów, jakie to przedstawia.
The Nate

Działa to doskonale, ale zagnieżdżanie, jeśli stwierdzenia wydają mi się mniej jasne i bardziej zagracone. To jednak tylko osobista opinia, więc cieszę się, że ta odpowiedź jest tutaj jako inna opcja
Kevin Wells

Jeśli chodzi o elegancję, jest to prawdopodobnie jeden z najmniej eleganckich sposobów na zrobienie tego.
dramzy

7

Myślę, że prawidłowym sposobem rozwiązania tego problemu jest rozważenie trzech sytuacji: podano zarówno „od”, jak i „hasło”, żadne z nich nie są podane, podano połączenie tych dwóch.

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.
}

Wygląda na to, że pierwotne pytanie chce przerwać przepływ, jeśli jest to niepoprawne dane wejściowe, ale później będą musieli powtórzyć część logiki. Być może dobrym stwierdzeniem dotyczącym rzutu może być:

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"
);

2
Ten kod jest zły nie dlatego, że nie działa, ale dlatego, że jest bardzo trudny do zrozumienia. Debugowanie tego rodzaju kodu, napisanego przez kogoś innego, to tylko koszmar.
NO_NAME

2
@NO_NAME Nie rozumiem, dlaczego trudno to zrozumieć. OP dostarczył trzy przypadki: gdy podano zarówno formularz, jak i hasło, gdy nie podano żadnego, oraz mieszaną wielkość liter, która powinna zgłosić wyjątek. Czy odnosisz się do środkowego warunku, aby sprawdzić, czy oba są zerowe?
Matt

2
Zgadzam się z @NO_NAME, że spojrzenie na środkowy przypadek wymaga zbyt wielu analiz. O ile nie przeanalizujesz górnej linii, nie dostaniesz, że wartość null ma coś wspólnego ze środkiem. Równość od i hasła w tym przypadku jest tak naprawdę efektem ubocznym braku wartości zerowej.
jimm101

1
@ jimm101 Tak, widzę, że to problem. Korzyści z wydajności byłyby minimalne / niewykrywalne w przypadku bardziej szczegółowego rozwiązania. Nie jestem jednak pewien, czy na tym polega problem. Zaktualizuję to.
Matt

2
@matt Może nie być korzyści w zakresie wydajności - nie jest jasne, co zrobiłby kompilator i co chip wyciągnąłby z pamięci w tym przypadku. Wiele cykli programistycznych można spalić na optymalizacjach, które tak naprawdę nic nie dają.
jimm101

6

Oto stosunkowo prosty sposób, który nie obejmuje żadnych Xor i długich ifs. Wymaga to jednak nieco większej szczegółowości, ale z drugiej strony możesz użyć niestandardowych wyjątków, które zasugerowałem, aby uzyskać bardziej znaczący komunikat o błędzie.

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);
  }
}

1
nie należy używać wyjątków zamiast instrukcji przepływu sterowania. Oprócz tego, że jest hitem wydajnościowym, co ważniejsze, zmniejsza czytelność kodu, ponieważ przerywa przepływ mentalny.
phu

1
@anphu Nie. Po prostu nie. Korzystanie z wyjątków zwiększa czytelność kodu, ponieważ usuwa klauzule if-else i sprawia, że ​​przepływ kodu jest bardziej przejrzysty. docs.oracle.com/javase/tutorial/essential/exceptions/…
Arnab Datta

1
Myślę, że mylisz coś, co jest naprawdę wyjątkowe, z czymś, co dzieje się rutynowo i może być uznane za część normalnej realizacji. Dokument java używa wyjątkowych przykładów, np. Braku pamięci podczas odczytu pliku; Napotkanie nieprawidłowych parametrów nie jest wyjątkiem. „Nie używaj wyjątków dla normalnego przepływu kontroli”. - blogs.msdn.com/b/kcwalina/archive/2005/03/16/396787.aspx
an phu

Po pierwsze: jeśli brakujące / prawidłowe argumenty nie są wyjątkowe, dlaczego w ogóle istnieje wyjątek IllegalArgumentException? Po drugie: jeśli naprawdę wierzysz, że niepoprawne argumenty nie są wyjątkowe, to również nie powinno być ich potwierdzania. Innymi słowy, po prostu spróbuj wykonać akcję, a gdy coś pójdzie nie tak, wyrzuć wyjątek. To podejście jest w porządku, ale spadek wydajności, o którym mówisz, występuje tutaj, a nie w podejściu, które sugerowałem. Wyrzucane wyjątki Java nie są powolne; to ślad stosu wymaga czasu, aby odzyskać.
Arnab Datta

Kontekst jest kluczowy. W kontekście OP (aplikacja sendmail) zapomnienie nazwy użytkownika i hasła jest powszechne i oczekiwane. W algo naprowadzania pocisków zerowy parametr współrzędnych powinien zgłosić wyjątek. Nie powiedziałem, żeby nie sprawdzać poprawności parametrów. W kontekście OP powiedziałem, że nie używaj wyjątków do sterowania logiką aplikacji. Rozwinięcie śledzenia stosu jest hitem, o którym mówię. Korzystając z twojego podejścia, ostatecznie albo złapiesz PasswordMissingException / FromEmailMissingException, czyli odpręż się, albo, co gorsza, zostaw to bez obsługi. .
phu

6

Wydaje się, że nikt nie wspomniał o operatorze trójskładnikowym :

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

Dobrze sprawdza się przy sprawdzaniu tego konkretnego warunku, ale nie generalizuje dobrze poza dwiema zmiennymi.


1
Wygląda ładnie, ale trudniejszy do zrozumienia niż ^, !=z dwoma bools lub dwóch ifsekund
coolguy

@coolguy Domyślam się, że operator trójskładnikowy jest znacznie bardziej powszechny niż operator XOR (nie wspominając o `` mentalnym zaskoczeniu '' za każdym razem, gdy widzisz XOR w kodzie, który nie wykonuje operacji bitowych), a to sformułowanie ma tendencję do unikania cięcia i wklej błędy, które nękają podwójne if.
gbronner

Niepolecane. Nie spowoduje to rozróżnienia między (a! = Null && b == null) i (a == null && b! = Null). Jeśli zamierzasz użyć operatora trójskładnikowego:a == null ? (b == null? "both null" : "a null while b is not") : (b ==null? "b null while a is not")
Arnab Datta

5

Jak widzę twoje intencje, nie ma potrzeby zawsze sprawdzać obu wyłącznych nieważności, ale sprawdzanie, czy passwordjest zerowe wtedy i tylko wtedy, gdy fromnie jest zerowe. Możesz zignorować podany passwordargument i użyć własnej wartości domyślnej, jeślifrom ma wartość null.

Napisane pseudo musi wyglądać tak:

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
}

4
Jedyny problem polega na tym, że gdy użytkownik dostarcza passwordbez dostarczania from, być może zamierzał zastąpić hasło, ale zachować konto domyślne. Jeśli użytkownik to zrobi, jest to nieprawidłowa instrukcja i należy go o tym poinformować. Program nie powinien działać tak, jakby dane wejściowe były prawidłowe, i próbować użyć domyślnego konta z hasłem, którego użytkownik nie określił. Przysięgam na takie programy.
David Bullock,

4

Dziwię się, że nikt nie wspomniał o prostym rozwiązaniu tworzenia fromi passwordpól klasy oraz przekazywania odwołania do instancji tej klasy:

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

Tutaj from może mieć wartość null lub niezerową, a jeśli jest różna od null, oba jego pola mają wartości inne niż null.

Jedną z zalet tego podejścia jest to, że błąd polegający na utworzeniu jednego pola, ale nie drugiego pola o wartości null, jest wyzwalany w momencie, gdy konto jest początkowo uzyskiwane, a nie podczas wykonywania kodu używającego konta. Do czasu wykonania kodu korzystającego z konta niemożliwe jest, aby dane były nieprawidłowe.

Kolejna zaleta tego podejścia jest bardziej czytelna, ponieważ dostarcza więcej informacji semantycznych. Jest również prawdopodobne, że będziesz potrzebować nazwy i hasła razem w innych miejscach, więc koszt zdefiniowania dodatkowej klasy amortyzuje się przy wielokrotnym użyciu.


Nie działa zgodnie z oczekiwaniami, ponieważ new Account(null, null)wyrzuci NPE, mimo że konto z pustą nazwą i hasłem jest nadal ważne.
HieuHT

Chodzi o to, aby przekazać null, jeśli nazwa i hasło są puste, niezależnie od tego, czy w świecie rzeczywistym można powiedzieć, że konto istnieje.
Przywróć Monikę

To, co otrzymuję z OP, to znaczy, że albo oba są niezerowe, albo oba są zerowe. Zastanawiałem się tylko, jak utworzyć obiekt konta z zerową nazwą i hasłem?
HieuHT

@HieuHT Przepraszam, mój ostatni komentarz był niejasny. Jeśli nazwa i hasło są puste, należy użyć nullzamiast Account. Nie przejdziesz nulldo Accountkonstruktora.
Przywróć Monikę
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.