Bez wyjątku podczas przesyłania typu z zerową wartością w Javie


Odpowiedzi:


323

Możesz rzutować nullna dowolny typ odniesienia bez żadnych wyjątków.

printlnMetoda nie wyrzucać pustego wskaźnika, ponieważ najpierw sprawdza, czy obiekt jest null lub nie. Jeśli jest pusty, to po prostu drukuje ciąg "null". W przeciwnym razie wywoła toStringmetodę tego obiektu.

Dodawanie dodatkowych szczegółów:String.valueOf(object) Metoda wywołania metody drukowania metod wewnętrznych na obiekcie wejściowym. W valueOfmetodzie to sprawdzenie pomaga uniknąć wyjątku wskaźnika zerowego:

return (obj == null) ? "null" : obj.toString();

Przez resztę zamieszania wywołanie dowolnej metody na obiekcie o wartości NULL powinno zgłosić wyjątek wskaźnika NULL, jeśli nie jest to szczególny przypadek.


1
@ JunedAhsan, jakie specjalne przypadki spowodowałyby, że nie wyrzuciłby NPE?
Holloway,

@Trengot Sprawdź jeden wymieniony w odpowiedzi Piotra poniżej.
Juned Ahsan,

144

Możesz rzutować nullna dowolny typ odniesienia. Możesz także wywoływać metody, które obsługują nulljako argument, np. System.out.println(Object)Robi, ale nie możesz odwoływać się do nullwartości i wywoływać na niej metodę.

BTW Istnieje trudna sytuacja, w której wydaje się, że można wywoływać metody statyczne na nullwartościach.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.

12
Łał. Gdyby mnie o to zapytał, byłbym w 100% pewien, że rzuci wyjątek. Rzeczywiście trudna sprawa.
Magnilex,

2
@Magnilex: Absolutnie! jest to typowe pytanie do egzaminu OCPJP.
ccpizza 17.03.16

3
Czy to nie dlatego, że kompilator w kodzie bajtowym „optymalizuje” go do tego t.yield() -> Thread.yeld() ? Podobne do tego, jak final int i = 1; while (i == 1)jest zoptymalizowany dowhile(true)
SGal

@SGal Jest jeszcze lepiej, ponieważ druga optymalizacja AFAIK nie jest obowiązkowa, podczas gdy pierwsza jest.
Paul Stelian,

36

To jest z założenia. Możesz rzutować nullna dowolny typ odniesienia. W przeciwnym razie nie byłoby możliwe przypisanie go do zmiennych odniesienia.


dzięki! ta uwaga dotycząca przypisywania wartości null do zmiennych referencyjnych jest naprawdę pomocna!
Max

22

Rzucanie wartości null jest wymagane w przypadku następującej konstrukcji, w której metoda jest przeciążona, a jeśli do tych przeciążonych metod zostanie przekazana wartość null, wówczas kompilator nie wie, jak usunąć niejednoznaczność, dlatego w takich przypadkach musimy wpisać typ null:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

W przeciwnym razie nie można wywołać wymaganej metody.


W większości przypadków rzutowanie jest niejawne, np. String bar = null;Rzutuje nullwartość na String. Do tej pory musiałem tylko jawnie nadawać wartość NULL w teście, w którym metoda została przeciążona i chciałem przetestować jej zachowanie przy użyciu danych wejściowych NULL. Mimo to, dobrze wiedzieć, miałem zamiar napisać podobną odpowiedź, zanim znalazłem twoją.
Vlasec

Ciekawostka: l instanceof Longi s instanceof Stringwróci falsew tych przypadkach.
Attila Tanyi

7

Println(Object) wykorzystuje String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) sprawdza wartość zerową.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}


3

Jak napisali inni, możesz rzucić zero na wszystko. Zwykle nie potrzebujesz tego, możesz napisać:

String nullString = null;

bez umieszczania tam obsady.

Ale są sytuacje, w których takie obsady mają sens:

a) jeśli chcesz się upewnić, że wywoływana jest określona metoda, na przykład:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

wtedy wpiszesz różnicę

foo((String) null) vs. foo(null)

b) jeśli zamierzasz używać swojego IDE do generowania kodu; na przykład zazwyczaj piszę testy jednostkowe, takie jak:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Robię TDD; oznacza to, że klasa „MyClassUnderTest” prawdopodobnie jeszcze nie istnieje. Zapisując ten kod, mogę następnie użyć mojego IDE do wygenerowania nowej klasy; a następnie wygenerować konstruktor akceptujący „wszystko” argument „po wyjęciu z pudełka” - IDE może stwierdzić z mojego testu, że konstruktor powinien wziąć dokładnie jeden argument typu Cokolwiek.


2

Drukuj :

Wydrukuj obiekt. Łańcuch wytworzony metodą String.valueOf (Object) jest tłumaczony na bajty

Wartość :

jeśli argument jest pusty, to ciąg równy „null”; w przeciwnym razie zwracana jest wartość obj.toString ().

Zwróci po prostu łańcuch o wartości „null”, gdy obiekt jest null.


2

Jest to bardzo przydatne, gdy używa się metody, która w innym przypadku byłaby niejednoznaczna. Na przykład: JDialog ma konstruktory z następującymi podpisami:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Muszę użyć tego konstruktora, ponieważ chcę ustawić GraphicsConfiguration, ale nie mam elementu nadrzędnego dla tego okna dialogowego, więc pierwszy argument powinien być pusty. Za pomocą

JDialog(null, String, boolean, Graphicsconfiguration) 

jest niejednoznaczny, więc w tym przypadku mogę zawęzić wywołanie, ustawiając null na jeden z obsługiwanych typów:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)

0

Ta funkcja języka jest wygodna w tej sytuacji.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Jeśli memberHashMap.get („Nazwa”) zwraca null, nadal chcesz, aby powyższa metoda zwracała null bez zgłaszania wyjątku. Bez względu na klasę, null to null.

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.