# String equals null wird nicht angenommen.



## fuerchterBR (15. Sep 2009)

Hallo liebe Leute,
mein erster Post und auch schon direkt eine Frage.
Und zwar bin ich im moment ein klein wenig mit den Java-Basics am rumexperimentieren, und ich stehe momentan vor einem problem.
Und zwar habe ich im Verlauf meines Quelltextes die Variable egoeins (egozwei, egodrei,...), aus denen ich etwas schließen will, wenn die Variablen leer sind, dafür habe ich dann angenommen, egoeins (egozwei etc.) sei "null". Allerdings, wenn ich meinen Code so anwende, wie ich ihn hierunter posten werde, erhalte ich beim ausführen des Projekts eine Fehlermeldung.


```
import java.io.*;

/**
 * Write a description of class Text here.
 * 
 * @author fuerchterBR
 * @version 09-15-09 v0.001
 */
public class Text
{
    // instance variables - replace the example below with your own
public int leben;
public String eingabe;
public String name;
public String erzaehler;
public String antwortja;
public String antwortnein;
public String egoeins;
public String egozwei;
public String egodrei;
public String egovier;
public String egofuenf;
public String egosechs;
public String egosieben;
public String egoacht;
public String egoneun;
public String egozehn;
public String antworteins;
public String antwortzwei;
public String antwortdrei;
public String antwortvier;
public String antwortfuenf;
public String antwortsechs;
public String antwortsieben;
public String antwortacht;
public String antwortneun;
public String antwortzehn;
    /**
     * Constructor for objects of class Text
     */
    public Text()
    {
        startespiel();
     }
     //methoden
     //methode um das Spiel zu starten.
     public void startespiel(){
        leben=100;
        erzaehler="Sie wachen auf und sehen eine Kerze, die neben ihrem Bett steht.";
        erzaehlen();
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        erzaehler="/Wollen sie sie auspusten?";
        erzaehlen();
        antwortja="Sie pusten die Kerze aus und schlafen erneut ein. Das Spiel wird neu gestartet.";
        antwortnein="/Geben sie ihren Namen ein.";
        abfragejanein();
        abfragename();
        erzaehler="Herzlich Willkommen in diesem Textadventure, "+name;
        erzaehlen();
        erzaehler="Lasst uns die Geschichte weiter verfolgen!";
        erzaehlen();
        erzaehler="Sie stehen auf und bemerken die bäuerliche, aber auch mittelalterliche Dekoration, als ein Ritter das Zimmer betritt.";
        erzaehlen();
        erzaehler="'Steh auf und beweg dich, "+name;
        erzaehlen2();
        erzaehler="du dummer Alter Bauer!'";
        erzaehlen();
        erzaehler="/Antworten sie dem Ritter!";
        erzaehlen();
        erzaehler="Antwortmöglichkeiten:";
        erzaehlen2();
        erzaehler="____________________";
        erzaehlen2();
        erzaehler="1) Jawohl, mein Herr, ich bin bereit erneut zu dienen!";
        erzaehlen2();
        erzaehler="2) Jaja, ich komme ja schon, was mache ich hier überhaupt, und wieso werde ich als Bauer beschimpft?";
        erzaehlen2();
        erzaehler="3) Niemals, ich bleibe liegen, ich werde nicht für ein solch eitles Königreich dienen!";
        erzaehlen2();
        egoeins="Jawohl, mein Herr, ich bin bereit erneut zu dienen!";
        egozwei="Jaja, ich komme ja schon, was mache ich hier überhaupt, und wieso werde ich als Bauer beschimpft?";
        egodrei="Niemals, ich bleibe liegen, ich werde nicht für ein solch eitles Königreich dienen!";
        antworteins="'Komm mit mir!', sagt der Ritter.";
        antwortzwei="'Ich beschimpfe dich als Bauer, weil du einer bist, und jetzt komm!', sagt der Ritter.";
        antwortdrei="'Na gut, dann bleibst du halt liegen, dem König wird das garantiert nicht gefallen, wenn ich es ihm berichte!', sagt der Ritter.";
        abfrageeinszehn();
    }
     //erzaehlen-methode, die die Variable erzaehler in der console wiedergibt.
     public void erzaehlen(){
     System.out.println(""+erzaehler);
     try{
        Thread.sleep(4000);
     }
     catch (InterruptedException e){
     }
    }
     //erzaehlen-methode, die die Variable erzaehler in der console wiedergibt. (Ohne Pause)
     public void erzaehlen2(){
     System.out.println(""+erzaehler);
    }
     //ja/nein-abfrage mit vorher zu definierender Antwort.
     public void abfragejanein(){
         try{
            BufferedReader in = new BufferedReader(
            new InputStreamReader( System.in ) );
            eingabe = in.readLine();
        }
        catch(IOException ex ){
        System.out.println( ex.getMessage() );
    }
    if (eingabe.equals("Ja")){
        System.out.println(""+antwortja);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        startespiel();
    }
        
    else if (eingabe.equals("Nein")){
        System.out.println(""+antwortnein);
    }
    else{
            System.out.println("Falsche Eingabe!");
            abfragejanein();
        }
    }
    
    //abfrage die eine beliebige Eingabe erfordert.
     public void abfrage(){
         try{
            BufferedReader in = new BufferedReader(
            new InputStreamReader( System.in ) );
            eingabe = in.readLine();
        }
        catch(IOException ex ){
        System.out.println( ex.getMessage() );
    }
}
    //abfrage die den Namen erfordert.
     public void abfragename(){
         try{
            BufferedReader in = new BufferedReader(
            new InputStreamReader( System.in ) );
            name = in.readLine();
        }
        catch(IOException ex ){
        System.out.println( ex.getMessage() );
    }
}

    //abfrage die eine Antwort von 1-10 erwartet
     public void abfrageeinszehn(){
        try{
            BufferedReader in = new BufferedReader(
            new InputStreamReader( System.in ) );
            eingabe = in.readLine();
        }
        catch(IOException ex ){
        System.out.println( ex.getMessage() );
    }
    if (eingabe.equals("1")){
        System.out.println("-"+egoeins);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antworteins);
    }
        
    else if (eingabe.equals("2")){
        System.out.println("-"+egozwei);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortzwei);
    }
    else if (eingabe.equals("3")){
        System.out.println("-"+egodrei);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortdrei);
    }
    else if (eingabe.equals("4")){
        System.out.println("-"+egovier);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortvier);
    }
    else if (eingabe.equals("5")){
        System.out.println("-"+egofuenf);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortfuenf);
    }
    else if (eingabe.equals("6")){
        System.out.println("-"+egosechs);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortsechs);
    }
    else if (eingabe.equals("7")){
        System.out.println("-"+egosieben);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortsieben);
    }
    else if (eingabe.equals("8")){
        System.out.println("-"+egoacht);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortacht);
    }
    else if (eingabe.equals("9")){
        System.out.println("-"+egoneun);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortneun);
    }
    else if (eingabe.equals("10")){
        System.out.println("-"+egozehn);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortzehn);
    }
    else{
        System.out.println("Falsche Eingabe!");
        abfrageeinszehn();
        }
/**    if (egovier.equals("null")){
        System.out.println("Falsche Eingabe!");
        abfrageeinszehn();
    }   */
}
}
```

