try-catch, call-by-reference, Streaming und Strings

Status
Nicht offen für weitere Antworten.

maxxi

Bekanntes Mitglied
Hello :meld:

ich habe mein erstes total kompliziertes Java-Programm fertig :applaus:

Aber da sind echt so viele neue, schwere Sachen, es hätte mich interessiert, ob ich das wirklich alles richtig gemacht haben. Im Programm habe ich:

- Threads
- Streaming
- ErrorHandling
- Sockets

Das ist das Programm:
Java:
import java.net.*; // Socket
import java.io.*;  // Input-/Output-Stream
public class Server
{  public static void man (String[] arrArg)
   {  try
      {  ServerSocket oSS=new ServerSocket(80); // Port; ev. IOException
         while(true)
         {  Socket oS=oSS.accept();             // blockiert; wartet auf Client; ev. IOException
            (new ServerThread(oS)).start();     // ruft ServerThread.run() auf; ev. IllegalThreadStateException
         }
      }
      catch(Exception oE)
      {  System.err.println(oE.toString());
      }
   }
}
class ServerThread extends Thread
{  private Socket _oS;
   public ServerThread(Socket oS)
   {  this._oS=oS;
   }
   public void run()
   {  StringBuffer oSB=new StringBuffer();
      try
      {  InputStream  oIS=this._oS.getInputStream();  // ev. IOException
         OutputStream oOS=this._oS.getOutputStream(); // ev. IOException
         int iC;
         while((iC=oIS.read())!=-1)                   // ev. IOException
            oSB.append((char)iC);
         oOS.write((oSB.toString()).getBytes());      // ev. IOException
      }
      catch(IOException oE)
      {  System.err.println(oE.toString());
      }
      try
      {  this._oS.close();                            // ev. IOException
      }
      catch(IOException oE)
      {  System.err.println(oE.toString());
      }
   }
}

Mich würden interessieren:

- Habe ich das richtig gemacht, dass ich close in ein eigenes try-catch gegeben habe? In meinem Buch ist das nämlich nicht so. Ich dachte, dass close auf jeden Fall ausgeführt werden muss, falls es davor im ServerThread irgendwelche Probleme gab. Könnte man das vielleicht noch irgendwie vereinfachen?

- ServerThread erhält das this._oS von Server. Server übergibt das oS als call-by-reference, ist das richtig? Wenn ich also im ServerThread ein this._oS.close(); ausführe, wird das oS im Server geschlossen, stimmt das?

- Im Server verwende ich ein catch(Exception oE). In meinem Buch steht catch(IOException oE). Das habe ich geändert, weil start() eine IllegalThreadStateException auslösen könnte. Ist das richtig, dass mein catch IOException und IllegalThreadStateException abfängt? Habe ich diesen catch richtig programmiert?

- Ist das OK, dass ich vor ServerThread kein public gesetzt habe? Was ist das dann eigentlich? protected? Nur innerhalb des eigenen Pakets sichtbar? Ich habe das so gemacht, weil ich die beiden Klassen in 1 Datei haben wollte. Ist das OK?

- Ist das Programm - ganz allgemein betrachtet - OK? Stil OK? Vielleicht noch irgendwelche Fehler oder sonst etwas, was ich noch machen sollte?

- Gibt es eigentlich eine Möglichkeit, wie ServerThread Fehler an Server melden kann? Wenn also in run eine Exception auftritt, dass diese an Server weitergeleitet wird und erst in Server die eigentliche Fehlerbehandlung durchgeführt wird?

Eure Meinung würde mich echt interessieren. Das ist mein erstes komplizierte Java-Programm 🙂
 
Zuletzt bearbeitet:
- Habe ich das richtig gemacht, dass ich close in ein eigenes try-catch gegeben habe? In meinem Buch ist das nämlich nicht so. Ich dachte, dass close auf jeden Fall ausgeführt werden muss, falls es davor im ServerThread irgendwelche Probleme gab. Könnte man das vielleicht noch irgendwie vereinfachen?
Grundsätzlich ist das richtig. Du solltest das close() aber in einem finally-Block schreiben, damit es auf jeden Fall ausgeführt wird. Warum schließt du den in-Stream nicht?

