Baza Wiedzy

Helpful NullPointerExceptions

Jednym z usprawnień, które zostały wprowadzone w Javie 14 jest JEP 358, czyli Helpful NullPointerExceptions.

    Wprowadzenie🔗

    Do tej pory NullPointerException mówił nam o tym, że w kodzie wystąpił wyjątek, polegający na tym, że próbujemy się odwołać do jakiegoś pola lub metody poprzez pustą referencję (null). Niestety w przypadku, gdy w kodzie wywołujemy ciąg kilku metod, albo odwołujemy się do obiektów, które są zagregowane w innych obiektach, to wyjątek NPE nie był zbyt czytelny. Usprawnienie Helpful NullPointerExceptions rozwiązuje ten problem. Poniżej znajdziesz przykład, w którym pokażę Ci jak włączyć wyświetlanie dodatkowych informacji o wyjątku.

    Kurs Java

     

    NullPointerException🔗

    Spójrzmy na przykład, w którym klasa Group reprezentuje grupę w pewnej szkole (np. językowej). Grupa składa się z wielu uczniów, których możemy dodawać do listy, dodatkowo grupy są tematyczne i opisane jest to przy pomocy dodatkowego pola. Każdy uczeń ma pola takie jak imię i nazwisko oraz ma przypisany adres.

    Group.java

    import java.util.ArrayList;
    import java.util.List;
    
    class Group {
        private List<Student> students = new ArrayList<>();
    
        void add(Student student) {
            students.add(student);
        }
    
        public List<Student> getStudents() {
            return students;
        }
    }

    Student.java

    class Student {
        private String firstName;
        private String lastName;
        private Address address;
    
        public Student(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    }

    Address.java

    class Address {
        private String city;
        private String street;
        private String details; //home no / flat no
    
        public Address(String city, String street, String details) {
            this.city = city;
            this.street = street;
            this.details = details;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public String getStreet() {
            return street;
        }
    
        public void setStreet(String street) {
            this.street = street;
        }
    
        public String getDetails() {
            return details;
        }
    
        public void setDetails(String details) {
            this.details = details;
        }
    }

    W klasie testowej tworzę teraz grupę i dodaję do niej kilku studentów. Dalej będę chciał odfiltrować studentów, którzy mieszkają we Wrocławiu i wyświetlić ich imię oraz nazwisko.

    TestNpe.java

    import java.util.List;
    import java.util.stream.Collectors;
    
    class TestNpe {
        public static void main(String[] args) {
            Group group = new Group();
            group.add(new Student("Jan", "Kowalski"));
            group.add(new Student("Anna", "Zawadzka"));
            group.add(new Student("Piotr", "Adamczyk"));
    
            List<Student> wroclawStudents = group.getStudents()
                    .stream().filter(s -> s.getAddress().getCity().equals("Wrocław"))
                    .collect(Collectors.toList());
            wroclawStudents.forEach(s -> System.out.println(s.getFirstName() + " " + s.getLastName()));
        }
    }

    Po uruchomieniu programu otrzymamy wyjątek NullPointerException o treści:

    Na tej podstawie możemy wywnioskować, że wyjątek został rzucony gdzieś w wierszu 12, ale nie wiemy czy nullem jest referencja s, s.getAddress, czy też może miasto w adresie, czyli s.getAddress().getCity().

     

    Helpful NullPointerExceptions🔗

    Od Javy 14 wprowadzono usprawnienie o nazwie Helpful NullPointerExceptions. Domyślnie jest ono wyłączone, aby je włączyć, podczas uruchamiania programu należy dodać flagę -XX:+ShowCodeDetailsInExceptionMessages. Jeżeli korzystasz z IntelliJ IDEA, to możesz to zrobić w konfiguracji uruchomieniowej aplikacji:

    Po uruchomieniu programu z tą dodatkową flagą zobaczymy taki komunikat błędu:

    Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Address.getCity()" because the return value of "Student.getAddress()" is null
    	at TestNpe.lambda$main$0(TestNpe.java:12)
    	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)
    	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1624)
    	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    	at TestNpe.main(TestNpe.java:13)

    W pierwszym wierszu otrzymujemy dokładną informację o tym co poszło nie tak. Nie musimy się już domyślać, która referencja jest pusta, ponieważ otrzymujemy jasny komunikat, że któryś student nie ma ustawionego adresu (u nas żaden student go nie ma).

    Wyjątek NullPointerException jest często zmorą początkujących programistów. Dzięki temu usprawnieniu jego wykrycie i wyeliminowanie może być dużo prostsze.

    Najlepszy newsletter o Javie w Polsce

    Czy chcesz otrzymywać nowości ze świata Javy oraz przykładowe pytania rekrutacyjne? Zapisz się na newsletter i bądź na bieżąco! Otrzymasz także ekskluzywne materiały oraz informacje o nowych kursach i promocjach.

    Nikomu nie udostępniamy Twojego maila, a jeśli zechcesz to w każdej chwili możesz się wypisać.

    Komentarze do artykułu

    Wyłączyliśmy możliwość dodawania komentarzy. Poniżej znajdziesz archiwalne wpisy z czasów gdy strona była jeszcze hobbystycznym blogiem. Zapraszamy natomiast do zadawnia pytań i dyskusji na naszej grupe na facebooku.