Null-Pointer Exception beim Programmstart

Wuast

Bekanntes Mitglied
Hallo Leute,

ich drehe durch. Ich bekomme beim Programmstart eine Null-Pointer-Exception geworfen.
Das Problem ist eine Liste. Wenn ich diese nun
Java:
public class Beispielklasse {
List beispielListe =  new ArrayList();
    //Variablen & Methoden sind hier nicht weiter relevant
}
so deklariere und in der Main ein Objekt der beispielKlasse erzeuge, ist alles fein.

Wenn ich das aber über einen Konstruktor mache, dann ist die Liste null.
Code:
public class Beispielklasse {

    List beispielListe;
    
    public Beispielklasse(){
    beispielListe = new ArrayList();
    }

    // und sie ist auch null bei
    public Beispielklasse (BeispielObjekt objekt){
    beispielListe = new ArrayList();
    beispielListe.add(objekt);
    }
    //weil ich beim Programmstart noch kein BeispielObjekt habe, das soll nämlich der Nutzer über ein UI erzeugen
    //und dann hätte ich auch wieder diese hässliche static-Kacke in der Main.
}

Sollte ich also automatisch immer eine neue ArrayList erzeugen lassen, wenn ein Objekt der Beispielklasse erzeuge oder wie verhindert man die Exception sonst so (Stichwort "guter Code")? Kümmert sich dann der Garbage-Collector darum, wenn ich das später nicht mehr brauche?
Wenn die Liste null ist, ist das Programm jedenfalls nicht lauffähig, also hier habe ich entweder ein tiefsitzendes Designproblem oder zu viel Angst, einfach die = new ArrayList(); einzusetzen.

Kann mir da jemand einen Tipp geben? 🙂
 
Eine NPE kommt, wenn du auf eine Variable ohne "Inhalt" (also NULL) zugreifen willst. Zum Beispiel dein .add();

Pauschal gesagt: Wenn du zu einer Liste etwas hinzufügen wisst, musst du die Liste "automatisch" erzeugen.

Ich würde das so machen:

Java:
public class Beispielklasse {

    private List beispielListe;
    
    public Beispielklasse(){
        beispielListe = new ArrayList();
    }

    public Beispielklasse (BeispielObjekt objekt){
        this();
        beispielListe.add(objekt);
    }

}

Anhand deines Beispiels lassen sich viele "gute Code" Geschichten erzählen, aber wäre meines erachtens zu sehr ins blaue geraten, was du da tatsächlich brauchst.

Der GC wird das Objekt wegräumen, wenn kein Thread mehr darauf zugreifen kann. Wann das in deinem Programm und ob das überhaupt passiert, kann nicht beurteilt werden.

Poste hier deinen richtigen Code, damit man eine fundierte Code Review machen kann.
 
Eine NPE kommt, wenn du auf eine Variable ohne "Inhalt" (also NULL) zugreifen willst. Zum Beispiel dein .add();
Grundsätzlich klar. Ich möchte also, dass die Liste nicht null ist. Deswegen klappt es ja auch, wenn ich direkt = new ArrayList(); verwende.
Aber wenn ich die über den Konstruktor deklarieren will, ist die wieder null. Das schnall ich nicht, warum ist das so?



Java:
public class Beispielklasse {

    private List beispielListe;
   
    public Beispielklasse(){
        beispielListe = new ArrayList();
    }

    public Beispielklasse (BeispielObjekt objekt){
        this();
        beispielListe.add(objekt);
    }

}
was bewirkt das this(); hier konkret? 🙂 Und welchen Konstruktor rufst du dann in der Main auf? Weil
public Beispielklasse(){
beispielListe = new ArrayList();
}
habe ich ja selbst schon aufgerufen, da ist die Liste wieder null.

Poste hier deinen richtigen Code, damit man eine fundierte Code Review machen kann.
Da gibts einen guten Grund, warum ich das nicht getan habe 😀 Sorry
Aber danke für deine Rückmeldung
 
Anhand deiner Informationen kann man maximal raten, was du da tust.

- Poste den konkreten Quellcode
- Poste die Fehlermeldung die du hast.

Eine NPE zu debuggen ist super einfach, wenn man beides hat.

Das was du hier schreibst, erzeugt keine NPE. Du machst etwas falsch, was du hier nichts zeigst.

was bewirkt das this(); hier konkret? 🙂 Und welchen Konstruktor rufst du dann in der Main auf?

Bezüglich deines zweiten Satzes, weiß ich nicht, was du meinst. Aus dem Quellcode sollte klar sein, welcher Konstruktor aufgerufen wird.
 
Wie @Apple’s Jünger geschrieben hat, kann man nur raten.

Also ein typisches Problem wäre bei sowas:
Java:
public class SomeClass {
    List someList;
    
    public SomeClass() {
        List someList = new ArrayList();
    }
}

Du hast also nicht nur eine Zuweisung sondern durch den Typ eine lokale Variable deklariert.

Wichtig: Du wirst doch hoffentlich Java 8 oder neuer nutzen. List hat ein Generic und den sollte man immer angeben!

Andere Fehlersituationen sind deutlich seltener:

Java:
public class SomeClass {
    List<String> someList;
    String one = someList.get(1);
    public SomeClass() {
        List<String> someList = List.of("0", "1", "2", "3");
    }
}

Du greifst also darauf zu, ehe der Konstruktor gelaufen ist. (Das geht auch über Methoden und ganz blöd zu sehen bei Vererbungen, wenn der Konstruktor der Basisklasse eine Methode aufruft, die die abgeleitete Klasse überschreibt.)
 
Unabhängig von deinem konkreten Problem noch ein Hinweis: Du solltest keine "rohe" Liste verwenden, sondern einen generischen Typen angeben.

Anstatt von List list = new ArrayList(); besser etwas wie List<String> list = new ArrayList<String>(); (hier mit dem Typen "String"). Auf der rechten Seite kann die Typangabe auch weggelassen werden: List<String> list = new ArrayList<>();

Dadurch gewinnst du in deinem Programm Typsicherheit.

Sollte ich also automatisch immer eine neue ArrayList erzeugen lassen, wenn ein Objekt der Beispielklasse erzeuge

Meinst du damit, die Erzeugung der Liste, direkt bei der Instanzvariable?

Dein Konstruktor erzeugt ja ebenfalls eine Instanz der Liste und weist sie der Instanzvariablen zu. Es wird also in jedem Fall eine Instanz erzeugt, sobald eine Instanz der Beispielklasse erzeugt wird und das ist auch sinnvoll, sofern die Beispielklasse die Liste benötigt. Es kann auch Fälle geben, wo es sinnvoll ist, die Instanzvariable erst zu initialisieren, wenn sie auch tatsächlich benötigt wird. Das wäre z. B. der Fall, wenn die Erzeugung der Instanzvariablen "teuer" ist, also viel Zeit erfordert, weil Datenbankzugriffe notwendig sind, o.ä.

Java:
class Foo {
 
    private List<String> data = new ArrayList<>();
 
}

// gleichwertig

class Foo {
 
    private List<String> data;
 
    public Foo() {
        data = new ArrayList<>();
    }
}

// "verzögerte" Erzeugung der Liste, sog. "lazy initialization"

class Foo {
 
    private List<String> data;
 
    public void add(String value) {
        if (data == null) {
            data = new ArrayList<>();
        }
    
        data.add(value);
    }
 
}
 
Zuletzt bearbeitet:
Dachte das hätte ich aber das Problem hat sich anhand der Ausführungen hier dann erübrigt. Insbesondere das
Unabhängig von deinem konkreten Problem noch ein Hinweis: Du solltest keine "rohe" Liste verwenden, sondern einen generischen Typen angeben.

Anstatt von List list = new ArrayList(); besser etwas wie List<String> list = new ArrayList<String>(); (hier mit dem Typen "String"). Auf der rechten Seite kann die Typangabe auch weggelassen werden: List<String> list = new ArrayList<>();

(...)

Java:
class Foo {
 
    private List<String> data = new ArrayList<>();
 
}

// gleichwertig

class Foo {
 
    private List<String> data;
 
    public Foo() {
        data = new ArrayList<>();
    }
}

}
hatte ich nicht auf dem Schirm. Dann gab es ja eigentlich kein Problem, bis ich eines daraus machte.
Die Typisierung ist in meinem konkreten Fall zum Glück vorhanden 🙂

Danke euch!
 

Neue Themen


Zurück
Oben