Monday, December 24, 2012

Frohe Weihnachten

Ich möchte allen Lesern meines Blogs ein besinnliches und frohes Weihnachtsfest wünschen. Wir sollten diesen Tag nützen, um uns im Kreise der Familie vom Weihnachtsstreß zu erholen und darüber nachzudenken was die wirklich wichtigen Dinge in unserm Leben sind. Das Christus vor über 2000 Jahren nicht in eine reiche Königsfamilie sondern in eine arme Handwerkerfamilie geboren wurde soll uns zum Nachdenken anregen, dass das Anhäufen von irdischen Gütern nicht der alleinige Zweck unseres Daseins sein kann.

Quelle Openclipart Library

Friday, December 14, 2012

"equal" vs "==" in Java

Ein typischer Anfängerfehler in Java ist, zwei Objekte in einer if Klausel mit "==" statt mit .equals() zu vergleichen. Dies ist aber in den meisten Fällen grundfalsch. Das tückische dabei ist, dass der Fehler nicht immer sofort auffällt, da unter manchen Umständen der Vergleich mit "==" auch funktioniert.

Um zu verstehen warum die beiden Vergleiche unterschiedlich sind, muss man zuerst wissen, wie Java eigentlich Objekte verwaltet. Wenn mit new ein neues Objekt erzeugt wird und einer Variable zugewiesen wird, wird nicht das Objekt in der Variable gespeichert, sondern das Objekt wird am Heap (Hauptspeicher) erzeugt und ein Zeiger auf die Stelle im Heap an der das Objekt gespeichert ist, wird der Variable zugewiesen. Man kann sich sozusagen die Variable als einen primitiven Datentyp vorstellen, der eine Referenz auf den Heap speichert. Mehrere Variablen können die selbe Referenz auf das selbe Objekt im Heap zugewiesen haben. Wenn nun mit "==" verglichen wird, wird das Objekt im Heap gar nicht angeschaut, sondern es wird nur verglichen, ob die Variable die gleiche Referenz enthält. Wenn ja wird true zurückgeliefert und wenn nein wird false zurückgeliefert. Ganz anders verhält es sich beim equals(). Hier müssen die Objekte nicht einmal vom gleichen Typ sein, sondern es kommt auf die Implementierung der "equals" Methode an, ob das Ergebnis true oder false ist. Im Normalfall wird man immer mit equals() vergleichen, da ich im Normalfall wissen will, ob es sich um ein logisch gleiches Objekt handelt und nicht um das selbe Objekt. Wenn alles so klar ist, warum funktioniert dann folgender Code:
String test1="Test";
String test2="Test";
System.out.println(test1==test2); //Bitte auf keinen Fall so machen
System.out.println(test1.equals(test2); //So vergleicht man richtig.
Im Normalfall würde man erwarten, da man zwei String Literale hat, dass der erste Vergleich false ergeben würde. Doch die JVM verwendet für Stringliterale einen Cache und so wird der zweite Literal wegoptimiert und beide Variablen verweisen auf das selbe Objekt im String Cache. Nur sollte man sich auf keinen Fall auf das verlassen, da eine andere JVM Implementierung auf diesen Cache eventuell verzichtet, oder der Cache bereits voll ist und dann hat man plötzlich zwei unterschiedliche Objekte und der erste Vergleich ergibt false.

Thursday, December 6, 2012

System.out Ausgaben in eine Datei umleiten

Manchmal hat man Java Programme, die statt einem Loggingframework alle Statusausgaben mit System.out.println() machen. Wenn nun so ein Programm während der Ausführung abstürzt hat man natürlich nicht mehr viel von den Statusmeldungen. Wenn ich so ein Javaprogramm habe, mache ich einfach eine kleine Wrapperklasse darum, mit der die Standardausgabe in eine Datei umgeleitet wird.

Ein kleines Beispiel:

public class LogginWrapper {
   /**
    * @param args
    */
    public static void main(String[] args) {
       // Leite die Ausgabe von Standard Out und ERR in Log Dateien um
 try {
   System.setOut(new PrintStream(new FileOutputStream(System.getenv("TEMP") 
  + File.separator + "$$log" + new Date().getTime() + ".out")));
   System.setErr(new PrintStream(new FileOutputStream(System.getenv("TEMP") 
  + File.separator + "$$log" + new Date().getTime() + ".err")));
 } catch (FileNotFoundException e) {
   e.printStackTrace();
        }  
      // Aufruf des Programms ohne Loggingframework.
  Test.main(args);
   }
}
Dann kann man einfach statt der Programmklasse die Wrapperklasse aufrufen und alle Ausgaben an Out und ERR werden in das Tempverzeichnis geschrieben. Im Fehlerfall hat man dann Anhaltspunkte was schiefgegangen ist.

Tuesday, December 4, 2012

Fehlerquelle beim Dividieren von BigDecimals in Java

Ich verwende bei Berechnungen sehr gerne die BigDecimal Klasse von Java. Da mit dieser beliebig große Zahlen und auch in beliebig großer Genauigekeit gerechnet werden können. Beim Dividieren bekommt man aber bei Berechnungen die zu keinem eindeutigen Ergebnis (z.B. 10/3) kommen die Exception "Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result." 

Deshalb sollte man bei Divisionen mit BigDecimal immer die Anzahl der gewünschten Dezimalen und den Rundungsmodus wie in der letzten Berechnung des kleinen Beispiels angeben.
 
public static void main(String[] args) {
 // Berechnung ergibt das endliche Ergebnis 0.5
 System.out.println(new BigDecimal(1).divide(new BigDecimal(2)));
 // Hier tritt eine ArithmeticException auf.
 System.out.println(new BigDecimal(10).divide(new BigDecimal(3)));
 // Berechnung ergibt 3.33 und wirft keine Exception, da wir die Anzahl
 // der Stellen beschränkt haben. Das Ergebnis ist aber natürlich nicht
 // 100% korrekt, aber in der Praxis bei für die Anwendung genügend
 // signifikante Stellen ausreichend.
 System.out.println(new BigDecimal(10).divide(new BigDecimal(3), 2, BigDecimal.ROUND_HALF_UP));
} 

Einen Notesagenten aus einem cmd script starten.

Im atnotes Forum wurde die Frage gestellt, wie man einen Notes agent aus einem cmd Befehlszeilenscript aufrufen kann. Über Befehlszeile oder über eine URL ist das relativ schwierig, da aber Lotus Notes sein API über COM anbietet ist es ein leichtes dass in einem vbscript zu implementieren. Dieses vbscript kann dann aus dem cmd script aufgerufen werden.

Dim s
Dim db
Dim agent
Set s=CreateObject("Lotus.NotesSession")
Call s.Initialize
Set db=s.GetDatabase("servername","db.nsf")
Set agent=db.GetAgent("agent")
Call agent.Run
servername, db.nsf und agent müssen natürlich angepasst werden.

Friday, November 30, 2012

Generische Collection in ein Array verwandeln.

Das Collectionsframework von Java ist vor allem seit der Einführung von Generics eine wirkliche tolle Sache. Aber leider hat man manchmal das Problem, dass man die Collection z.B. für die Übergabe an eine Funktion als Array benötigt. Dafür gibt es in der Collection Klasse die Methode toArray(). Bei nicht spezifizierten Collections funktioniert diese auch ziemlich einfach. Wenn man aber eine Collection mit einem bestimmten Typ hat, dann gibt toArray() auch ein Object Array zurück, was natürlich nicht verwendbar ist.

Ein kleines Beispiel wir haben eine List vom Typ String und möchten die Funktion test(String[]) aufrufen.

public class Test {
 public static void main(String[] args) {
  List<String> list = new ArrayList<String>();
  list.add("Test1");
  list.add("Test2");
  test(list.toArray());
 }
 private static void test(String[] test) {
  // mache irgendwas.
 }
}

Der Compiler wird folgenden Fehler ausgeben: "The method test(String[]) in the type Test is not applicable for the arguments (Object[])"

Nach längerer Suche im Internet habe ich herausgefunden, dass man ein leeres Array des Typs den die Collection hat als Parameter für toArray() übergeben muss, damit es funktioniert.

public class Test {
 public static void main(String[] args) {
  List<String> list = new ArrayList<String>();
  list.add("Test1");
  list.add("Test2");
  test(list.toArray(new String[0]));
 }
 private static void test(String[] test) {
  // mache irgendwas.
 }
}

Tuesday, November 27, 2012

Fork/Join Framework in Java 7

Auf Heise Developer wurde ein sehr interessanter Artikel über das mit Java 7 eingeführte Fork/Join Framework gepostet. Das Fork/Join Framework sieht sehr interessant aus, um komplexe Aufgaben in kleinere Tasks aufzuteilen und auf mehreren Prozessorcores gleichzeitig auszuführen. Leider wird Java 7 von Notes noch nicht unterstützt. Aber vielleicht ändert sich das ja mit Lotus Notes Social Edition.

Tuesday, November 13, 2012

Burnout in der IT Branche

Heise hat über eine Studie zum Thema "Burnout in der IT" die ich wirklich sehr interessant finde berichtet. Vor allem, dass die IT Branche eine höhere Gefährung als die Gesundheitsberufe haben soll, hätte ich so nicht erwartet.


ad