- ServerThread erhält das this._oS von Server. Server übergibt das oS als call-by-reference, ist das richtig? Wenn ich also im ServerThread ein this._oS.close(); ausführe, wird das oS im Server geschlossen, stimmt das?
Es gibt kein Call-by-Reference in Java. Du übergibst eine Referenz auf den (einzigen) Stream an die Methode.

- Im Server verwende ich ein catch(Exception oE). In meinem Buch steht catch(IOException oE). Das habe ich geändert, weil start() eine IllegalThreadStateException auslösen könnte. Ist das richtig, dass mein catch IOException und IllegalThreadStateException abfängt? Habe ich diesen catch richtig programmiert?
An solchen Stellen solltest du niemals alle Exceptions fangen. Immer nur die Exceptions, die auch geworfen werden können. Das ist zwar umständlich, wird mit Java 7 aber etwas vereinfacht.

- Ist das OK, dass ich vor ServerThread kein public gesetzt habe? Was ist das dann eigentlich? protected? Nur innerhalb des eigenen Pakets sichtbar? Ich habe das so gemacht, weil ich die beiden Klassen in 1 Datei haben wollte. Ist das OK?
Die Klasse ist nur innerhalb des Paketes sichtbar. Trotzdem sollte man jede Top-Level-Klasse in eine Datei speichern. Das dient der Übersicht. Für kleine Spielereien ist es aber OK so.

- Ist das Programm - ganz allgemein betrachtet - OK? Stil OK? Vielleicht noch irgendwelche Fehler oder sonst etwas, was ich noch machen sollte?
Dein Klammerungs-Stil ist ungewöhnlich. Die Variblen könntest du sprechender benennen. Unterstriche haben in Variablennamen nichts zu suchen.
 
Zuletzt bearbeitet:
Normalerweise (genauer gesagt, solange du nicht von mehreren Threads darauf zugreifst, was die absolute Ausnahme sein sollte) solltest du StringBuilder statt StringBuffer verwenden, was deutlich schneller ist.
 
Normalerweise (genauer gesagt, solange du nicht von mehreren Threads darauf zugreifst, was die absolute Ausnahme sein sollte) solltest du StringBuilder statt StringBuffer verwenden, was deutlich schneller ist.
Deutlich schneller? Kann ich mir nicht vorstellen. Hast du da einen Benchmark?
 
Deutlich schneller? Kann ich mir nicht vorstellen. Hast du da einen Benchmark?
synchronized gegen nicht synchronized... ergo schneller

ueber das Ausmass laesst sich natuerlich streiten... wir sprechen hier nicht von grossen O unterschieden


aber zb StringBuffer vs. StringBuilder performance comparison | Little Tutorials
So StringBuilder is faster by a good percentage (34% on my machine in this case) but remember that it is not thread safe

und doc:
This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
 
Zuletzt bearbeitet von einem Moderator:
wir sprechen hier nicht von grossen O unterschieden
Das will ich meinen. Synchronisation ist nicht mehr so teuer wie in der Vergangenheit. Außerdem könnte ein JIT die wegoptimieren, wenn bewiesen ist, dass das Objekt nur lokal verwendet wird.
Aber grundsätzlich sollte man natürlich den Builder bevorzugen.
 