Wenn ich nun also an dem Punkt bin, an dem die Nummer zwischen 1 und 10 (egoeins-egozehn) abgefragt wird und ich die 4 (die nicht definiert ist, also "null" sein müsste), erhalte ich folgende Meldung (der Code, der die Problemstelle darstellt ist als comment im Quelltext ganz unten angehangen):
NullPointerException:
null

mfg fuerchterBR

//EDIT:
Und ja, falls die Frage kommen sollte, ich habe gegoogelt, aber die Ergebnisse waren entweder so formuliert, dass ich sie nicht verstehen konnte, oder sie behandelten nicht das richtige Problem.

//EDIT2:
Falls es helfen sollte, ich habe auch bereits probiert 
	
	
	
	





```
if (egovier.equals(""))
```
 zu schreiben, selbes Problem.


----------



## Landei (15. Sep 2009)

Wenn du irgend eine Methode an einer Referenz aufrufst, die gerade null ist, gibt es eine NPE


```
String x = "bla";
String y = null;
if(x.equals(y)) {} //<--OK
if(y.equals(x)) {} //<-- Boom!!!!
if(y != null && y.equals(x)) {} // <-- Ist immer sicher
if("irgendeineStringKonstante".equals(y)){} //Auch immer sicher
```

Das war ja genau der Grund, warum in Java7 die Null-sicheren Operatoren( ?. und ?: , a.k.a. "Elvis") eingeführt werden sollten (was sie inzwischen aber unverständlicherweise wieder rausgeschmissen haben)


----------



## Sanix (15. Sep 2009)

Wenn ein Objekt, in diesem FAll dein String null ist, kannst du keine Methoden davon aufrufen. Da das Objekt nicht existiert. Wenn du es auf null prüfen willst musst du 
[c]egovier == null[/c] prüfen. Dies bedeutet, dass kein String referenziert ist, was wohl in deinem Fall zutrifft.


----------



## maki (15. Sep 2009)

[c]null[/c] ist eine Null-Referenz, [c]"null"[/c] dagegen ist ein String.
Wenn du versuchst eine Null-Referenz zu dereferenzieren (zB.[c]null.irgendEineMethode()[/c]), gibt es eine NullPointerException.
Man kann sich einen Nullcheck sparen, indem man zB. die für null in Frage kommende Refrenz nicht dereferenziert: [c]"einString".equals(eineMöglicheNullReferenz)[/c]
Aber was du wohl brauchst sieht eher so aus: [c]if (null == egovier)[/c]

Respekt für den Mut solchen Code zu posten


----------



## fuerchterBR (15. Sep 2009)

Also muss ich egovier etc. extra definieren auf "nichts" oder ähnliches um dies abzufragen?

btw. danke für die schnelle Antwort.


----------



## Landei (15. Sep 2009)

Eine Referenz kann auf "gar nichts" zeigen. "Gar nichts" ist etwas ganz anderes, als ein leerer String (der immer noch ein String ist) und heißt in Java null (ohne Anführungszeichen). Es hat keine Methoden, die man aufrufen könnte, es fliegt einem immer um die Ohren. Bevor man etwas mit einer Referenz tut, die eventuell null ist, muss man das halt vorher testen (wie vom Vorredner beschrieben).

Null ist eine der dümmsten Ideen überhaupt in der IT (der "Erfinder" T. Hoare bezeichnete sie als seinen "Milliarden-Dollar-Fehler"), aber wir müssen in Java leider damit leben.


----------



## Spacerat (15. Sep 2009)

maki hat gesagt.:


> ...was du wohl brauchst sieht eher so aus: [c]if (null == egovier)[/c]


Öhm... Ich würd' 
	
	
	
	





```
if(egovier.equals("")) {
```
schlicht durch
	
	
	
	





```
if("".equals(egovier)) {
```
ersetzen (hat maki ja auch schon angedeutet). Und niemals vergessen:
	
	
	
	





```
definedObject.equals(undefinedObject);
```



maki hat gesagt.:


> Respekt für den Mut solchen Code zu posten


Dem schliess' ich mich an.


----------



## fuerchterBR (16. Sep 2009)

Okay, danke es funktioniert, ich habe aber dafür eine kleine Änderung gemacht, damit es funktioniert bzw. um den Code einfacher zu gestalten.


```
else if (eingabe.equals("4") & "".equals(egovier)){
        System.out.println("-"+egovier);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortvier);
    }
```

Wenn ich das nicht in die else if Bedingung reingeschrieben hätte, hätte er mir "-null" und "null" geprintet. 
Naja, danke auf jedenfall, hat mir sehr geholfen.

mfg fuerchterBR

//EDIT:
Ja, das ganze so in die einzelnen else if prozesse reinzuschreiben, wie ich es oben im Code schon gemacht habe (am Beispiel von egovier) lässt alle Antworten (1-10) die Antwort "Falsche Eingabe" bringen. Daraufhin ist mir aufgefallen, dass die Abfrage ja eigentlich sein muss "wenn die eingabe 1 ist und egoeins nicht null ist, dann gebe text aus". Naja, daraufhin noch einmal gegoogelt und den Code umgeändert in:


```
else if (eingabe.equals("4") & !"".equals(egovier)){
        System.out.println("-"+egovier);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortvier);
    }
```

Leider auch nicht erfolgreich, habe ich mich verlesen, oder stimmt das Ungleich mit dem Ausrufezeichen? Jedenfalls gibt mir die Konsole erneut die Antworten "-null" und "null", da ja nichts definiert ist (Es sollte eig. "Falsche Eingabe" (wie im else) kommen und das Eingabefeld wiederholt werden).

//EDIT2:

Habe jetzt einmal makis version probiert:


```
else if (eingabe.equals("4") & null != egovier){
        System.out.println("-"+egovier);
        try{
            Thread.sleep(4000);
        }
        catch (InterruptedException e){
        }
        System.out.println(""+antwortvier);
    }
```

Für egovier funktioniert diese Variante schon einmal, nun noch schnell bei dem Rest ausprobieren. Ok danke, funktioniert super, ich denke man kann das Thema jetzt schließen, habe vorerst keine weiteren Probleme.


----------



## SlaterB (16. Sep 2009)

Landei hat gesagt.:


> Null ist eine der dümmsten Ideen überhaupt in der IT (der "Erfinder" T. Hoare bezeichnete sie als seinen "Milliarden-Dollar-Fehler"), aber wir müssen in Java leider damit leben.


stimmt nicht, falls sich irgendjemand beeinflussen lassen sollte,
in der ernsthaften Diskussion darüber blieben fragliche Punkte von Landei unbeantwortet,
etwa
http://www.java-forum.org/allgemeine-java-themen/87667-java-7-auslese-3.html#post552931

ohne null wäre ein sinnvolles Programm nicht denkbar, von kleinen Code-Schnipseln und generell anderen Programmierstil (funktional) abgesehen


----------



## Landei (16. Sep 2009)

@fuerchterBR: Auch wenn es funktionert, bitte in Tests nicht & sondern && nehmen, weil das die rechte Seite nur dann auswertet, wenn es "nötig" ist

```
String s = null;
if(s != null & s.length() > 4) {} //BUMM!!!
if(s != null && s.length() > 4) {} //OK
```



SlaterB hat gesagt.:


> stimmt nicht, falls sich irgendjemand beeinflussen lassen sollte,
> in der ernsthaften Diskussion darüber blieben fragliche Punkte von Landei unbeantwortet,
> etwa
> http://www.java-forum.org/allgemeine-java-themen/87667-java-7-auslese-3.html#post552931
> ...



Ich bleibe bei meiner Meinung. Das Haskell usw. ohne null auskommen, liegt nicht am "funktionalen" Stil, denn wie man sieht, lässt sich die Option-Lösung ohne weiteres auf OO-Sprachen übertragen, es gibt aber auch andere Ansätze (Wikipedia nennt "Void safety, or static protection against calls on null references, through the attached-types mechanism." als Eigenschaft von Eiffel). Elvis-Operatoren u.s.w in vielen Sprachen (leider nicht in Java7) bekämpfen zwar nur die Symptome, zeigen aber, dass da etwas prinzipiell schiefläuft. Auch Sprachdesigner sind da meiner Meinung, etwa Bertrand Meyer: http://docs.eiffel.com/sites/default/files/void-safe-eiffel.pdf . Bei der Entwicklung neuerer Sprachen wird laut darüber nachgedacht, wie man null loswerden oder die Effekte zumindest eindämmen kann (in Fan kann man z.B. angeben, dass bestimmte Variablen oder Argumente nicht null sein dürfen).

Im übrigen ist es kein Problem, dass eine Variable zunächst "undefiniert" ist, solange der Compiler nachweisen kann, dass der erste Zugriff auf die Variable immer eine Zuweisung ist. Das ist insbesondere nützlich, wenn die Sprache eine "lazy"-Semantik unterstützt, also das Lazy Initialization Pattern ein Sprachbestandteil wird (womit viele Probleme mit der Initialisierungsreihenfolge wegfallen, wofür man sonst null benötigen würde). 

Null ist ein Krebsgeschwür, es ist ein Konzept, das mit Objektorientierung nicht vereinbar ist, denn die Kernaussage eines guten OO-Systems ist "Alles ist ein Objekt". Null ist ein Sonderfall, der überall berücksichtigt werden muss. Null ist eine Zeitbombe, die man hier in ein System wirft, und die einen halben Tag später dort mit einer NPE hochgeht. Mit einer leeren Liste einm Array der Länge 0 oder dem leeren String hat man keine Probleme, es sind Objekte und verhalten sich auch wie Objekte. Soll ich bei einer Suche, bei der nichts gefunden wurde, null zurückgeben? Sicher nicht, denn eine leere Liste drückt viel besser das Ergebnis der Suche aus, und eine nachfolgende for-Schleife ist überhaupt kein Problem. Warum soll das für andere Typen nicht auch gelten?


----------



## faetzminator (16. Sep 2009)

Dann nehmen wir als Beispiel einen Point. Soll er - falls "null" - x und y als 0,0 beschreiben? oder MIN_VALUE? In allen Fällen könnte der Wert auch vom Benutzer gesetzt sein. Man kann natürlich auch einen boolean hinzufügen, der bestimmt, ob der Point "null" ist. Aber da kann ich gleich gegen null checken!?


----------



## bygones (16. Sep 2009)

Natuerlich hat man bei ValueObjects (z.b. Point) immer eine Diskussion zwischen ungueltigen Zustand und bewusstem Zustand. D.h. ist Point(0,0) etwas anderes als ein ungueltiger Punkt. Ich wage zu behaupten dass dies nicht generell zu loesen ist sondern eben von Fall zu Fall zu unterscheiden ob in einer Applikation man 0 oder MIN/MAX Value nutzt

ansonsten auch siehe: Effective Java Item 43

Dennoch bin ich und bleibe ich ein absoluter Gegner von null.... is satan sozusagen ;-)


----------



## SlaterB (16. Sep 2009)

Landei hat gesagt.:


> Das Haskell usw. ohne null auskommen [..]


mit solch allgemeinen Aussagen kann ich leider nichts anfangen,
ich weiß nicht wie in Haskell ein JFrame oder 1000 andere Klasse mit 10.000 Klassenattributen definiert ist,

ob für jede Klasse manuell ein eigenes Null-Objekt definiert ist usw.


> Bei der Entwicklung neuerer Sprachen wird laut darüber nachgedacht, wie man null loswerden oder die Effekte zumindest eindämmen kann (in Fan kann man z.B. angeben, dass bestimmte Variablen oder Argumente nicht null sein dürfen).


ähm, ja, genau wie in Java: if (x == null) { throw Exception(); }

kürzere Syntax ist bisschen was anderes als 'null existiert nicht'?

falls der Compiler das automatisch beim Aufrufer prüft wäre man fast wieder bei 
'Variable darf man nicht null zuweisen'

das ist natürlich interessantes Konzept, bisher konntest du dich zu diesem Punkt noch nicht durchdringen



> Im übrigen ist es kein Problem, dass eine Variable zunächst "undefiniert" ist, solange der Compiler nachweisen kann, dass der erste Zugriff auf die Variable immer eine Zuweisung ist.


ok, da stehts ja doch,
und da ist wie gesagt meine Frage: zwingt einen eine solche Sprache, zu allen Klassen ein Null-Objekt anzulegen?
oder anderenfalls immer eine Exception zu werfen falls etwas nicht initialisiert wurde? 


> Null ist eine Zeitbombe, die man hier in ein System wirft, und die einen halben Tag später dort mit einer NPE hochgeht.


über etwas zu meckern ist leicht, aber ohne eine Alternative aufzuzeigen?
ich sehe keine andere Möglichkeit bzw. ich verweise auf diverse andere Probleme, die versteckte Standardwerte zur Folge haben



> Soll ich bei einer Suche, bei der nichts gefunden wurde, null zurückgeben? Sicher nicht, denn eine leere Liste drückt viel besser das Ergebnis der Suche aus, und eine nachfolgende for-Schleife ist überhaupt kein Problem. Warum soll das für andere Typen nicht auch gelten?


Container haben eine einfache feste Semantik,
ist leer? ja/ nein
get/ set/ iterate

selbst das wäre übrigens automatisch erstellt für einen Computer wohl nicht sinnvoll zu lösen sein,
der würde bei Standard-Rückgabewerten bei isEmpty() false zurückgeben und bei isNotEmpty() genauso -> Chaos

man muss also manuell eigene NULL-Objekte definieren,
und das ist ja schon länger meine Frage: zwingt die Sprache den Programmierer wirklich, zu jeder Klasse ein NULL-Objekt zu definieren?
für sich schon ungeheuerlich,
aber wenn, dann habe ich glaube ich noch paar weitere Punkte auf Lager,

ohne NULL-Objekt sehe ich noch weniger durch, wie das alles funktionieren soll

@faetzminator
> Aber da kann ich gleich gegen null checken!? 

nur dann wenn man muss, siehe EMPTY_LIST und Iterator, es gibt Fälle, in denen NULL-Objekte ganz natürlich ohne Check verwendet werden können,
nur nicht immer, ein Gegenbeispiel spricht nicht gegen das Pattern
aber es spricht dagegen, null in einer Sprache zu verbieten


----------



## bygones (16. Sep 2009)

ich hab so das Gefuehl NULL wird die neue Singleton diskussion ;-)

wenn das so weitergeht eroeffne ich einen Singleton thread

Edit: ich versteh nicht was alle mit "eigenen NULL Objekte" meinen ? man muss kein neues Objekt erzeugen, wie eine neue art von Collection... es ist einfach eine leere.


----------



## Landei (16. Sep 2009)

SlaterB hat gesagt.:


> mit solch allgemeinen Aussagen kann ich leider nichts anfangen,
> ich weiß nicht wie in Haskell ein JFrame oder 1000 andere Klasse mit 10.000 Klassenattributen definiert ist,


Haskell ist nicht objektorientiert, es hat Typen, aber keine Klassen im OO-Sinn.



> ob für jede Klasse manuell ein eigenes Null-Objekt definiert ist usw.


Wie oft muss ich das Option-Pattern noch erklären?



> ähm, ja, genau wie in Java: if (x == null) { throw Exception(); }
> 
> kürzere Syntax ist bisschen was anderes als 'null existiert nicht'?
> 
> ...


Es besteht ein großer Unterschied, ob ich in einer Methode alle Argumente mit x == null überprüfe, oder ob man schon an der Argumentliste, also der öffentlichen API, *sehen* kann, das null nicht erlaubt ist.




> ok, da stehts ja doch,
> und da ist wie gesagt meine Frage: zwingt einen eine solche Sprache, zu allen Klassen ein Null-Objekt anzulegen?
> oder anderenfalls immer eine Exception zu werfen falls etwas nicht initialisiert wurde?
> 
> ...


Eine mögliche Antwort heißt Option, eine generische Wrapperklasse, einmal definiert. Aber das hatten wir schon x-mal.



> Container haben eine einfache feste Semantik,
> ist leer? ja/ nein
> get/ set/ iterate
> 
> ...


Option, Option, Option

Lies doch bitte, bitte einfach mal Null ist keine Option…  eSCALAtion Blog

Ich weiß nicht, wie du auf die Idee kommst, dass du für jede Klasse einen eigenes Null-Objekt brauchst, wofür haben wir Generics?


----------



## SlaterB (16. Sep 2009)

bygones hat gesagt.:


> Edit: ich versteh nicht was alle mit "eigenen NULL Objekte" meinen ?



damit meine ich extra Code, ein spezielles selbst-programmiertes Sonder-Objekt, so wie


```
/**
     * The empty list (immutable).  This list is serializable.
     *
     * @see #emptyList()
     */
    public static final List EMPTY_LIST = new EmptyList();

    /**
     * Returns the empty list (immutable).  This list is serializable.
     *
     * <p>This example illustrates the type-safe way to obtain an empty list:
     * <pre>
     *     List&lt;String&gt; s = Collections.emptyList();
     * </pre>
     * Implementation note:  Implementations of this method need not
     * create a separate <tt>List</tt> object for each call.   Using this
     * method is likely to have comparable cost to using the like-named
     * field.  (Unlike this method, the field does not provide type safety.)
     *
     * @see #EMPTY_LIST
     * @since 1.5
     */
    public static final <T> List<T> emptyList() {
	return (List<T>) EMPTY_LIST;
    }

    /**
     * @serial include
     */
    private static class EmptyList
	extends AbstractList<Object>
	implements RandomAccess, Serializable {
	// use serialVersionUID from JDK 1.2.2 for interoperability
	private static final long serialVersionUID = 8842843931221139166L;

        public int size() {return 0;}

        public boolean contains(Object obj) {return false;}

        public Object get(int index) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }

        // Preserves singleton property
        private Object readResolve() {
            return EMPTY_LIST;
        }
    }
```
in java.util.Collections

für 10-100 einfache Klassen, die man überall braucht, ist das leicht, am besten sogar in der API vorgegeben,
aber bei jeder eigenen Person-Klasse, jedem ActionListener, jedem Hibernate-Proxy usw...


----------



## SlaterB (16. Sep 2009)

Landei hat gesagt.:


> Option, Option, Option
> 
> Lies doch bitte, bitte einfach mal Null ist keine Option…  eSCALAtion Blog
> 
> Ich weiß nicht, wie du auf die Idee kommst, dass du für jede Klasse einen eigenes Null-Objekt brauchst, wofür haben wir Generics?



das ist doch keine Alternative, man kann doch nicht jede einzelne Variable in einem Programm in Option umschreiben


```
class Person {
  String name;
  Adresse adresse;
  Person vater;
  Person mutter;
  ...
  evtl. getter/setter, vielleicht auch public-Zugriff
}
```
wie funktioniert das in echt, niemand will doch


```
class Person {
  Option<String> name = new Option();
  Option<Adresse> adresse = new Option();
  Option<Person> vater = new Option();
  Option<Person> mutter = new Option();
  ...
  evtl. getter/setter, vielleicht auch public-Zugriff
}
```
schreiben?

hast du vielleicht längere Code-Beispiele, wie programmierst du das in Scala?


----------



## maki (16. Sep 2009)

> ich hab so das Gefuehl NULL wird die neue Singleton diskussion
> 
> wenn das so weitergeht eroeffne ich einen Singleton thread


:shock:
:applaus:

Nach dem "S" wort nun auch das "N" Wort...


----------



## Landei (16. Sep 2009)

Ich schätze, dass in einem normalen Java-Programm höchstens 25% aller Variablen jemals mit null belegt werden. Wenn man etwas mehr darauf achtet, kann man diesen Wert wahrscheinlich auf 10% drücken.

Dass Option "unbequem" ist, liegt nicht am Konzept, sondern an der Umständlichkeit von Java (bessere Typinferenz in Java7 hilft schon etwas). Im Übrigen dient Option auch der *Dokumentation*: Es ist ein großes Warnschild, das diese Werte eben eventuell nicht initialisiert sind.

Ich denke, es ist auch nicht so wild, wenn lokale Variablen mit null hantieren und auf übliche Weise gegen null getestet werden, insbesondere wenn man es mit langatmigem Java zu tun hat. Das Problem wird ja es dadurch schlimm, dass Nullreferenzen zurückgegeben werden und als Argumente übergeben werden, also aus ihrem Kontext entkommen (ähnlich wie veränderliche Daten nicht unbedingt "böse" sind, aber eben auch so lokal wie möglich eingekastelt werden sollten).

[edit]
Vielleicht nicht das beste Beispiel (zu viele Dinge, die es in Java nicht gibt), aber z.B. hier
lazyEvaluation.scala | The Scala Programming Language

Es ist schon bezeichnend, dass ich Mühe hatte, auf der Scala-Seite _überhaupt_ ein Beispiel zu finden, was meine These untermauert, dass null oft nur ein Designfehler ist.
Eine typische Anwendung in Scala ist Map, wo die get-Methode eine Option zurückliefert. Es gibt aber z.B. auch eine alternative Methode getOrElse, bei der man (wie in Java bei Properties) einen Default-Wert angeben kann (oder eine Exception werfen).
In Scala arbeitet Option gut mit den restlichen Konstrukten zusammen und stört kaum. Eine Liste aus Options kann z.B. man mit "flatten" einfach zu einer Liste mit Werten machen (Nones werden weggeworfen)


----------



## SlaterB (16. Sep 2009)

Landei hat gesagt.:


> Ich denke, es ist auch nicht so wild, wenn lokale Variablen mit null hantieren und auf übliche Weise gegen null getestet werden,


wie kann das möglich sein, wenn null in einer Sprache verboten ist?!
wir drehen uns im Kreis


----------



## Landei (16. Sep 2009)

SlaterB hat gesagt.:


> wie kann das möglich sein, wenn null in einer Sprache verboten ist?!
> wir drehen uns im Kreis



Ich sprach über Java. Und wegen der Java-Kompatibilität ist auch in Scala null "erlaubt", wird aber in reinem Scala-Code normalerweise nicht verwendet (da Option gut "integriert" ist und einfach besser passt). Kein null haben z.B. Haskell und Self.


----------



## SlaterB (16. Sep 2009)

also mit EMPTY_LIST usw. ist das dann nicht mehr vergleichbar, das wurde nämlich schon oft genug bei 'null böse' genannt,

ich erinnere nur an die Diskussion um mein unsägliches Beispiel

```
Person x = db.ladePerson("tommy");
String y = x.getEhePartner().getVater().getGrabstein().getInschrift();
```
da ging es lange darum, dass doch am Ende ein String rauskommen soll, egal welches Objekt zwischendurch null ist,

Option hilft hier nicht weiter, korrekt?



--------

natürlich kann man 

```
Option<Person> x = db.ladePerson("tommy");
if (x.isEmpty()) {
return "";
} else {
..
}
```
verwenden,
aber das ist ja nicht viel anders als 


```
Person x = db.ladePerson("tommy");
if (x == null) {
return "";
} else {
..
}
```
es ist sicherer, es ist programmatisch sauberer vorgegeben, 
aber bitte, wer einen solchen Rückgabewert nicht selber vorher prüft..

das ist ja erschreckend unwichtig

getOrElse() kann man hier nicht nutzen, denn dann müsste man ein NULL-Objekt übergeben, wogegen wir uns ja zum Glück doch einig sind

```
Option<Person> x = db.ladePerson("tommy");
return x.getOrElse(Person.EMPTY_PERSON).get...;
```
über 4-5 Stufen mit Ehepartner, Grabstein usw. wäre das noch schlimmer,


also Option als Markierung, dass etwas null sein kann und der Test erforderlich ist,
das kann ich als ein seriöses Konzept akzeptieren, besonders sinnvoll ist das aber nicht,


hier und jetzt habe ich die Wahl das in mein zukünftigen Java-Programme einzubauen und mache es nicht,
genau wie prakisch keine Java-API, kein Java-Lehrbuch auf dieser Welt.., 

in einzelnen Fällen ist es nützlich, manche Maps oder einzelnen Methode habe ich bereits in meinen Programm

T getValue(String key, T defaulValue) // defaultValue wenn sonst null

um ein if abzukürzen, aber null ganz verbieten, nein



edit:
würde man null verbieten ginge gar nicht mehr das Feature


```
Person x = db.ladePerson("tommy");
String y = x?.getEhePartner()?.getVater()?.getGrabstein()?.getInschrift();
```
und nur mit Option kriegt man das ja nicht ähnlich hübsch hin, oder?
so gesehen wäre Option + kein null gar ein Rückschritt, würde diese tolle Syntax verhindern (sofern es sie in Java je geben wird  ) ?


----------



## Landei (16. Sep 2009)

Man kann Options ähnlich wie "Elvis" verwenden:

Scala:

```
val map = Map(1 -> Map(2 -> (Map(3 -> "X")))
val x = map.get(1).flatMap(_.get(2).flatMap(_.get(3)))
//--> x: Option[java.lang.String] = Some(X)
val y = map.get(4).flatMap(_.get(2).flatMap(_.get(3)))
//--> y: Option[java.lang.String] = None
```


----------



## SlaterB (16. Sep 2009)

stimmt, da kann man schon was drehen wenn Option ein SprachElement ist, dann kann man Abkürzungen einbauen,
dein Beispiel klingt etwas gefährlich, gilt das nur für Maps oder für beliebige Objekte?

geht
Option<Person> x = ..;
Option<String> y = x?.getVaterOption()?.getName()
?

naja, selbst wenn bisher nicht, könnte man es immer noch einbauen, denkbar wäre es


----------



## Landei (16. Sep 2009)

Für beliebige Objekte (flatMap ist eine Methode von Option). Ist natürlich in Java wegen der fehlenden Closures nicht wirklich attraktiv, aber ob man Elvis für null oder für Options (analog zu flatMap) definiert, bleibt sich eigentlich gleich.

Übrigens wird oft übersehen, dass die üblichen Nulltests ein kleines Problem haben:

```
public class NullTest {
  static String s = null;
  
  public static void main(String... args) throws InterruptedException {
     new Thread(){
       public void run() {
         while(true) {
           s = System.currentTimeMillis() % 2 == 0 ? null : "Hallo!";
         }
       }
     }.start();  
     
     while(true) {
       if(s != null) {
         Thread.sleep(1); //oder irgendwas anderes, was etwas Zeit braucht
         System.out.println(s.length());
       }
     }
  }
}
```


----------