Wow, das waren schon mal mächtig viele Infos 🙂
Grundsätzlich ist das richtig. Du solltest das close() aber in einem finally-Block schreiben, damit es auf jeden Fall ausgeführt wird.
Mal 2 Beispiele:
Beispiel 1:
Java:
try
{  throw new Exception();
}
catch(Exception oE)
{  System.out.print("error");
}
System.out.print("ende");
Beispiel 2:
Java:
try
{  throw new Exception();
}
catch(Exception oE)
{  System.out.print("error");
}
finally
{  System.out.print("ende");
}
Wo liegt denn der Unterschied? "ende" wird doch in beiden Beispielen (egal ob mit oder ohne Exception) immer ausgegeben, oder?
Warum schließt du den in-Stream nicht?
Das geht? Wird in keinem einzigen Beispiel in meinem Buch gemacht. Hm ... muss ich noch nachforschen.
Dann muss ich doch den out-Stream auch schließen, oder?
An solchen Stellen solltest du niemals alle Exceptions fangen. Immer nur die Exceptions, die auch geworfen werden können.
Worin liegt denn der Vorteil, wenn ich die Exceptions alle extra abfange? Ist doch - speziell bei großen Programmen - ein ziemlicher Programmieraufwand, oder?
Das ist zwar umständlich, wird mit Java 7 aber etwas vereinfacht.
In Java 7 verändert sich das Verhalten beim try-catch-finally?
Dein Klammerungs-Stil ist ungewöhnlich.
Mit gefällt der, weil { und } immer untereinander stehen. Sollte das { irgendwo gaaaanz rechts stehen, wo ich scrollen muss, um es zu sehen, finde ich das nicht so schön übersichtlich 🙂
Unterstriche haben in Variablennamen nichts zu suchen.
Das mache ich, um schon anhand des Namens private/protected-Methoden/Eigenschaften von public Methoden/Eigenschaften unterscheiden zu können. Könnte es damit Probleme geben?
that it is not thread safe
Darauf habe ich noch überhaupt nicht geachtet. Stimmt das, dass ich in ServerThread nur Sachen verwenden darf, die thread-sicher sind? Wie erkenne ich denn, welche Methode oder Eigenschaften von welchen Klassen das sind??
 
Wo liegt denn der Unterschied? "ende" wird doch in beiden Beispielen (egal ob mit oder ohne Exception) immer ausgegeben, oder?
bei einem finally ist gewaehrleistet dass der code auf alle faelle ausgefuehrt wird bevor die methode verlassen wird (egal ob ueber return oder ein fehler)... in deinem bsp macht dies keinen unterschied

Das geht? Wird in keinem einzigen Beispiel in meinem Buch gemacht. Hm ... muss ich noch nachforschen.
Dann muss ich doch den out-Stream auch schließen, oder?
jeden stream sollte man schliessen

Das mache ich, um schon anhand des Namens private/protected-Methoden/Eigenschaften von public Methoden/Eigenschaften unterscheiden zu können. Könnte es damit Probleme geben?
ich sehe es nicht so besorgniserregend an wenn eine Variable mit _ beginnt... wenn man mit einer IDE arbeitet kann man sich alle moeglichen kombinationen farblich markieren, um unterscheiden zu koennen.
Probleme gibt es auf alle faelle nicht, es ist eine Geschmackssache.
 
Worin liegt denn der Vorteil, wenn ich die Exceptions alle extra abfange? Ist doch - speziell bei großen Programmen - ein ziemlicher Programmieraufwand, oder?
Exceptions fängt man eigentlich nur dann ab, wenn man sie auch behandelt. In deinem Beispiel gibt's du sie ja einfach nur aus. Also macht es hier keinen Unterschied.
In Java 7 verändert sich das Verhalten beim try-catch-finally?
In Java 7 kann man in einer catch-Klausel mehrere unterschiedliche Exceptions fangen.

Das mache ich, um schon anhand des Namens private/protected-Methoden/Eigenschaften von public Methoden/Eigenschaften unterscheiden zu können. Könnte es damit Probleme geben?
Wie gesagt, es ist eine Stil-Frage. Ich finde, es ist schwer zu schreiben und schwer zu lesen und hat dabei keinen richtigen Vorteil.

Darauf habe ich noch überhaupt nicht geachtet. Stimmt das, dass ich in ServerThread nur Sachen verwenden darf, die thread-sicher sind? Wie erkenne ich denn, welche Methode oder Eigenschaften von welchen Klassen das sind??
In deinem Beispiel verwendest du den StringBuffer nur lokal in einer Methode. Andere Threads können den gar nicht sehen. Also braucht man hier keine Threadsicherheit und kannst StringBuilder verwenden.
 
Jetzt habe ich noch 3 close eingebaut:
Java:
import java.net.*; // Socket
import java.io.*;  // Input-/Output-Stream
public class Server
{  public static void man (String[] arrArg)
   {  try
      {  ServerSocket oSS=new ServerSocket(80); // Port; ev. IOException
         try
         {  while(true)
            {  Socket oS=oSS.accept();          // blockiert; wartet auf Client; ev. IOException
               (new ServerThread(oS)).start();  // ruft ServerThread.run() auf; ev. IllegalThreadStateException
            }
         }
         catch(Exception oE)
         {  System.err.println(oE.toString());
         }
         oSS.close();
      }
      catch(Exception oE)
      {  System.err.println(oE.toString());
      }
   }
}
class ServerThread extends Thread
{  private Socket _oS;
   public ServerThread(Socket oS)
   {  this._oS=oS;
   }
   public void run()
   {  StringBuffer oSB=new StringBuffer();
      try
      {  InputStream oIS=this._oS.getInputStream();      // ev. IOException
         try
         {  OutputStream oOS=this._oS.getOutputStream(); // ev. IOException
            try
            {  int iC;
               while((iC=oIS.read())!=-1)                // ev. IOException
                  oSB.append((char)iC);
               oOS.write((oSB.toString()).getBytes());   // ev. IOException
            }
            catch(IOException oE)
            {  System.err.println(oE.toString());
            }
            oOS.close();
         }
         catch(IOException oE)
         {  System.err.println(oE.toString());
         }
         oIS.close();
      }
      catch(IOException oE)
      {  System.err.println(oE.toString());
      }
      try
      {  this._oS.close();                               // ev. IOException
      }
      catch(IOException oE)
      {  System.err.println(oE.toString());
      }
   }
}
Jetzt habe ich mächtig viele try-catch. Geht das noch irgendwie einfacher?

Aber 2 Fragen sind jetzt noch übriggeblieben:
- Wie erkenne ich, was in Java threadsicher ist?
- Kann ich im run Exception irgendwie an Server weiterreichen?
 
Zuletzt bearbeitet:
Das mache ich, um schon anhand des Namens private/protected-Methoden/Eigenschaften von public Methoden/Eigenschaften unterscheiden zu können. Könnte es damit Probleme geben?
Probleme nicht, ist halt nur komisch zu lesen...

Darauf habe ich noch überhaupt nicht geachtet. Stimmt das, dass ich in ServerThread nur Sachen verwenden darf, die thread-sicher sind? Wie erkenne ich denn, welche Methode oder Eigenschaften von welchen Klassen das sind??
Du darfst in threads auch dinge verwenden die nicht thread-safe sind, aber da kannst du inkonsistente Daten erhalten und viele andere schöne Dinge...

Beispiel:
Ein Thread soll von einem Objekt eine Variable erhöhen->
Java:
public class ObjektIncrement{
 private int zahl=0;
 public void inc(){
  zahl = zahl+1;
 }
}
Java:
public class AddThread implements Runnable{
 private ObjektIncrement o;
 public AddThread(ObjektIncrement o){
  this.o=o;
 }
 public void run(){
  for(int i=0;i<500;i++){
   o.inc();
  }
 }
 public static void main(String[] args){
  ObjektIncrement o = new ObjektIncrement;
  new Thread(AddThread(o).start());
  new Thread(AddThread(o).start());
 }
}

inc() kann man ja aufschlüsseln zu:
Java:
 int r=zahl;
 r++;
 zahl=r;
Nach jeder Anweisung kann nun ein anderer Thread an die Reihe kommen!
Was passiert nun wenn zwei Threads bei o inc() aufrufen?
3 Fälle, erst wird ein Thread abgearbeitet, dann der andere, die 2 Fälle sind ok so.
Der letzte Fall hat aber ein Problem:
Nebenläufig:
Java:
Thread1:
r1 = zahl //zahl ist 0, also r1=0
r++;
Thread2:
r2 = zahl //zahl ist immer noch 0, also r2=0  
Thread1:
zahl=r1 //r1=1, also zahl=1
//Thread 1 fertig.
Thread2:
r2++ //r2=1
zahl=r2; //r2=1, zahl=1

Zum Schluss wurde zweimal inc() aufgerufen, aber zahl hat sich nur um 1 erhöht.

Aber bei deinem Thread ist das soweit noch kein Problem...
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben