Deutsch
Springe zu
Dein Feedback:
Hat die Seite Deine Erwartung erfüllt? vote3 Ja
vote2 Teilweise
vote1 Nein
Noch ein Kommentar?

Nur falls, Du eine Antwort erwartest, Deine E-Mailadresse

Gegebenenfalls noch Dein Name

Do not change this:
Feedback
Suchen

Java

07-04-2010 00.12

Links und Literatur


Java Aufruf

Java mit mehr Speicher starten

java -Xmx512m

Bestimmte Java Version erzwingen

java -version:1.4

Java Programm compilieren und ausführen

Achtung, das Trennzeichen unter Windows ist nicht ":" sondern ";".

So erzeugt man aus einer .java Datei eine .class Datei
javac -classpath "foo/bar.jar:foo/tests.jar:../foo.jar" MyClass.java
Dabei muss man alle jar Dateien angeben, die direkt von der Klasse genutzt werden (also nicht die, die nur von Klassen genutzt werden, die wir aufrufen).

So erzeugt man jar Dateien
jar cf MyJar.jar MyClass.java
Siehe auch die JAR Dateien erzeugen Anleitung.

So führt man das Java Programm dann aus (jetzt muss man wirklich all jars auflisten die zur Ausführung gebraucht werden)
# java -classpath "foo/bar.jar:foo/tests.jar:../foo.jar:../misc.jar" MyClass

Java debuggen

So kann man auf einem entfernten Rechner Java so starten, dass es im lokalen Debugger untersucht werden kann
java -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n ...
Dabei sorgt
suspend=y
dafür, dass das Programm erst losläuft, wenn der Debugger verbunden ist.
Um den Debugger einzurichten, in Eclipse
open debug digalog
remote java application
new
Rechnername und Port des Java Programms

Kleines Beispiel

Ein Interface, darf nur abstrakte Methoden und Konstanten enthalten
/**
* My Interface
*/
package mypackage;

/**
* @author John Doe
*
*/
public interface MyInterface
{

/**
* @param number The number which is added
* @return The new sum
*/
public double add(final int number);

/**
* The limit for the result after the mathematical operations
*/
final static double maxValue=10000;
}
Eine abtrakte Klasse, enthält mindestens eine abstrakte Methode
/**
* An abstract class which will be used for things which are
* not allowed in an Interface
*/package mypackage;

/**
* @author John Doe
*
*/
public abstract class MyAbstractClass
{

/**
* Constructor
*/
public MyAbstractClass()
{
this.value=0;
}

/**
* This is the current value which will be modified by the
* mathematical operations which are offered
*/
protected double value;

}
Eine normale Klasse, darf höchsten von einer anderen Klasse erben, aber von beliebig vielen Interfaces implementieren.
/**
* This class shows that you can implement multiple Interfaces
*/
package mypackage;

/**
* @author John Doe
*
*/
public class MyClass extends MyAbstractClass
implements MyInterface, MyOtherInterface
{

/* (non-Javadoc)
* @see mypackage.MyInterface#add(int)
*/
public double add(final int number)
{
System.out.println("The maxvalue is " + AdderInterface.maxValue);
double res=this.value+=number;
this.value=res;
return res;
}
}


Variablen

TypeGrößeVon bis
boolean1
char2
byte1-128...127
short2-32768...32767
int4-2147483648 ... 2147483647
long8-9223372036854775808...9223372036854775807
float41,40239846 * 10^-45 ... 3,40282347 * 10^38
double84,94065645841246544 * 10^-324 ... 1,79769131486231570 * 10^308

Autoboxing

int i     = 4711;
Integer j = i; // j = Integer.valueOf(i)
int k = j; // k = j.intValue()

instanceof

String str = "HELLO WORLD";
b = ( str instanceof String ); // (1)
b = ( str instanceof Object ); // (2)
b = ( str instanceof Foo ); // (3)

(1) und (2) sind beide wahr, (3) nicht

Gleichheit

int x,y;
Foo a, b;

x==y // (1)

a==b // (2)

a.equals(b); (3)

(1) Bei Basistypen ein normaler Test auf Gleichheit
(2) Ansonsten Test ob beides eine Referenz auf das gleiche Objekt ist
(3) Inhaltliche Gleichheit mit equals() testen

Wenn man equals nicht selbst implementiert sieht es so aus:
und equals selbst implementieren, default ist das:

public boolean equals( Object obj ) 
{
return ( this == obj );
}

Eine mögliche Implementierung:
public boolean equals( Object obj ) 
{
if ( obj instanceof Foo ) {
Foo tmp = (Foo) obj;
return (bar == tmp.bar)
}
return super.equals( obj );
}

Als Parameter aber Object erwarten und nicht die Klasse für die die Methode gedacht ist. Also nicht:
//public boolean equals(Foo fooObj) {...};

Achtung, wenn man equals ändert, darauf achten, dass aus a.equals(b) auch a.hashcode()==b.hashcode() folgen muss (umgekehrt aber nicht).
Eclipse kann für equals() und hashcode() sinnvolle Vorschläge machen.

Achtung, die Reihenfolge beim equals() Vergleich ist z.B. dann relevant, wenn einer der beiden Objekte null werden kann.
Ist z.B. a potentiell null, b hingegen nicht, kann man das equals von a natürlich nicht aufrufen
// a.equals(b);
b.equals(a);
Können beide null sein, diesen Fall vorher extra abfangen (sonst gibt es eine Exception wenn versucht wird equals auf null aufzurufen).

Conditional Expressions

Kurzschreibweise für bedingte Zuweisung
//if(ungerade) max=l; else max=l-1;
int max=(ungerade) ? l : l-1;

Kurzschlußoperatoren

boolean b1 = true || foo(); // (1)
boolean b2 = true | foo(); // (2)
boolean b3 = false & foo(); // (3)
(1) foo() wird nicht aufgerufen
(2) foo() wird aufgerufen
(3) foo() wird aufgerufen

Arrays

int i[];   // == int [] i;
Foo[] x;

int i[][]; // == int [][] i == int[] i[]
int[] i, x[], y; // == int [] i; int [][]x; int[] y;

int[] prim = { 5, 7, 7 + 4, };

Array mit vorgegebener Größe:
// int hundredElements[ 100 ];  <-- ERROR
int[] hundredElements;
hunderdElements = new int[ 100 ];

int[] prim;
prim = new int[]{ 5, 7, 11, };

Arraygröße

System.out.println( hunderedElements.length );

Mehrdimensionale Arrays

Rechteckiges Array
int i[][]=new int[3][4];

Beliebiges mehrdimensionales Array
int i[][]=new int[3][];
i[0]=new int[7];
i[1]=new int[19];
i[2]=new int[2];
i[3]=new int[100];

Anonyme Arrays

foo( new double[]{ 1.1, 2,5, 3.2 } );

Arrays durchlaufen


double sum = 0;
double[] myarray;
List<Double> mylist=new LinkedList<Double>();

// (1)
for ( int i = 0; i < myarray.length; i++ )
{
sum += myarray[i];
}

// (1b)
for ( double n : mylist )
{
sum += n;
}

// (2)
for (ListIterator<Double> i = mylist.listIterator(); i.hasNext(); )
{
sum+=i.next();
}

// (2b)
for ( double n : myarray )
{
sum += n;
}
(1) Normaler Array Durchlauf
(1b) Kurzschreibweise für (1)
(2) Durchlauf eines Containers mit einem Iterator
(2b) Kurzschreibweise für (2). Man verliert aber den Vorteil gegebenfalls einen Iterator zur Hand zu haben (z.B. zum Löschen von Elementen).

Unnötige Methodenaufrufe in for Schleifen sparen
Häufig sehen for Schleifen so aus
for(int a=0; a<getMaxA(); a++)
Wenn sich der Rückgabewerte der Methode aber für die Dauer des Schleifendurchlaufes nicht ändert und die Methode eine nennenswerte Laufzeit hat, kann man die Schleife über eine weitere Variable deutlich beschleunigen
for(int a, int b=getMaxFoo();
a<b;
a++);

Teile eines Arrays in einen anderen Array oder in sich selbst kopieren

static void arraycopy( Object src, int srcPos, Object dest, int destPos, int length );

int[] y = Arrays.copyOfRange( x, 6, 9 );

Einen Array in einen Vector wandeln

So kann man einen String Array in einen String Vector wandeln
String [] myArray;
...
Vector<String> myVector = new Vector<String>(Arrays.asList(myArray));

Array Vergleichen

Arrays.equals( a1, a2 ) );   // (1)
Arrays.deepEquals( a1, a2 ); // (2)
// (1) Referenzen der Elemente im Array müssen gleich sein
// (2) Inhalt muss gleich sein // (2)

Undefinierte Parameter Anzahl

Methoden können eine undefinierte Anzahl an Parametern erwarten, ansprechbar wie ein Array
int max( int... x)
{
System.out.println(x.lenght);
}

Clone

Foo x,y;
x=new Foo();
y=x.clone();
Flache Kopie von Objekten erzeugen:


Überdeckte Namen

void foo(int x)
{
x = 12; // (1)
this.x = 12; // (2)
this.x=x;
}

(1) Zuweisung an lokale Variable x
(2) Zuweisung an Objektvariable x

enum

public enum Weekday
{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

Der Zugriff erfolgt so:
Weekday.MONDAY

In den case Statements einer switch Anweisung dagegen so:
MONDAY

Über Enums kann man iterieren
for (Tag tag:Weekday.values()) { }

Override

Optional erklären dass man eine Methode des Vaters überschreibt (Fehler falls nicht)
@Override
public void foo( int alter )

Konstruktor

Anderen Konstruktor der eigenen Klasse aufrufen
this(5);
muss die erste Anweisung des Konstruktors sein, keine Objektvariablen übergebbar

Wenn man eine Klasse hat, von der es nur wenige Ausprägungen gibt, wie z.B. Boolean.
Dann macht es oft keinen Sinn, dass man mit new beliebig viele verschiedene Objekte dieser Klasse erzeugen kann. Eine besser Variante ist es dann, statt einem Konstruktor eine valueOf() Methode anzubieten
public static valueOf(boolean b)

Diese liefert dann immer wieder die wenigen Objekte zurück die es geben kann, hier z.B. entweder Boolean.TRUE oder Boolean.FALSE. Es darf dann natürlich keine Methode geben, ob den Wert eines solchen Objektes zu verändern, weil sonst auch alle anderen Nutzer dieses Objektes davon betroffen wären.

Exemplarinitialisierern

Initialisieren von Variablen in allen Konstruktoren
class Foo
{
int j=1; // (1)

Foo()
{
this.k=0;
}

Foo( int i )
{
this.k = j;
}
}

entspricht
class Foo
{
int j; // (1)

Foo()
{
this.j=1; // (1)
this.k=0;
}
Foo( int i )
{
this.j = 1; // (1)
this.k = i;
}
}

Bei statischen Variablen
public class Foo
{
static int x = 2;
}

entspricht

public class InitStaticVariable 
{
static int x;
static
{
x = 2;
}
}


Super

Konstruktor des Vaters aufrufen
super(5);

Methode des Vaters aufrufen
@Override
public void foo( int alter ) {
super.foo();
...
}


final

Variable nicht änderbar (wohl aber Methoden aufrufbar die sie ändern)
final int x=3;
final Foo y=new Foo();
y.reset();

Erben nicht möglich
final class Bar
{
// ...
}

Überschreiben nicht möglich
class Foo
{
final void bar();
}


Innere Klassen

Siehe auch Innere Klassen in Java mehr als eine Insel
class Foo
{
class Bar
{
}
}
Zum Erzeugen eines Objekts der inneren Klasse, braucht man ein Objekt der äußeren Klasse (Ausnahme statische innere Klassen). Versucht man z.B. in einer statischen Methode der äußeren Klasse ein Objekt der inneren Klasse zu erzeugen würde das fehlschlagen
No enclosing instance of type foo is accessible. Must qualify the allocation with an enclosing instance of type foo (e.g. x.new Bar() where x is an instance of foo).
Nur innere Klassen dürfen Private oder Protected sein. Wenn sie es sind, hat es Einfluss darauf, wer sie benutzen darf.

Statische Klasse

Statische Klassen werden auch nested top-level class genannt. Sie benötigen kein Exemplare der äußeren Klasse, um erzeugt zu werden.
Eine statische Klasse kann auf alle statischen Attribute und Methoden der umgebenden Klasse zugreifen. Auf nicht statische Attribute oder Methoden hingegen ist kein direkter Zugriff möglich.
public class Foo
{
static String s = "HELLO WORLD";
int i = 1;

static class Bar
{
void test()
{
System.out.println(s);
// System.out.println( i ); // (1)
}
}
}


Mitglieds- oder Elementklassen

Auch member class genannt. Kann auch alle Attribute (inklusiver privater) der äußeren Klasse zugreifen. Allerdings benötigt man ein Exemplar der äußeren Klasse, um ein Exemplar der inneren Klasse von außen zu erzeugen.
public class Foo
{
String s = "Hello World";

class Bar
{
void test1()
{
System.out.println( s );
}

//static void test2() { } // (2)
}
}

Von aussen erzeugen
Foo a = new Foo();
Bar b = a.new Bar();

Die Mitgliedsklasse darf selbst keine statischen Attribute oder Methoden haben.

Lokale Klassen

Klassen, die innerhalb von Methoden der äußeren Klasse definiert werden. Die lokalen Klassen können auf die Methoden der äußeren Klassen zugreifen und auf deren Elemente, die mit final markiert sind. Wird die lokale Klasse in einer static Methode definiert ist ein Zugriff auf nicht statische Elemente und Methoden hingegen nicht möglich.
public class Foo
{
public static void main( String[] args )
{
int i = 1;
final int j = 2;

class Bar
{
Bar() {
System.out.println( j );
//System.out.println( i ); // (3) Fehler, da i nicht final
}
}
new Bar();
}
}

Anonyme innere Klassen

Anonyme innere Klassen erben entweder von einer anderen Klasse oder implementieren eine Schnittstelle
class Foo()
{
// ...
}

interface Bar()
{
// ...
}

class Blub{}
{
new Foo()
{
...
}
new Bar()
{
...
}
}

Generische Datentypen / Generics

class Foo<T>
{
private T val;

void setValue( T val )
{
this.val = val;
}

T getValue()
{
return val;
}
}

Foo<String> stringFoo = new Foo<String>();
Foo<Integer> intFoo = new Foo<Integer>();
Foo<Point> pointFoo = new Foo<Point>();

class Bar
{
public static <T extends Number> T myMethod( T a, T b, HashMap<T, String> )
{
//...
}
}

So kann man von einer generischen Klasse erben, ohne deren generischen Typ weiter einzuschränken.
public class Bar<T> extends Foo<T> { ... }

Macht man das falsch erhält man oft diesen Fehler
A supertype may not specify any wildcard

Manchmal will man den Typen dabei aber auch weiter einschränken. Hier ein Beispiel wie es geht.
Angenommen man hat eine einfache Klassenhierarchie, z.B. verschiedene Hunde
public class Dog
{
public void bark()
{
System.out.println("Wuff!");
}
}

public class Poodle extends Dog
{

public void barkLikeAPoddle()
{
System.out.println("Wuff, Wuff!");
}
}

public class FrenchPoodle extends Poodle
{
public void barkLikeAFrenchPoddle()
{
System.out.println("Wüff, Wüff!");
}
}

Und jetzt möchte man parallel dazu eine weitere Klassenhierarchie haben. Diese neue Hierarchie soll jetzt mit der ersten verbunden werden. Bestimmte Stufen der neuen Hierarchie arbeiten nur mit bestimmten Klassen der ersten Hierarchie zusammen. Eine Möglichkeit das abzubilden sind Generics. Zum Beispiel soll es jetzt verschiedene Hundehütten geben, die nur bestimmte Hunde akzeptieren.
public class DogHouse<T extends Dog>
{
protected T dogInTheHouse;

public void wakeTheDog()
{
this.dogInTheHouse.bark();
}
}

Trickreich sind hier die Zwischenklassen, die bereits von einer anderen Klasse mit Einschränkung auf den Typ erben, sich aber auf den Typ noch nicht final festlegen. Besondern schwierig ist es, in einer solchen Zwischenklasse neue Objekte des eingebetteten Typs zu erzeugen, weil die Klasse nie wissen kann, für welchen Typ sie später benutzt wird.
public class DogHouseForAPoodle<T extends Poodle> extends DogHouse<T>
{
public void wakeTheDog()
{
this.dogInTheHouse.bark();
this.dogInTheHouse.barkLikeAPoddle();
}

public void assignementIsEasy(T newDog)
{
this.dogInTheHouse=newDog;
}

/*
public void butCreationIsTricky()
{
this.dogInTheHouse=new Dog(); // Fails because T might be Poodle
this.dogInTheHouse=new Poodle(); // Fails because T might be FrenchPoodle
this.dogInTheHouse=new FrenchPoodle(); // Fails because T might be something which also extends Poodle
}
*/
}

Das ist wieder leicht:
public class DogHouseForAFrenchPoodle extends DogHouseForAPoodle<FrenchPoodle>
{
public void wakeTheDog()
{
this.dogInTheHouse.bark();
this.dogInTheHouse.barkLikeAPoddle();
this.dogInTheHouse.barkLikeAFrenchPoddle();
}
}

Javadoc

/**
* @see Bar
* @link Bar
* @version 1.01
* @author John Doe
* @param x A number
* @param y Another number
* @return This method always returns 5
* @exception NumberFormatException
* @throws NumberFormatException
* @category Setter
* @deprecated Since yesterday
*/
public int foo(int x, float y)
{
return 5;
}

Exceptions

try
{
// ...
return 5;
}
catch ( Exception e )
{
System.err.println( "Error");
}
finally
{
... // (1)
// return 7; (2)
}
(1) auf jeden Fall, auch nach dem return
(2) keine Exception kann nach oben durchgereicht werden

Wann wird finally ausgeführt

In diesem Beispiel nutzen alle return Anweisungen eine Methode um den Rückgabewert zu ermitteln. Dadurch kann man dokumentieren, wann die einzelnen return Anweisungen aufgerufen werden
public static String getStringValueAndLogIt(String pValue)
{
System.out.println("Here is your String value: "+pValue);
return pValue;
}

@SuppressWarnings("finally")
public static String doSomething(boolean pDoException)
{
System.out.println("Method entered");
try
{
System.out.println("Try block entered");
if(pDoException) throw new Exception("Bang!");
return getStringValueAndLogIt("NormalReturn");
}
catch(Exception e)
{
System.out.println("Exception occured");
return getStringValueAndLogIt("ExceptionReturn");
}
finally
{
System.out.println("Finally block entered");
// do not use return in a finally block!
return getStringValueAndLogIt("FinallyReturn");
}
}
Falls keine Exception auftritt:
Method entered
Try block entered
Here is your String value: NormalReturn
Finally block entered
Here is your String value: FinallyReturn

Falls eine Exception auftritt
Method entered
Try block entered
Exception occured
Here is your String value: ExceptionReturn
Finally block entered
Here is your String value: FinallyReturn

Man sieht also, in beiden Fällen wird erst das return aufgerufen und dann erst den finally Block. Das ist auch sehr sinnvoll, weil natürlich auch das return Statement eine Exception auslösen könnte.
Da der finally Block selbst wieder ein return enthält (was man tunlichst vermeiden sollte) setzt dieser sich am Ende durch und die Methode liefert in beiden Fällen
FinallyReturn
zurück.

Eigene Exceptions

public class ClubException extends RuntimeException
{
public ClubException()
{
}

public ClubException( String s )
{
super( s );
}
}

Stacktrace

kill -3 PID
jstack PID;
Thread.dumpStack();

Assert

Sicherstellen dass die gegebene Bedingung erfüllt ist
assert(i>0);
Überwachung der Assertions aktivieren
java -enableassertions      foo
java -enableassertions:bar foo

Multithreading

Erste Variante

Von der Klasse
Thread
erben und die Methode run überschreiben.
public class Foo extends Thread
{
@Override
public void run()
{
// ...
}
}

Jetzt einfach ein Objekt dieser Klasse erzeugen und die Methode
start()
und nicht
run()
aufrufen.
final int nrOfThreads=4;
Foo [] f=new Foo[nrOfThreads];
for(int i=0; i<nrOfThreads; i++)
{
f[i]=new Foo();
f[i].start();
}

Zweite Variante

Das Interface
Runnable
implementieren
public class Bar implements Runnable
{
public void run()
{
// ...
}
}

final int nrOfThreads=4;
Thread [] f=new Thread[nrOfThreads];
for(int i=0; i<nrOfThreads; i++)
{
f[i]=new Thread(new Bar());
f[i].start();
}

Auf das Ende eines Threads warten

try
{
for(int i=0; i<nrOfThreads; i++) f[i].join();
}
catch (InterruptedException e) {};
Normalerweise läuft ein Programm so lange weiter, bis auch der letzte Thread sich beendet hat. Ruft man auf einem Thread die Methode
setDaemon(true);
auf, wird auf das Ende dieses Threads nicht mehr gewartet.

Threads von außen beenden

Um einen Thread von außen beenden zu können, ist es hilfreich, wenn dieser auf
!isInterrupted()
testet und
InterruptedException
Exceptions fängt und dann selbst
interrrupt()
aufruft. Z.B.
while (!isInterrupted())
{
try
{

...

}
catch ( InterruptedException e )
{
interrupt();
}
}
Jetzt kann man den Thread von außen mit
interrupt()
beenden.

Hat man Runnable implementiert, kann man so testen, ob man unterbrochen wurde
while(!Thread.currentThread().isInterrupted())
{
try
{
...
}
catch (InterruptedException e)
{
...
Thread.currentThread().interrupt();
}
}

Synchronized

Methode darf nur von einem Thread gleichzeitig betreten werden
public class Foo
{
synchronized public static void bar()
{
// ...
}
}

Pro Objekt darf Methode nur von einem Thread gleichzeitig betreten werden
public class Foo
{
synchronized public void bar()
{
// ...
}
}

Entspricht
public class Foo
{
public void bar()
{
synchronized(this)
{
// ...
}
}
}

Alternative:
Lock l = ...; 
l.lock();
try
{ ...}
finally
{
l.unlock();
}

ThreadLocal

Variablen auf die nur der entsprechenden Thread Zugriff hat (auf private Attribute hätte alle Objekte der entsprechenden Klasse Zugriff).
ThreadLocal foo = new ThreadLocal<Integer>();
foo.set(42);
Integer i=foo.get();

Exceptions in Threads

Angenommen man hat 4 Threads plus den Thread in dem main() läuft:
public static void main(String[] args)
{
Thread t1,t2,t3,t4;
...
t1.start();
t2.start();
t3.start();
t4.start();

while(true)
{
foo();
}
}

Eine nicht gefangene Exception in einem der Threads bricht nur genau diesen ab, alle anderen laufen ganz normal weiter. Selbst wenn der Thread in dem main läuft abbricht, laufen t1 bis t4 weiter.

Möchte man ein anderes Verhalten erreichen muss man manuell eingreifen. Z.B. kann man einen UncaughtExceptionHandler in der Klasse Thread eintragen:
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

Die Klasse muss die Methode
void uncaughtException(Thread t, Throwable e)
überschreiben, die bei jedem Thread aufgerufen wird, der durch eine unbehandelte Exception vor der Beendigung steht. In dieser Methode kann er dann auch andere Threads zum Beenden auffordern.
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler
{
private HashMap<Thread, Set<Thread>> connectedThreads;

...
@Override
public void uncaughtException(Thread t, Throwable e)
{
for(Thread connectedThread : connectedThreads.get(t))
{
System.out.println("Thread "+t+" had an uncaught exception, stop also the connected thread "+connectedThread);
connectedThread.interrupt();
}
}
}
Im Debugger funktioniert das möglicherweise nicht wie erwartet.

CountDownLatch

Die Klasse java.util.concurrent.CountDownLatch kann benutzt werden, um mehrere Threads zu koordinieren. Ein CountDownLatch hat einen Startwert, kann um 1 heruntergezählt werden und wenn 0 erreicht wird, kann eine Aktion ausgelöst werden.

Das ist hier ist ein normaler Thread, der zwei CountDownLatch Objekte beinhaltet. Über das eine Objekt teilen wir dem Thread mit, wann er starten darf, über das andere teilt er uns mit, wann er fertig ist.

import java.util.concurrent.CountDownLatch;

public class ThreadLatched extends Thread
{
private final CountDownLatch startLatch;
private final CountDownLatch stopLatch;

/**
* Constructor
*
* @param startLatch latch to signal the start
* @param stopLatch latch to signal the end
*/
public ThreadLatched(CountDownLatch startLatch, CountDownLatch stopLatch)
{
this.startLatch = startLatch;
this.stopLatch = stopLatch;
}

/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run()
{
try
{
// wait for the startLatch to reach 0 to start
startLatch.await();

...
}
catch (InterruptedException iex)
{
...
}
finally
{
// reduce the stopLatch by one to indicate that we are done
stopLatch.countDown();
}
}
}

Und so kann man die CountDownLatch Objekte dann benutzen

final int nrOfThreads=5;

// this starts at 1, is passed to all threads and once it hits 0, everything starts
CountDownLatch startLatch = new CountDownLatch(1);

// this starts at number of threads, is passed to all threads, every thread that finishes reduces it by one, once it reaches 0 all threads are done
CountDownLatch stopLatch = new CountDownLatch(nrOfThreads);

// init threads
for(int i=1; i<=nrOfThreads; i++)
{
Thread t = new ThreadLatched(startLatch, stopLatch);
t.start();
}

// this gives the start signal for all threads
startLatch.countDown();

// this waits for all threads to be finished
stopLatch.await();

Semaphore

Mit einer Semaphore kann man die Anzahl der Thread für eine Resource beschränken. Mit
semaphore.acquire();
kann eine Thread in den kritischen Bereich eintreten, ist der schon zu voll wird automatisch gewartet. Und mit
semaphore.release();
kann er sie beim Verlassen wieder freigeben und einer der Wartenden kann dafür eintreten.

Die Semaphore wird zentral erzeugt und dann allen interessierten Threads zugewiesen. Beim Erzeugen kann man noch festlegen, ob sie fair ist, d.h. der, der am längsten wartet, darf als erstes rein. Fair sein ist hier etwas langsamer, dafür kann es aber auch nicht passieren, dass ein Thread in der sehr Warteposition sehr lange hängen bleibt.

boolean fair=true;
Semaphore s=new Semaphore(3, fair);

MyTask t1=new MyTask(s);
MyTask t2=new MyTask(s);
...

import java.util.concurrent.Semaphore;

public class MyTask implements Runnable
{
private Semaphore semaphore;

public MyTask(Semaphore pSemaphore)
{
this.semaphore=pSemaphore;
}

@Override
public void run()
{
try
{
this.semaphore.acquire();

// do the work

this.semaphore.release();
}
catch (InterruptedException e)
{
e.printStackTrace();
}

}

}

ThreadPoolExecutor

Wenn man in Java x Threads zu verarbeiten hat und davon immer y Threads parallel verarbeiten möchte, geht das so:
// number of CPUs in your computer
int cpus=Runtime.getRuntime().availableProcessors();

// what to run
Runnable r1, r2;

// run Runnables
ExecutorService executorService = Executors.newFixedThreadPool(cpus);
...
executorService.execute(r1);
executorService.execute(r2);
...
executorService.awaitTermination(15, TimeUnit.SECONDS);

Wenn man von den Tasks auch ein Ergebnis zurückgeliefert haben möchte, kann man statt Runable zu nutzen das Interface
Callable< TYPE >
implementieren.
public class MyTask implements Callable< Integer >
{

@Override
public Integer call() throws Exception
{
Integer result;
...
return result;
}
}

Und so stellt man neue Tasks ein (es wird nicht darauf gewartet, bis das Ergebnis wirklich vorliegt, man bekommt nur ein mehr oder weniger leeres Future Objekt):
Future<Integer> myResult= executorService.submit( new MyTask() );

So kann man testen ob das Ergebnis bereits vorliegt (es wird nicht darauf gewartet, dass ein Ergebnis vorliegt)
myResult.isDone();

Und so holt man sich das Ergebnis (falls es noch nicht fertig ist wird darauf gewartet)
myResult.get();

Wenn eine Menge von Tasks abgeben möchte und erst weiterlaufen will, wenn alle ein Ergebnis vorliegen geht das so:
List< Callable< TYPE > > myTasks;
results=executorService.invokeAll(myTasks);
Man erhält dann eine komplette Liste aller Ergebnisse, die auch bereits alle vorliegen.

ForkJoinPool

Ab Java 7 gibt es ein neues Framework für die Abarbeitung von Task. Hierbei gibt es nicht nur eine Warteschlange mit zu erledigenden Tasks, sondern jeder Task hat selbst auch eine lokale Warteschlange, in die er Tasks einstellen kann. Wenn ein Task mit seiner Warteschlange fertig ist, versucht er erst den anderen Tasks einen Task abzunehmen (zu "stehlen") und wenn alle fertig sind wird die Haupt Warteschlange abgearbeitet. In einigen Fällen kann das schneller sein als eine ThreadPoolExecutor Lösung die nur eine Warteschlange für alle Tasks hat. Ein Beispiel dafür ist, die Abarbeitung verschieden aufwendiger Tasks, die sich selbst in kleinere Subtasks aufteilen. Die Threads, die die leichteren Task bereits abgearbeitet haben, können hier die belasteten Threads Aufgaben stehlen und so die Last gleichmäßig verteilen.
Eine andere Anwendung ist die Möglichkeit, dass ein Task auch ein Ergebnis zurückliefern kann. Wenn er seine Aufgabe in Subtasks verteilt, kann er selbst auf das Ergebnis der Subtask warten und wird während er wartet nicht mehr als aktiver Thread gezählt. Bei einer ThreadPoolExecutor Lösung ist es in diesem Fall schwieriger eine ungefähr konstante Anzahl an aktiven Threads zu haben und gleichzeit die Ergebnisse aller Threads optimal aufzusammeln.
So kann man einen Pool erzeugen und ihn mit Aufgaben auffüllen. In diesem Beispiel berechnen die Tasks alle Primzahlen im vorgegeben bestimmten Bereich:

import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;

// create a pool of 4 parallel tasks
final int nrOfParallelTasks=4;
ForkJoinPool pool= new ForkJoinPool(nrOfParallelTasks);

// add some tasks to that pool
ForkJoinTask<Set<Integer>> task_A = new PrimeCalculator(1, 100000);
pool.invoke(task_A);

ForkJoinTask<Set<Integer>> task_B = new PrimeCalculator(100000, 200000);
pool.invoke(task_B);

// collect the results of our tasks
Set<Integer> allPrimes=new HashSet<Integer>();
allPrimes.addAll(task_A.getRawResult());
allPrimes.addAll(task_B.getRawResult());

Und so sieht ein Task aus (die eigentlichen Methoden, die berechnen ob eine Zahl prim ist fehlen).

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.RecursiveTask;

public class PrimeCalculator extends RecursiveTask<Set<Integer> > {
private final int min;
private final int max;

public PrimeCalculator(int pMin, int pMax)
{
this.min=pMin;
this.max=pMax;
}

/* (non-Javadoc)
* @see java.util.concurrent.RecursiveTask#compute()
*/
@Override
protected Set<Integer> compute()
{
Set<Integer> result=new HashSet<Integer>();

// decide if our task should be split in two smaller tasks
if(notTooBigForOneTask())
{
// do the calculation
System.out.println("Calculate "+this.min+ " to "+this.max);
int currentNumber=this.min;
while(currentNumber<=this.max)
{
if(isPrime(currentNumber))
result.add(currentNumber);

currentNumber++;
}
}
else
{
// split the task into two subtasks
int splitPos=splitPosition();

System.out.println("Split task "+this.min+"-"+this.max+" into two subtasks "+this.min+"-"+splitPos+" and "+splitPos+"-"+this.max);

PrimeCalculator a=new PrimeCalculator(this.min, splitPos);
PrimeCalculator b=new PrimeCalculator(splitPos+1, this.max);
// add the new tasks to the local queue of this taks
invokeAll(a, b);
// collect their results
result.addAll(a.getRawResult());
result.addAll(b.getRawResult());
}
return result;
}
}

Links ForkJoinPool


Datencontainer

Entweder für beliebige Objekte
Collection c = new LinkedList(); 
c.add("Hello");
c.add("World");
for ( Object x : c ) System.out.println( x );

Oder für spezielle
Collection<String> c = new LinkedList<String>();
for ( String x : c ) System.out.println( x );

Listen

ArrayList, LinkedList

Mengen

HashSet, TreeSet, LinkedHashSet

Assoziativspeicher

HashMap, TreeMap, LinkedHashMap, WeakHashMap

  • man hat ein Object O
  • und einen Key K
  • Von dem Key K gibt es ein H(K)
Die HashMap fügt im Hash dann unter H(K) alle Objekte O ein. Es kann mehrere Objekte O geben, die den gleichen Wert für H(K) haben, aber unterschiedliche Werte für K. Ist auch K gleich, wird der vorherige Eintrag überschrieben.
Für die Klasse Integer gilt z.B. H(K)=K, das muss aber nicht so sein.

WeakHashMap

Der Garbage Collector in Java entsorgt automatisch alle Java Objekte, auf die niemand mehr eine Referenz hält.

Wenn man untersuchen möchte, ob ein Objekt schon entsorgt worden ist, kann man daher natürlich keine Referenz mehr auf das Objekt halten. Hier kommt die WeakHashMap ins Spiel. Objekte die als Value in ihr enthalten sind, zählen nicht als Referenz für die Garbage Collector. Sobald ein Objekt entsorgt wird, wird es auch automatisch aus der WeakHashMap entfernt.
Kleines Beispiel:

private WeakHashMap<Integer, BigThing> notYetFreed;

public void doTest()
{
notYetFreed=new WeakHashMap<Integer, BigThing>();

for(int i=0; i<100; i++)
{
BigThing bt=new BigThing();
notYetFreed.put(i, bt);
System.out.println(notYetFreed.size());
}

while(notYetFreed.size()>0)
{
System.out.println(notYetFreed.size());
}
}

Da die BigThing Objekte nach jedem Durchlauf der Schleife von niemandem außer der WeakHashMap referenziert werden, werden die Einträge aus der WeakHashMap schnell wieder entfernt.

Achtung: Das funktioniert nicht, wenn man die Objekte auch als Key und nicht nur als Value in der WeakHashMap verwendet. So würde es also nicht funktionieren:

private WeakHashMap< BigThing, BigThing> notYetFreed;
...
notYetFreed.put(bt, bt);

Queue

LinkedList, ArrayBlockingQueue, PriorityQueue

Sortieren von Datencontainern

So kann man eine Collection sortieren lassen:
public class MyFooComparator implements Comparator<Foo>
{
...

@Override
public int compare(Foo o1, Foo o2)
{
...
}

...
}

List<Foo> myList;
Collections.sort(myList);

Comparator myComparator=new MyFooComparator();
Collections.sort(myList, myComparator);
Im ersten Fall muss Foo Comparable implementieren, im zweiten Fall kann man seine(n) eigenen Comparator(en) schreiben.
Die Sortierung arbeitet direkt auf dem Container selbst, gegenfalls vorher klonen.

Bei Sortieren kann man leicht das Problem bekommen, dass man zwei Elemente a, b hat, die nicht gleich sind (!a.equals(b)). Allerdings könnten beide Objekte bezüglich einer Sortierung weder kleiner noch größer sein. Beispielsweise bei der Sortierung von Personen nach Schuhgröße. a und b können ganz verschiedene Menschen sein und dennoch genau die selbe Schuhegröße haben. In diesem Fall muss man besonders mit einem TreeSet Container aufpassen. Dieser speichert jedes Objekt höchstens ein mal und aus a.compareTo(b)==0 schließt er (fälschlicherweise?) nur eines der beiden Objekte muss im Container gespeichert werden. Lösung: compareTo() auf mehr Attribute ansetzten oder statt TreeSet eine andere Datenstruktur benutzen (TreeBag?)

Dateien und Verzeichnisse

Java is auch eine Insel: Dateien und Verzeichnisse.

CSV Dateien auslesen

OpenCSV
import au.com.bytecode.opencsv.CSVReader;
...

CSVReader reader = new CSVReader("Foo.csv", ',');
List<String[]> myEntries = reader.readAll();

Excel Dateien schreiben und lesen

Apache POI
import java.io.File;
import java.io.FileOutputStream;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

...

XSSFWorkbook workbook=new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("My Excel Sheet");
XSSFRow row0 = sheet.createRow(0);
{
XSSFCell cell0 = row0.createCell(0);
XSSFCell cell1 = row0.createCell(1);
cell0.setCellValue(“Number”);
cell1.setCellValue(“Date”);
}

XSSFRow row1 = sheet.createRow(1);
{
XSSFCell cell3 = row1.createCell(1);
cell3.setCellValue(42);

XSSFCell cell4 = row1.createCell(2);
cell4.setCellValue(new Date());

XSSFCellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(workbook.getCreationHelper().createDataFormat().getFormat("yyyy-mm-dd"));
cell4.setCellStyle(cellStyle);
}

sheet.autoSizeColumn(0);
sheet.autoSizeColumn(1);

File output=new File(“excelfile.xlsx);
FileOutputStream out = new FileOutputStream(output);
workbook.write(out);

out.close();

Datei im Classpath finden

URL url = this.getClass().getClassLoader().getResource(pFilename);
if(url!=null)
{
return url.getPath();
}

Reguläre Ausdrücke

Häufig möchte man aus einem String bestimmte Teile ausschneiden und dann neu zusammensetzen. Ein typisches Beispiel ein Datum liegt in dieser Form vor
13/07/2013
und soll in diese Form übertragen werden
2013-07-13
Mit einer sogenannten Backreference kann man jetzt Tag, Monat und Jahr erst durch einen regulären Ausdruck erfassen und Klammern. Danach dann via $1, $2, $3 wieder ausgeben lassen
string s=s.replaceAll("([0-9]*)/([0-9]*)/([0-9]*)", "$3-$2-$1");
Und schon hat man ein Format welches Date versteht
java.sql.Date d=java.sql.Date.valueOf(s);

Datum

Zahlreiche Methoden der Date Objekte sind seit einiger Zeit deprecated. Mit der Hilfe der Calendar Klasse kann man weiterhin auf die entsprechenden Datumsfelder zugreifen:

Date lCurrentDate=new Date();
Calendar lCal=Calendar.getInstance();
lCal.setTime(lCurrentDate);
lCal.get(Calendar.YEAR);
lCal.get(Calendar.MONTH);
lCal.get(Calendar.DAY_OF_MONTH);

Und entsprechend lässt sich das Datum auch manipulieren

Calendar lToday = new GregorianCalendar();
lToday.set(Calendar.HOUR_OF_DAY, 23);
lToday.set(Calendar.MINUTE, 59);
lToday.set(Calendar.SECOND, 0);
lToday.set(Calendar.MILLISECOND, 0);
Date lNewDate=lToday.getTime();

Möchte man von einem gegebenen Datum einige Tage abziehen oder addieren geht das so
Date yourDate=...;
Calendar calendar = new GregorianCalendar();

// remove timezone
Date cleanDate=new Date(yourDate.getTime());

calendar.setTime(cleanDate);
calendar.add(Calendar.DAY_OF_MONTH, -14);
Date lNewDate=calendar.getTime();

So kann man ein Datum in einen schönen String umwandeln (format()) oder aus einem beliebigen String ein Datum erzeugen (parse())
Date d=new Date();
...
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String s=f.format(d);
f.setLenient(false);
Date d2=f.parse(s);

Mit dem Datum kann man in Java viel Spaß haben. Angenommen man hat zwei Datumsobjekte

long time1=1376639746195L;

java.util.Date date1;
java.util.Date date2;

Eines davon ist wirklich vom Typ Date, das andere ein Timestamp (ein Erbe von Date)

date1=new java.util.Date(time1);
date2=new java.sql.Timestamp(time1);

Das ist keine künstliche Situation, das passiert z.B. schnell wenn man ein Datum per Hibernate in einer Datenbank persistiert und wieder ausliest.
Bei zeigen auf exakt dieselbe Uhrzeit und sind sogar equal

date1.getTime(); // 1376639746195
date2.getTime(); // 1376639746195
date1.equals(date2); // true

Was passiert wohl, wenn man beide vergleicht?
date1.compareTo(date2); // 1

Die ersten der beiden gleichen Daten ist also größer!

(equals) ... is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.

Testen wir doch mal

date1.equals(date2); // true
date2.equals(date1); // false

Die Ursache ist offenbar, dass die Genauigkeit von Timestamp eigentlich nicht genau genug für Millisekunden ist. Also entfernen wir im Date doch auch mal die Millisekunden (die letzten 3 Stellen)

long time1=1376639746195L;
long time2=1376639746000L;
date1=new java.util.Date(time2);

Und schon findet compareTo, dass beide gleich sind.

date1.getTime(); // 1376639746000
date2.getTime(); // 1376639746195
date1.compareTo(date2); // 0

Aber sind sie eigentlich trotz der abweichenden getTime() Werte noch equals?

date1.equals(date2); // false
date2.equals(date1); // false

Es hilft hier nur, in beiden den Millisekundenanteil zu streichen. Kleiner Auszug aus dem JavaDoc von compareTo()

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)).

Reflection

Class c=null;
try
{
c = Class.forName("foo");
} catch (ClassNotFoundException ex)
{
// ...
}

Annotations

So macht man seine eigene Annotation
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface XMLGeneratorAnnotation
{
String elementName() default "";
int elemntOrder() default 0;
}

So ermittelt man alle Attribute eines Objektes und seine Werte

for(Field f : myObject.getClass().getDeclaredFields())
{
f.setAccessible(true);
MyAnnotation a=f.getAnnotation(MyAnnotation.class);
try
{
f.getName();
f.get(myObject);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
}
finally
{
}
}

So ermittelt man alle Methoden eines Objektes und ruft sie auf

for(Method m : myObject.getClass().getDeclaredMethods())
{
m.setAccessible(true);

ElementContainer container=new ElementContainer();

MyAnnotation a=m.getAnnotation(MyAnnotation.class);
try
{
m.getName();
m.invoke(myObject);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
{
}
finally
{
}
}

Apache Commons

Nützliche Java Komponenten Apache Commons.

Objekte in Strings umwandeln

ToStringBuilder
ToStringBuilder.reflectionToString(this);

new ToStringBuilder(this).append("Name: ", name).append("ID: ", id).toString();

one-jar

Mit one-jar kann man mehrere jars in ein großes jar packen und über one-jar selbststartend machen.

JAD Decompiler

Mit dem JAD Java Decompiler aus class-Dateien wieder lesbaren Quellcode machen. Mit dem Eclipse Plugin JADClipse sogar vollautomatisch öffnen der entsprechenden Klassen.
Wenn man eine Eclipse Version neuer als Indigo einsetzt, muss man manuell in den Eclipse Einstellungen unter
General - Editors - File Associations
diese Dateiendung
.class without source
auch mit Jadclispe verbinden. Siehe auch Configuring eclipse to use jad.

String in Zahl konvertieren

Integer.parseInt("042", 10);

0 Padding

So kann man den String year mit führenden Nullen auf 4 Stellen auffüllen:
String s=String.format("%04d",year);
Syntax:
%[flags][width]conversion

Flags '0' (0 Padding)
Conversion 'd' Integer, 'f' Float, 't' date, 'T' Time

BigDecimal

Ein BigDecimal erzeugen
BigDecimal x=new BigDecimal("1.123456789");

Ein BigDecimal runden
BigDecimal y=x.setScale(2, BigDecimal.ROUND_HALF_UP);
(x bleibt dabei unverändert)

Mit BigDecimal teilen
BigDecimal a=new BigDecimal("1").setScale(0);
BigDecimal b=new BigDecimal("1.2345");
BigDecimal r=a.divide(b, RoundingMode.HALF_UP);
Achtung, die Genauigkeit beim Teilen zweier BigDecimal wird durch das Objekt festgelegt, dessen divide Methode aufgerufen wird. Das kann zu überraschenden Ergebnissen führen! Daher überlegen, die Genauigkeit beim Teilen anzugeben
BigDecimal r=a.divide(b, 7, RoundingMode.HALF_UP);

Gibt man beim teilen zweier BigDecimal Zahlen keine Roundsart an, und passt das Ergebnis nicht in ein BigDecimal (z.B. 1/3), gibt es eine Exception
java.lang.ArithmeticException: Non-terminating decimal expansion; noexact representable decimal result.
Deshalb beim Teilen immer eine Rundungsart angeben!

Binärdarstellung

Siehe Binärdarstellung von Zahlen
Integer.toBinaryString(number);
Long.toBinaryString(number);
Long.toBinaryString(Double.doubleToRawLongBits(number));

Java Properties

Über Properties kann man leicht Parameter zur Konfiguration einer Anwendungen setzen und lesen (ähnlich dem setzen einer Systemvariable wie z.B. PATH).
So kann man in Java leicht Properties auslesen
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;

...

// System properties (java -Dvariable=value)
Properties systemProperties=System.getProperties();

// Properties found in a file in the classpath, will also
// contain the values from the system properties
Properties fileProperties =new Properties(systemProperties);
URL url = ClassLoader.getSystemResource("MyProperties.properties");
fileProperties.load(new FileInputStream(new File(url.getFile())));

// Properties we will fill with the code during runtime
// will also contain the file properties (and with them also
// the system properties)
Properties extraProperties =new Properties(fileProperties);

// changes to the top level properties objects ...
systemProperties.setProperty("test.helloworld", "Hello world");
// ... are also reflected in their children
String message=extraProperties.getProperty("test.helloworld");
// debug output
extraProperties.list(System.out);

Java Preferences

Über Preferences kann man leicht Userbezogene Einstellungen abspeichern und später wieder laden. Dabei werden die Information im Hintergrund automatisch an einem zentralen Ort (pro User) abgelegt. Unter Windows z.B. in der Registry,
HKEY_CURRENT_USER\Software\JavaSoft\Prefs\
man selbst muss sich um den Ablageort nicht kümmern.
Preferences prefsRoot = java.util.prefs.Preferences.userRoot().node("de.tgunkel.Java.Demo.Preferences");

// read the already stored values
String name =prefsRoot.get( "name", "unknown");
Double weight =prefsRoot.getDouble( "weight", 0.0);
Boolean selected=prefsRoot.getBoolean("selected", false);
Long id= prefsRoot.getLong( "id", 0L);

// store new values
prefsRoot.put ("name", "John Doe");
prefsRoot.putDouble ("weight", 90.01);
prefsRoot.putBoolean("selected", true);
prefsRoot.putLong ("id", 1234567L);


JMX

jconsole

Kleine Java Tools

jvisualvm

OutOfMemoryError: Java heap space

Als erstes den Heap Speicher hochsetzen
-Xmx512m
Falls das nicht hilft, aktuellen heap Speicherverbrauch des Programms mit der genannten PID ausgeben
jmap -histo PID
Oder aber abwarten bis es nicht mehr gereicht hat und dann erst auswerten
# java -XX:+HeapDumpOnOutOfMemoryError -jar foo.jar
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid29731.hprof ...
Heap dump file created [1271286324 bytes in 143.266 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
...

Und die Datei dann auswerten
jhat -J-Xmx512m java_pid29731.hprof
...
Started HTTP server on port 7000

Speichermodell in Java

Stack: Die lokalen und primitiven Variablen einer Methode werden im Stack gespeichert.
Heap: Neu erzeugte Objekte landen im Eden Space / "young generation". Objekte dort werden statistisch oft erzeugt und schnell wieder aufgegeben. Nach einem Garbage Collector Lauf wandern alle Objekte, die ihn überlegt haben in den Survivor Space. Nach einigen Durchläufen landen die überlegebenden Objekte dann in der Tenured Generation / old generation. Das Verschieben der Objekte kostet zwar Aufwand, dafür können dabei aber wieder zusammenhänge Speicherbereiche entstehen.
Non-heap memory: Thread übergreifender Speicher welchen die Java VM für interne Zwecke benötigt. Z.B. Informationen pro Klasse, Methode, Konstruktoren, aber auch Konstanten. Wird Permanent Generation genannt, obwohl der Speicher nicht permant sein muss. Hinzu kommt noch der Code Cache.


25-10-2014 13.08

GUI mit Java

Swing

Java Swing

Java in Internetseiten

Java Applet

Java wird beim Client ausgeführt
Sun Java Applet Tutorial
import javax.swing.JApplet;
import java.awt.Graphics;

public class HelloWorld extends JApplet
{
private static final long serialVersionUID = 1L;

public void init() {};

public void start() {};
public void stop() {};

public void paint(Graphics g)
{
g.drawRect(20, 20, getSize().width - 40, getSize().height - 40);
g.drawString("Hello world!", 40, 40);
}

public void destroy() {};

}
Wird so in HTML eingebettet
<applet width=300 height=300 code="HelloWorld.class"> </applet>

JavaServer Pages und Servlets

Java wird auf dem Server ausgeführt
JavaServer Pages und Servlets

Verteilte Programmierung mit RMI und WebServices

Verteilte Programmierung mit RMI und WebServices
22-09-2012 11.37

Bound Properties / PropertyChangeListener

Bound Properties
Man möchte Code ausführen, wann immer sich in einer anderen Klasse (einer Bean) ein bestimmtes Attribut ändert. Dazu nimmt man sich die ganz normale Bean Klasse mit ihren Settern und Gettern. Die Klasse wird um ein PropertyChangeSupport Attribut ergänzt und in allen betroffenen Settern wird über diese Attribut in jedem relevanten Setter ein firePropertyChange ausgeführt. Außerdem wird noch die Möglichkeit geschaffen, dass man von außen einen PropertyChangeListener in dem PropertyChangeSupport Attribut registrieren kann.

public class MyBean
{
private Long id;
private String name;
private Integer age;

private final PropertyChangeSupport myPropertyChangeSupport = new PropertyChangeSupport( this );

public void addPropertyChangeListener( PropertyChangeListener listener )
{
this.myPropertyChangeSupport.addPropertyChangeListener( listener );
}

public void removePropertyChangeListener( PropertyChangeListener listener )
{
this.myPropertyChangeSupport.removePropertyChangeListener( listener );
}

public Long getId()
{
return id;
}
public void setId(Long pId)
{
this.id = pId;
}

public String getName()
{
return name;
}
public void setName(String pName)
{
String lOldName=this.name;
this.name = pName;
this.myPropertyChangeSupport.firePropertyChange("name", lOldName, this.name);
}

public Integer getAge()
{
return age;
}
public void setAge(Integer pAge)
{
Integer lOldAge=this.age;
this.age = pAge;
this.myPropertyChangeSupport.firePropertyChange("age", lOldAge, this.age);
}
}

So sieht z.B. ein PropertyChangeListener aus, der nur ermittelt, wie das Attribut hieß, dass geändert wurde.

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class AttributeStalker implements PropertyChangeListener
{
@Override
public void propertyChange(PropertyChangeEvent evt)
{
String attributeName=evt.getPropertyName();
...
}
}

Und so benutzt man die Bean mit dem PropertyChangeListener

MyBean b=new MyBean();
AttributeStalker s=new AttributeStalker();
b.addPropertyChangeListener(s);
b.setId(5l);
b.setName("Foo");


13-07-2011 21.56

junit


Man erzeugt eine neue Klasse, in der mit @Test markierte Methoden einzelne Tests ausführen
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class MyCTestClass
{
@Before
public void Myinit()
{
...
}

@Test
public void TestAddMethod()
{
assertTrue(a.add(ZERO).equals(a));
assertTrue(a.add(b).equals(b.add(a)));
}

@Test
public void isDivOK()
{
assertTrue(a.div(ONE).equals(a));
assertTrue(a.mult(b).div(b).equals(a));
}

@Test(expected=NullPointerException.class)
public void nullParameter()
{
a.add(null);
}

}

Diese Tests können dann über die Kommandozeile, die IDE oder im Buildprozess ausgeführt werden.

Man sollte sich vorher überlegen, ob man die JUnit Testklassen direkt im normalen Source Ordner ablegt, wo auch die zu testenden Klassen liegen
MyProject
build
src
de
tgunkel
Foo.src
FooTest.src
oder ob man parallel zum Source Ordner eine weitere Ordner Hierarchie einzieht in der dann die Tests liegen
MyProject
build
src
de
tgunkel
Foo.src
src_tests
de
tgunkel
FooTest.src
Legt man sie im selben Ordner ab, werden die Klassen direkt mitkompiliert und man muss seinen Buildprozess nicht anpassen. Dafür ist es aufwendiger die Tests vom normalen Code zu trennen, z.B. wenn man die Testklassen nicht mit ausliefern möchte. Das Ergebnis kann man dann in einem Ordner ablegen lassen. Andere Tools können die Ergebnisse in diesem Ordner dann auswerten.

JUnit Test über die Kommandozeile

java org.junit.runner.JUnitCore MyCTestClass

JUnit Tests in Eclipse

Eclipse unterstützt direkt JUnit Tests
Eclipse JUnit

JUnit Tests mit ant

Man kann direkt aus ant heraus die JUnit Tests durchlaufen lassen
<property name="junitTestResults"     location="_junit_test_results/" />

<path id="classpath">
<fileset file="MyProject.jar" />
</path>

<path id="classpath_tests">
<fileset file="MyProjectTests.jar" />
<fileset file="junit-4.8.1.jar" />
</path>

<target name="unittests" description="Execute unit tests" depends="compile_tests,jar_tests">
<echo message="Unit tests ..." />
<junit printsummary="withOutAndErr" fork="no" failureproperty="junit.failure" haltonfailure="false">

<classpath refid="classpath" />
<classpath refid="classpath_tests" />

<formatter type="xml" usefile="true" />

<batchtest todir="${junitTestResults}">
<fileset dir="src_tests">
<include name="**/*.java"/>
</fileset>
</batchtest>

</junit>
<echo message="Unit tests done" />
</target>

So kann man steuern, ob mögliche Stacktraces auf der Konsole landen
<!-- <formatter type="xml" usefile="true" /> -->
<formatter type="plain" usefile="false"/>

JUnit und log4j

public class myTestClass
{
@BeforeClass
public static void staticInit()
{
// make log4j happy
BasicConfigurator.configure();
}
}

Junit, ant und Stacktrace für Tests auf Console



Hudson / Jenkins

Hudson (Oracle) bzw. Jenkins (freier Fork) ist ein Tool zur kontinuierlichen Überwachung von Softwareprojekten. Damit kann man z.B. periodisch aus einem Subversion Server Code auschecken, in compilieren und danach die Ergebisse der JUnit Test überprüfen. Über die Ergebnisse können die Entwickler dann direkt informiert werden.

13-02-2012 00.26

Java Logging

Simple Logging Facade for Java SLF4J

Mit SLF4J bietet generische Log Methoden an, welches Framework dann wirklich zum Loggen benutzt wird, kann dann zur Laufzeit festgelegt werden. Sehr praktisch wenn ein Programm vertreiben möchte und den Kunden bezüglich des Log Frameworks die Qual der Wahl lassen will.

So einfach kann man dann Logs schreiben:

Erst slf4j-api-?.jar SLF4J dem Projekt hinzufügen und dann

package de.tgunkel.Java.LogTest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyLogTest
{
final static Logger logger1 = LoggerFactory.getLogger(MyLogTest.class);
final static Logger logger2 = LoggerFactory.getLogger("Foo");

public static void main(String[] args)
{
logger1.info("Hello World");
logger1.warn("Say '{}' for '{}' times", "Hello World", 3);
logger2.info("Bye bye");
}
}

Allerdings passiert mit den Logs erst mal nichts, es erscheint nur folgende Warnung in der Konsole

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

SLF4J Simple

Um das Logging auszuprobieren, kann man dann

slf4j-simple-?.jar

in den Klassenpfad auchnehmen. Und schon erscheinen dann die Logmeldungen:

0 [main] INFO de.tgunkel.Java.LogTest.MyLogTest - Hello World
4 [main] WARN de.tgunkel.Java.LogTest.MyLogTest - Say 'Hello World' for '3' times
4 [main] INFO Foo - Bye bye

SLF4J NOP

Mit slf4j-nop-?.jar werden alle Logmeldungen hingegen einfach verworfen.

SLF4J log4J

Um log4j zu benutzen sind ein paar extra Schritte notwendig:

slf4j-log4j12-?.jar in der Klassenpfad aufnehmen.
log4j-?.jar (von der log4j Webseite http://logging.apache.org/log4j/) runterladen und ebenfalls dem Klassenpfad hinzufügen
Eine Datei log4j.properties anlegen:

log4j.appender.MyAppender1=org.apache.log4j.ConsoleAppender
log4j.appender.MyAppender1.layout=org.apache.log4j.PatternLayout
log4j.rootLogger = DEBUG, MyAppender1

und ebenfalls dem Klassenpfad hinzufügen.

Log4j


Komponenten

In Log4j gibt es 3 (4) Komponenten
  • Loggers
  • Layouts
  • Appenders
  • (und aus Gründen der Rückwärtskompatibilität noch Category)


Loggers

Der Root Logger hat keinen Namen und existiert implizit. Man erhält ihn über die statische Methode
Logger.getRootLooger();

Alle anderen Logger werden über
Logger.getLogger(name);
bezogen.

Logger sind hierarchisch über ihren Namen aufgebaut. Der Logger foo ist der Vater von foo.bar, welcher der Vater von foo.bar.blub ist, usw. Das kann z.B. so benutzt werden, dass man als Namen für den Logger den vollständigen Klassennamen de.foo.class1 oder nur den Paketnamen de.foo benutzt.

Logger ohne Vater haben automatisch den Root Logger als Vater.

Levels

Alle Logger haben einen Log Level. Es gibt folgende Level
  • FATAL
    • ERROR
      • WARN
        • INFO
          • DEBUG

Wird für einen Logger kein Level konfiguriert, erhält er den Level des nächsten übergeordneten Vorgängers, der einen Level gesetzt hat. Der Root Logger hat immer ein Log Level gesetzt.

Geloggt wird im Java Code so:
Logger logger=...;
logger.debug("Hello World");
logger.info("Hello World");
logger.warn("Hello World");
logger.error("Hello World");
logger.fatal("Hello World");

Die Meldung erscheint aber nur, wenn der Log Level mindestens auf dem Level steht, welches der Log Methode entspricht. Also logger.info() wirkt nur, wenn logger mindestens auf DEBUG oder INFO steht.
Baut man den Text zum Loggen erst aufwendig zusammen, lohnt es sich oft, erst zu prüfen, ob dieses Level überhaupt geloggt werden soll (ansonsten lohnt sich dieser extra Test aber nicht):

if( logger.isDebugEnabled())
{
String text="foo bar";
logger.debug("a"+"b"+r*s/t+"c"+text);
}

Appenders

Jedem Logger kann ein oder mehrere Appenders zugewiesen werden. Dorthin werden die Log Meldungen geschrieben. Appenders können z.B. Dateien (FileAppender, DailyRollingFileAppender), die Konsole, syslog, E-Mail (SMTPAppender) oder sogar eine Datenbanktabelle (JDBCAppender) sein.
Der Log Text erscheint in allen Appenders des benutzten Loggers plus in allen Appenders aller Vorgänger inklusive dem Root Logger. Möchte man das nicht, kann man das sogenannte Additivity Flag setzen:
log4j.additivity.MyLogger=false

Layout

Ausgaben können formatiert werden. Interessant sind SimpleLayout, PatternLayout, HTMLLayout

Konfiguration

Wenn die Konfiguration über eine Properties Datei durchgeführt wird, gibt man diese Datei entweder über
-Dlog4j.configuration=
beim Starten der VM an, oder man nennt die Datei log4j.properties, Log4j durchsucht alle Ordner im Klassenpfad nach einer solchen Datei.

Beispiel
log4j.appender.MyAppender1=org.apache.log4j.ConsoleAppender

log4j.appender.MyAppender2=org.apache.log4j.RollingFileAppender
log4j.appender.MyAppender2.file=logfile.log
log4j.appender.MyAppender2.MaxFileSize=10MB
log4j.appender.MyAppender2.MaxBackupIndex=1
log4j.appender.MyAppender2.layout=org.apache.log4j.PatternLayout
log4j.appender.MyAppender2.layout.ConversionPattern=%-5p [%t] (%F:%L) - %m%n
# send logs via mail
#log4j.appender.MyAppender2.layout.ConversionPattern=ROOT %d{ABSOLUTE} [%-30.30C{1}] [%-17t] %-5p %x - %m%n
log4j.appender.MyAppender3 = org.apache.log4j.net.SMTPAppender
log4j.appender.MyAppender3.To = foo@example.com <mailto:foo@example.com>
log4j.appender.MyAppender3.From = bar@example.com
log4j.appender.MyAppender3.SMTPHost <mailto:bar@example.comlog4j.appender.MyAppender3.SMTPHost> = mail.example.com
log4j.appender.MyAppender3.Subject = New Mail from your logger
log4j.appender.MyAppender3.LocationInfo = false
log4j.appender.MyAppender3.layout = org.apache.log4j.PatternLayout
log4j.appender.MyAppender3.layout.ConversionPattern=%m%n
log4j.appender.MyAppender3.EvaluatorClass = foo.bar.MailEventTriggerEvaluatorClass
log4j.rootLogger = DEBUG, MyAppender1

log4j.logger.MyLogger1 = ERROR, MyAppender2
log4j.additivity.MyLogger1=false

log4j.logger.MyLogger1.Foo = DEBUG, MyAppender2, MyAppender3

Achtung, der SQL Appender von log4j hat ein Limit an Zeilen, die geloggt werden. Sonst schneidet er die älteren Zeilen einfach ab

# max nr of log messages (default seems to be 512)
log4j.appender.BusinessMailAppender.BufferSize=2048

Java Logging

Alternative zu log4j

Beispiel

private Logger mLogger;

...

private Logger getLogger()
{
if(mLogger==null)
{
Level minLevel=Level.FINE;
mLogger=Logger.getLogger(this.getClass().toString());
mLogger.setLevel(minLevel);
Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(minLevel);
mLogger.addHandler(consoleHandler);
}
return mLogger;
}

...

getLogger().warning("Oh oh!");
13-02-2012 00.26

Java XML

Es gibt zwei Unterschiedliche Ansätze im in Java XML zu bearbeiten, dom4j und SAX.

Java XML dom4j

So schreibt man in Java eine XML Datei mit dom4j. Dabei wird der komplette Inhalt in ein Objekt gepackt und am Ende in XML umgewandelt.
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

Document document = DocumentHelper.createDocument();
Element root = document.addElement(“foo“);
for(...)
{
Element node=root.addElement(name);
node.addText(“12345”);
}

String xmlString=document.asXML();

Java XML SAX

So liegt man inJava eine XML mit SAX. Dabei definiert man Methoden die während dem Lesen der XML Datei aufgerufen werden, z.B. wenn ein sich öffnendes XML Element gefunden wird.

Als erstes eine Hilfklasse, in die wir ein XML Element speichern können
public class MyElement
{
private String name;
private String content;
MyElement father;

/**
* @param pName
*/
public MyElement(String pName) {
this.name=pName;
}

/**
* @return the father
*/
public MyElement getFather()
{
return father;
}

/**
* @param father the father to set
*/
public void setFather(MyElement father)
{
this.father = father;
}

/**
* @param pContent
*/
public void addContent(String pContent) {
content=""+pContent;
}

/**
* @return the name
*/
public String getName()
{
return name;
}

/**
* @return the content
*/
public String getContent()
{
return content;
}

/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return "[" + name + "]" + content + "[/"+name+"]";
//return name;
}

}

Dann die eigentliche Handler Klasse. Diese enthält die Methoden, die aufgerufen werden sollen. Sie merkt sich dabei alle XML Elemente in der Hilfsklasse
import java.util.Stack;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
* @author Thorsten Gunkel (GUT)
*
* This classes helps SAX to parse an XML document.
* Whenever an XML element is opened, closed or
* data is read one of the corresponding methods is
* called.
*
*/
public abstract class MyXMLHandler extends DefaultHandler
{
Logger logger=LoggerFactory.getLogger(MyXMLHandler.class);

/** Stack to remember which element have been opened */
private Stack<MyElement> elements;

/**
* Constructor
*/
public MyXMLHandler()
{
super();
elements=new Stack<MyElement>();
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException
{
logger.debug("Start to handle new document");
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endDocument()
*/
@Override
public void endDocument() throws SAXException
{
logger.debug("Stop to handle document");
}

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
logger.trace("Start of XML element: "+qName);
MyElement e=new MyElement(qName);
if(elements.size()>0)
{
MyElement father=elements.peek();
e.setFather(father);
}
elements.push(e);
newElementStarted(e);
}

/**
* Overwrite this for every XML file you
* want to parse, it is called every time a new element
* has been found. New elements are not yet complete
* so you may decide to do nothing in here
* @param pElment New and incomplete element
*/
protected abstract void newElementStarted(MyElement pElment);

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
logger.trace("End of XML element: "+qName);
MyElement e=elements.pop();
if(!e.getName().equals(qName)) {
elements.add(e);
throw new SAXException("Found closing element "+qName+" but expected element "+e.getName()+" to be closed.");
}
logger.debug("Finished element: "+e);
newElementFinished(e);
}

/**
* Overwrite this for every XML file you
* want to parse, it is called every time an
* element has been closed, this are the
* complete elements, do something with
* it
*
* @param pElment Finished and complete element
*/
protected abstract void newElementFinished(MyElement pElment);

/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
String value=new String(ch, start, length);
logger.trace("Read of data: "+value);
MyElement e=elements.peek();
e.addContent(value);
}

}

Und mit SAX werden diese Methoden dann passend aufgerufen
URL url=BreachXMLServer.class.getClassLoader().getResource("MyXMLInputFile.xml");
String file=url.getFile();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();

MyXMLHandler h=new MyXMLHandler_ForThisInputFile();
saxParser.parse(file, h);
07-09-2014 02.12

Java SSL

Der Inhalt der keystore Datei auflisten
# keytool.exe -list -keystore my_keystore
Enter keystore password: ********
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
XXXX, 18.03.2014, PrivateKeyEntry,
Certificate fingerprint (SHA1): XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Ein jar mit jarsigner auf valide Signaturen überprüfen
# jarsigner.exe -verbose -certs  -verify myfile.jar
07-09-2014 02.12

ANT

Das Apache ANT Werkzeug. Vergleichbar mit Makefiles, Schwerpunkt liegt aber nicht auf Abhängigkeiten (das kann Java selbst) sondern auf der Bereitstellung plattformunabhängiger Befehle (z.B. zum Kopieren von Dateien).

Links

Kleines ANT Beispielprojekt

<project name="MyProject" default="compile" basedir=".">

<!-- set global properties for this build -->
<property name="src" location="src" />
<property name="build" location="build" />
<property name="dist" location="dist" />
<property name="mainclass" value="de.tgunkel.Test.Foo" />
<property name="distjarname" value="MyProject" />

<!-- path for compiling the code -->
<path id="compilepath">
<fileset file="../../src/lib/foo_1.5.0.jar" />
<fileset dir="../../src/lib/">
<include name="**/*.jar"/>
</fileset>
</path>

<!-- path for running the code -->
<path id="runpath">
<path refid="compilepath"/>
<pathelement location="build"/>
<pathelement location="etc"/>
<fileset file="../../lib/otherlib/foo-2.0.0.jar" />
</path>

<!-- clean -->
<target name="clean" description="clean">
<!-- <delete dir="${build}" /> -->
<delete includeemptydirs="true">
<fileset dir="${build}" includes="**/*"/>
</delete>
</target>

<!-- Some initial stuff -->
<target name="init" description="init">
<!-- Create the time stamp -->
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>

<!-- compile it -->
<target name="compile" description="compile the source" depends="init">
<javac srcdir="${src}" destdir="${build}">
<classpath refid="runpath">
</classpath>
</javac>
</target>

<!-- run the compiled code -->
<target name="run" depends="compile" description="Run the program" >
<java classname =3D "${mainclass}">
<arg value="foo" />
<arg value="bar" />
<arg value="42" />
<classpath refid="runpath" />
</java>
</target>

<!-- create a jar -->
<target name="jar" description="makes a jar" depends="compile">
<jar basedir="${build}" compress="true" jarfile="${dist}/${distjarname}">
<manifest>
<attribute name="Built-By" value="Thorsten Gunkel" />
<attribute name="Main-Class" value="${mainclass}" />
<!-- You need the whole run time path here for an executable jar
<attribute name="Class-Path" value="../../../src/lib/foo_1.0.0.jar" />
-->
</manifest>
</jar>
</target>

</project>

Variablen mit Werten aus anderen Dateien füllen

<property file="my-extra-variables.properties"/>
<property name="JAVA_HOME" value="${YOUR_JAVA_HOME}" />

Warnungen des Compilers wie Fehler behandeln lassen

Wenn man erreichen möchte, dass sich kein Code eingebaut wird, der nur mit Warnungen übersetzt wird, kann man diese nützlich Option setzen:
-Xlint -Werror
Bzw. über ant

 %lt;javac ....>
...
%lt;compilerarg value="-Xlint" />
%lt;compilerarg value="-Werror" />
%lt;/javac>

Jede Warnung wird dann wie ein Fehler behandelt und führt zum Abbruch des Compilers. So werden Warnungen sehr früh bemerkt.

Textersetzung

So kann man mit ANT in Dateien Textersetzung durchführen
<project basedir=".">
<target name="build" description="Replace some strings">

<replace dir=".">
<include name="myfiles/**" />
<replacefilter token="__FOO__" value="BAR" />
<replacefilter token="__43__" value="42" />
</replace>

</target>
</project>

Java Debug

<jvmarg value="-Xdebug"  />
<jvmarg value="-Xnoagent" />
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" />


Classpath setzen

So kann man den Class-Path in einem Manifest setzen
<!-- This is the manifest file we will use -->
<property name="manifest_file" value="$../manifest.mf" />

<!-- This path will be added to the manifest file as the class path-->
<path id="manifestpath_as_path">
<fileset dir="../lib">
<include name="**/*.jar"/>
</fileset>
</path>

<!-- This converts the manifestpath into a format that manifest task will accept. The jarfile attribute is require, but only the path of the file is relevant -->
<manifestclasspath property="manifestpath_as_list" jarfile="../lib/FIXME.jar">
<classpath refid="manifestpath_as_path" />
</manifestclasspath>

<!-- This creates the manifest file -->
<target name="CreateManifest">
<manifest file="${manifest_file}">
<attribute name="Class-Path" value="${manifestpath_as_list}" />
</manifest>
</target>
05-05-2012 23.55

Maven

Maven Buch: Better Build With Maven Better Build With Maven online lesen
Erster Test, geht Maven?

mvn -version

Ein neues Projekt erzeugen
mvn archetype:create   -DgroupId=bar.foo.main -DartifactId=MyFirstMavenApplication
Oder so
mvn archetype:generate -DgroupId=bar.foo.main -DartifactId=MyFirstMavenApplication

Compile
cd MyFirstMavenApplication
mvn compile

Man kann auch nur mal ausprobieren, ob es kompilieren würde
mvn test-compile

So führt man Surefire Tests für das Projekt durch
mvn test

So erstellt man ein Package
mvn package

Clean
mvn clean

Eclipse Konfigurationsdateien erzeugen
mvn eclipse:eclipse

Eine Webseite über das Projekt erzeugen lassen
mvn site

Style Fehler finden (landet in checkstyle-result.xml)
mvn checkstyle:checkstyle

Liste aller verfügbaren Maven Plugins
Wie fügt man Dateien in das erzeugte jar?

Alles was unter
src\main\resources
steht wird 1:1 in das jar übernommen (also z.B. auch jars von Drittanwendungen, die dort hineinkopiert werden).

Für die Tests gilt entsprechend
src\test\resources

Wie erklärt man Abhängigkeiten?
<project>
[...]
<version>1.42</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>foo.bar</groupId>
<artifactId>blub</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>foo.other</groupId>
<artifactId>X</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
</dependencyManagement>
[...]
</project>

Junit kann man so einbauen
<project>
[...]
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
[...]
</project>

Hier kann man Einstellungen festlegen (z.B. Umgebungspezifische Parameter)
<user_home>/.m2/settings.xml
profiles.xml

So kann man das Projekt gleich an den Zielort kopieren lassen (deploy)
<project>
[...]
<distributionManagement>
<repository>
<id>foo</id>
<name>My Foo Repository</name>
<url>scp://foo.example.com/deploy</url>
</repository>
</distributionManagement>
[...]
</project>

Wie fügt man 3rdparty libs hinzu? Entweder die Libs werden bereits auf http://mvnrepository.com gelistet. Dann reicht es, eine entsprechende Abhängigkeit zu benennen
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
Die jars stehen dann automatisch zur Verfügung.

Alternativ kann man auch ein lokales jar referenziere

<dependency>
<groupId>foo</groupId>
<artifactId>blub</artifactId>
<version>1.2.3</version>
<scope>system</scope>
<systemPath>${basedir}/lib/foo-1.2.3.jar</systemPath>
</dependency>

Letzteres wird aber nicht empfohlen.

Wenn man mit Maven solche Fehler bekommt:

generics are not supported in -source 1.3
(use -source 5 or higher to enable generics)
annotations are not supported in -source 1.3
(use -source 5 or higher to enable annotations)
for-each loops are not supported in -source 1.3
(use -source 5 or higher to enable for-each loops)

Kann man so einstellen, welche Version man beim Compilieren benutzen möchte:

<project ...>
...
<dependencies>
...
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

...
</project>

So kann man mit Maven ein Projekt auch ausführen:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>de.tgunkel.de.java.Foo.MyMainClass</mainClass>
</configuration>
</plugin>
</plugins>
</build>

Und dann
mvn exec:java

m2e

Das m2eclipse Maven Eclipse Plugin.
So einfach kann man mit m2e direkt aus einem Subversion Ordner ein Eclipse Projekt erstellen lassen
maven m2e Subversion import
Maven erzeugt eine Eclipse Konfigurationsdatei, in der keine absoluten Pfade stehen. Das ist sehr praktisch, weil man die dann einchecken kann und andere die auch benutzen können. Falls das erst nicht mal nicht funktioniert mit dieser Fehlermeldung
Unbound Classpath Variable M2_REPO 
In Eclipse Unter Preferences - Java - Classpath Variables die Variable M2_REPO anlegen und auf den Maven Repository Eintrag zeigen lassen
Eclipse Unbound Classpath Variable M2_REPO
Geht wohl auch via
mvn -Declipse.workspace=/home/foo/HERE_IS_MY_ECLIPSE_WORKSPACE eclipse:add-maven-repo

Manchmal gibt es Abhängigkeit nicht auf den Maven Server (z.B. aus Lizengründen). Dann kann man die auch manuell hinzufügen. Hier ein Beispiel für den Oracle JDBC Treiber. Erst mal die Abhängigkeit normal definieren

<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc16</artifactId>
<version>11.2.0.2.0</version>
</dependency>

Dann die Datei "ojdbc6.jar" runterladen und in die lokale Maven Installation hinzufügen

mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc16 -Dversion=11.2.0.2.0 -Dpackaging=jar -Dfile=ojdbc6.jar -DgeneratePom=true

Maven über einen Proxy

Maven so einstellen, dass es ein Proxy benutzt wird
~/.m2/settings.xml

<settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>my.proxy.foo.bar</host>
<port>8080</port>
<!--
<username>your-username</username>
<password>your-password</password>
-->
</proxy>
</proxies>
</settings>

Proxy für m2e

Wenn man m2e benutzen möchte und hinter einem Proxy sitzt gibt es mindestens 4 relevante Konfigurationen:
  • Den Proxy in Eclipse unter
    Preferences - General - Network Connections
    einrichten
  • Den Proxy für Subclipse unter
    C:\Users\USERID\AppData\Roaming\Subversion
    einstellen
  • Den Proxy für m2e unter
    C:\Users\USERID\.m2\settings.xml
    einstellen

Vergisst man den Proxy für Subclipse kann man kein Maven Projekt über eine SVN URL importieren, vergisst man den Proxy für m2e gibt es folgende Fehlermeldung:
Project build error: Non-resolvable parent POM for …
29-09-2013 18.03

Eclipse

So kann man an ein jar das Javadoc anhängen: Das Projekte anklicken, Menü, Project, Properties, Libraries, [jar], aufklappen, javadoc location.

Shortcuts

downcase:
STRG SHIFT y
UPCASE:
STRG SHIFT x

Breakpoints

Breakpoints können nur den aktuellen Thread anhalten, oder gleich die ganze VM. Den Default kann man so festlegen
Preferences -> Java -> Debug -> [ Suspend Execution | Suspend Thread ]
In der Debug View kann man mit dem J! Symbol Brakepoints setzen, die nur bei Exceptions aktiv werden
Eclipse Java Exception Brakepoint

Code formatieren

Preferences -> Java -> Code -> Style -> Formater

Dort New anklicken und ein eigenes anlegen.

Mit
CTR SHIFT F

anwenden lassen

Eclipse stürzt ab

Das Eclipse Error Log liegt im Workspace Ordner und endet auf .log.

Eclipse 3.1.1 und PermGen zu klein? In der eclipse.ini das hier mal mit mehr Speicher probieren
--launcher.XXMaxPermSize 256m

Wenn Eclipse in Dialogen abstürzt, in denen man durch das lokale Dateisystem navigiert (File open...) hilft seltsamerweise der eclipse.exe explizit den Pfad zur Java Installation mitzugeben.
C:\Programme\eclipse\eclipse.exe -vm C:\Programme\Java\jdk1.6.0_24\bin\java.exe

Quellen mit einem JAR verknüpfen

Java Eclipse jar Quellcode verknüpfen

Eclipse @author

Eigentlich setzt Eclipse z.B. bei generierten Kommentare für neue Klassen automatisch eine @author Annoation. Allerdings ermittelt Eclipse dann je nach Systemkonfiguration nicht den richtigen Namen. So kann man das in der eclipse.ini reparieren

-Duser.name=John Doe (JD)

Java imports automatisch von Eclipse verwalten lassen

Wenn z.B. in einer Klasse Code benutzt, der einen Import erforderlich gemacht hat, und entfernt diesen Code in Eclipse, kann Eclipse den überflüssigen Import automatisch entfernen
Preferences - Java - Editor - Save Actions - Organize imports

Eclipse Plugins


Eclipse Plugin für hprof Dateien (Speicherverbrauch)

Eclipse Memory Analyzer Plugin (MAT)

Eclipse UML Plugins

The ObjectAid UML Explorer for Eclipse UML of Java class
eUML2

CodePro Analytix

CodePro Analytix User Guide Inhalt:
  • Similar Code Findet Codestellen die durch Copy & Paste kopiert wurden, selbst wenn sie danach leicht verändert wurden. Danach können diese Stellen dann z.B. in eine gemeinsame Methode ausgelagert werden.
  • Code Coverage Zeigt wie oft während eines Laufes welcher Teil des Codes durchlaufen wurde. Es ist sogar möglich die Häufigkeit der letzten Läufe zu vergleichen. Interessant z.B. um zu überprüfen, wie stark Unit Tests den Code durchdringen.
  • Metrics Berechnet Software Metriken
    Eclipse Metrics Plugin
    • Alternativ: Metrics Berechnet für den Code verschiedene Metriken und zeigt wo im Code entsprechende Richtwerte überschritten werden.
  • JUnit
  • Dependency Analysis
  • Code Audit
22-09-2012 13.00

Netbeans

build Ordner

Man kann in Netbeans kein vorhandenes Projekt importieren, wenn man es dort bereits einen build Ordner gibt.

Fehlermeldung:
Cannot place the project in a Project Folder that already contains "build" folder.

Workarround:
  • Den vorhanden Ordner build Ordner temporär umbennen
  • Das Projekt normal importieren
  • CTRL 2 drücken, Projekt aufklappen, nbproject, project.properties, build.dir, diesen Wert abändern
  • Temporär umbennaten buidl Ordner wieder build nennen
  • Fertig

JDK

So kann man das JDK in Netbean umstellen:
Rechtsklick auf das Projekt, Libraries (!), Java Platform.
Falls das JDK noch nicht eingerichtet wurde: Manage Platforms (es können nur JDK ausgewählt werden, keine JRE).

Falls das Source Level sich auch ändert (z.B. von 1.4 auf 1.6) geht das so:
Rechtsklick auf das Projekt, Sources, Source / Binary Format.
01-08-2011 01.17

Performancemessungen / Profiler


JRat

JRat
So startet man das zu messende Programm

java -javaagent:shiftone-jrat.jar ...

So kann man sich die Ergebnisse mit dem mitgelieferten Viewer ansehen

java -Xmx256M -jar shiftone-jrat.jar

JRat hatte allerdings Probleme mit Hibernate und Annotations.

JIP

JIP
So startet man das zu messende Programm

java -javaagent:[DIR]\profile.jar ...

Am einfachsten ist es, wenn [DIR] ein absoluter Pfad ist.

Andere Variante

java -javaagent:[DIR]\profile.jar -Dprofile.properties=[DIR2]\profile.properties

Auch hier ist es einfacher, wenn [DIR] und [DIR2] absolute Pfade sind.

Im Paket ist ein Beispiel für eine profile.properties enthalten. Damit man sich die Ergebnisse visualisieren lassen kann, muss man in der properties mindestens
output=both
setzen. Wenn man in der properties den Eintrag
file
auf einen Ordner zeigen lässt, dann wird jeder neue Lauf in eine neue Datei geschrieben.
Ebenfalls nützlich ist der Eintrag
output-method-signatures=yes

So kann man sich die Ergebnisse schließlich visualisieren lassen

java -jar jipViewer.jar [DIR3]/profile.xml
Wobei hier [DIR3] der Ordner ist, in den JIP die Messwerte Schreiben sollte.
22-08-2010 14.19

Common Object Request Broker Architecture (CORBA)

Wikipedia: Common Object Request Broker Architecture (CORBA)
Standard zur Programmiersprachen übergreifende Kommunikation, wird von der Object Management Group (OMG) verwaltet.

Die Kommunikationschnittstellen werden über die Interface Definition Language (IDL) definiert.
Syntax IDL:

Kleines CORBA Beispiel / CORBA Tutorial
Siehe auch

Man erzeugt als erstes eine IDL Datei, z.B. in eine Datei MyInterface.IDL

// package de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent
module de
{
module tgunkel
{
module JAVA
{
module CorbaDemo
{
module CorbaGeneratedContent
{
interface MyCorbaInterface
{
// Method which returns a String which says hello to your name
string sayHelloTo(in string name);

// Method which returns the sum of two numbers
long calculateAdd(in long number1, in long number2);

/*
* interface to store and retrieve strings
*
*/

// Our own exception with two attributes
exception NoMoreSpaceLeftError
{
unsigned long position;
string notStoredString;
};

// constant to define how many values we are allowed to store
const long MAX_ITEMS_TO_BE_STORED = 9;

// our own type to have sequence of Strings
typedef sequence<string> MyStringArrayType;

// store a new string, may throw an exception
void storeString(in string text) raises (NoMoreSpaceLeftError);

// get all stored values
MyStringArrayType restoreStrings();

};
};
};
};
};
};

Aus dieser kann man jetzt z.B. mit idlj (Bestandteil des Java JDK) Java Code erzeugen:

idlj -fclient MyInterface.IDL
idlj -fserver MyInterface.IDL
Oder beides gleichzeitig:
idlj -fall MyInterface.IDL

Jetzt implementiert man die Methoden aus der IDL und füllt sie mit dem gewünschten Verhalten:

package de.tgunkel.JAVA.CorbaDemo.Server;
import java.util.ArrayList;
import java.util.List;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterface;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterfacePOA;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterfacePackage.NoMoreSpaceLeftError;
public class MyCorbaInterfaceImpl extends MyCorbaInterfacePOA
{
private List<String> memory;

public MyCorbaInterfaceImpl()
{
memory=new ArrayList<String>();
}

@Override
public String sayHelloTo(String name)
{
return "Hello World dear '"+name+"'.";
}
@Override
public int calculateAdd(int number1, int number2)
{
return number1+number2;
}
@Override
public String[] restoreStrings()
{
String []strArray = new String[memory.size()];
memory.toArray(strArray);
return strArray;
}
@Override
public void storeString(String text) throws NoMoreSpaceLeftError
{
int newPosition=memory.size()+1;
if(newPosition>=MyCorbaInterface.MAX_ITEMS_TO_BE_STORED)
{
throw new NoMoreSpaceLeftError(newPosition, text);
}
memory.add(text);
}
}

Man braucht eine Klasse, die die Server Seite repräsentiert

package de.tgunkel.JAVA.CorbaDemo.Server;
import org.omg.CORBA.*;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POAManagerPackage.AdapterInactive;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterface;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterfaceHelper;
public class MyCorbaServerClass
{
public static String CORBA_PROJECT_NAME="HelloWorld";

public static void main(String[] args) throws InvalidName, AdapterInactive
{
try
{
// init ORB, pass arguments from the command line (if there are any)
ORB orb = ORB.init(args, null);
// this is the class which implements the methods defined in the IDL
MyCorbaInterfaceImpl myCorbaInterfaceImplRef = new MyCorbaInterfaceImpl();
// get the root PAO of the CORBA server
POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
rootpoa.the_POAManager().activate();
// Registriere Servant und erzeuge (CORBA) Objektreferenz
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(myCorbaInterfaceImplRef);
// convert it into Java objects
MyCorbaInterface href = MyCorbaInterfaceHelper.narrow(ref);
// register at CORBA nameservice
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
NameComponent path[] = ncRef.to_name(CORBA_PROJECT_NAME);
ncRef.rebind(path, href);
// start orb
System.out.println("Server is now running...");
orb.run();

} catch(Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
}
}

Jetzt startet man als erstes ordb (auch Bestandteil des JDK)
orbd -ORBInitialPort 900

Und dann kann man die MyCorbaServerClass Klasse schon starten.

Jetzt noch eine Client Klasse

package de.tgunkel.JAVA.CorbaDemo.Client;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterface;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterfaceHelper;
import de.tgunkel.JAVA.CorbaDemo.CorbaGeneratedContent.MyCorbaInterfacePackage.NoMoreSpaceLeftError;
public class MyCorbaClientClass
{
public static String CORBA_PROJECT_NAME="HelloWorld";
public static void main(String[] args)
{
try
{
// init ORB
ORB orb = ORB.init(args, null);
// get the Java object via the CORBA nameservice
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
NameComponent path[] = ncRef.to_name(CORBA_PROJECT_NAME);
MyCorbaInterface helloRef = MyCorbaInterfaceHelper.narrow(ncRef.resolve(path));
/*
* Play with it, call the remote CORBA methods:
*/
// let the CORBA server say hello to John
System.out.println(helloRef.sayHelloTo("John"));
// let the CORBA server calculate
System.out.println(helloRef.calculateAdd(42, 8));
// store some strings in the CORBA server
try
{
helloRef.storeString("First string");
helloRef.storeString("Another string");
String[] restoredStrings=helloRef.restoreStrings();
for(String s : restoredStrings)
{
System.out.println("Restored: "+s);
}
}
catch(NoMoreSpaceLeftError e)
{
System.err.println("Failed to store string '"+e.notStoredString+"' at position '"+e.position+"'");
}
} catch(Exception e)
{
System.out.println("ERROR : " + e);
e.printStackTrace(System.out);
}
}
}

Nachdem man über Corba eine Methode aufgerufen hat, ist die Frage, ob man überhaupt warten muss, bis die Methode von der Gegenseite abgearbeitet wurde.
Sofern die Methode einen Rückgabewert liefert, muss der Aufrufer natürlich warten. Ansonsten läuft nach meiner Beobachtung der Aufrufer auch einfach so weiter. Laut Dokumentation ist dafür aber eigentlich das oneway Schlüsselwort notwendig:
oneway void foo()
22-09-2012 11.37

Quartz

Quartz ist ein Framework, mit dem man zeitgesteuert Code ausführen lassen kann.

Quartz Logging

Quartz nutzt SLF4J. Zum Start
slf4j-api-?.jar und slf4j-simple-?.jar in den Klassenpfad aufnehmen. Letzteres kann man dann z.B. durch slf4j-log4j12-?.jar ersetzen, wenn man lieber log4j benutzen möchte.

quartz.properties
# This scheduler's name will be "MyScheduler".
org.quartz.scheduler.instanceName = MyScheduler

# Max Number of parallel threads
org.quartz.threadPool.threadCount = 5

# store jobs in RAM instead of a real DB
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Quartz Beispiele

Quartz Job:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class MySimpleJob implements Job
{
@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
...
}


}

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

import static org.quartz.JobBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.TriggerBuilder.*;

public class Main
{
...
// Grab the Scheduler instance from the Factory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

// and start it off
scheduler.start();

// the job shall be started 8 times
JobDetail job = newJob(MySimpleJob.class).withIdentity("job1", "group1").build();
SimpleScheduleBuilder sb=SimpleScheduleBuilder.repeatSecondlyForTotalCount(8);

// Trigger the job to run now, and then repeat every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(sb)
.build();

// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);

// give the processes time to finish
Thread.sleep(5*60*1000);

scheduler.shutdown();
...
}

JobDataMap

Man kann den neu angelegten Jobs noch Werte über eine eingebaute Map mitgeben. Diese Map wird bei Bedarf sogar mit dem Job zusammen persistiert (wenn die Werte serialisierbar sind).
JobDetail job = newJob(MySimpleJob.class)
.withIdentity("job1", "group1")
.usingJobData("MY_MESSAGE", "Hello World")
.build();

Und so können die Werte im Job dann wieder ausgelesen werden
@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
JobDataMap dataMap=jobexecutioncontext.getJobDetail().getJobDataMap();
String lMessage=dataMap.getString("MY_MESSAGE");
}

Falls es im Job Objekt Setter gibt, die wie ein Key aus der Map heißen, werden diese auch aufgerufen. z.B.
public void setMY_MESSAGE(String pValue) { ... }

Quartz Annotation

@DisallowConcurrentExecution
Der Job, der so annotiert wurde, darf nicht parallel zu einem anderen Job mit der gleichen Klasse laufen

Quartz Cron

Quartz Cron
/*
* Quartz Cron syntax
*
* Seconds Minutes Hours Day-of-Month Month Day-of-Week Year(optional)
*
* Day-of-Weeks:
* MON
* TUE
* WED
* THU
* FRI
* SAT
* SUN
* MON-FRI
* MON,WED,FRI
* MON-WED,SAT
* * (every day in the week)
* ? day of the week is not relevant
*
* Day-of-Month
* 1 first day in month
* L last day in month
* * any day in month
* ? day in month is not relevant
*
*/

// Grab the Scheduler instance from the Factory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// and start it off
scheduler.start();

JobDetail job1 = newJob(MySimpleJob.class)
.withIdentity("job1", "group1")
.build();

// Noon
String cronString_noon="0 0 12 ? * *";

// Noon on Wednesday
String cronString_noon_wednesday="0 0 12 ? * WED";

// Every 6 minutes of the hour (10:06, 10:12, ..., 10:54, 11:06, etc)
String cronString_every_6="0 0/6 * * * ?";

// Every 35 minute of the hour (10:35, 11:35, 12:35, etc)
String cronString_every_35="0 0/35 * * * ?";

Trigger trigger_noon = newTrigger()
.withIdentity("trigger_noon", "group1")
.withSchedule(cronSchedule(cronString_noon))
.build();

Trigger trigger_noon_wednesday = newTrigger()
.withIdentity("trigger_noon_wednesday", "group1")
.withSchedule(cronSchedule(cronString_noon_wednesday))
.build();

Trigger trigger_every_6 = newTrigger()
.withIdentity("trigger_every_6", "group1")
.withSchedule(cronSchedule(cronString_every_6))
.build();

Trigger trigger_every_35 = newTrigger()
.withIdentity("trigger_every_35", "group1")
.withSchedule(cronSchedule(cronString_every_35))
.build();

// Tell Quartz to schedule the job using our trigger
scheduler.scheduleJob(job1, trigger_noon);
scheduler.scheduleJob(job2, trigger_noon_wednesday);
scheduler.scheduleJob(job3, trigger_every_6);
scheduler.scheduleJob(job4, trigger_every_35);

Listeners

Es gibt
  • JobListener
  • SchedulerListeners

Job Stores

RAMJobStore

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

JDBCJobStore

Quartz herunterladen, unter docs/dbTables/ findet man dann für verschiedene DB Scripte um die Tabellen anzulegen, die Quartz für den JDBCJobStore benötigt. Diese Tabellen in der DB anlegen.
Man benötigt das c3p0 jar im Klassenpfad und JDBC Treiber für die DB, z.B. ojdbc6.jar für Oracle.

# Persist Quartz status into an Oracle DB, manage Oracle DB transactions
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

# Oracle
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myQuartzDataSource
org.quartz.jobStore.useProperties = false

# Configure Datasources
org.quartz.dataSource.myQuartzDataSource.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myQuartzDataSource.URL = jdbc:oracle:thin:@myComputer.example.com:1521:myDB
org.quartz.dataSource.myQuartzDataSource.user = MrFoo
org.quartz.dataSource.myQuartzDataSource.password = SuperSecretPW123
org.quartz.dataSource.myQuartzDataSource.maxConnections = 5
org.quartz.dataSource.myQuartzDataSource.validationQuery=select 0 from dual

misfireThreshold

Wie lange darf ein Job seine Ausführzeit verpassen bis sie als verpasst angesehen wird? Angabe in Milliseconden, Default ist 60.000 (1 Minute)
org.quartz.jobStore.misfireThreshold 60000

Quartz Exceptionhandling

@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException
{
try
{
...
}
catch(NullPointerException e)
{
JobExecutionException e_new=new JobExecutionException(e);
// permanent error, never try to execute this job again
e_new.setUnscheduleAllTriggers(true);
throw e_new;
}
catch(Exception e)
{
JobExecutionException e_new=new JobExecutionException(e);
// try to execute this job right way
e_new.refireImmediately();
throw e_new;
}
}



13-02-2012 00.26

Serialisierung

Eine kleine Testklasse, die serialisiert werden soll:

package de.tgunkel.JavaDemo.Serialize;

import java.io.Serializable;

public class PersistMe implements Serializable
{
private static final long serialVersionUID = 291L; // == 0x123

byte variableA=127; // == 0111 1111 == 0x7f
int variableB=1092; // == 0000 1000 1000 1000 == 0x0444
String variableC="Hallo Welt";
}

So kann man ein Objekt der Klasse speichern:
private void saveObject(String pFileName, PersistMe pDemo) throws FileNotFoundException, IOException
{
FileOutputStream fos = new FileOutputStream(pFileName);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(pDemo);
out.close();
}

So kann man ein Objekt der Klasse wiederherstellen:

private PersistMe readObject(String pFileName) throws FileNotFoundException, IOException, ClassNotFoundException
{
FileInputStream fos = new FileInputStream(pFileName);
ObjectInputStream in = new ObjectInputStream(fos);
PersistMe d = (PersistMe) in.readObject();
in.close();
return d;
}

Mit einem Hexeditor kann man in der Datei
00000000: aced 0005 7372 0027 6465 2e74 6775 6e6b  ....sr.'de.tgunk
00000010: 656c 2e4a 6176 6144 656d 6f2e 5365 7269 el.JavaDemo.Seri
00000020: 616c 697a 652e 5065 7273 6973 744d 6500 alize.PersistMe.
00000030: 0000 0000 0001 2302 0003 4200 0976 6172 ......#...B..var
00000040: 6961 626c 6541 4900 0976 6172 6961 626c iableAI..variabl
00000050: 6542 4c00 0976 6172 6961 626c 6543 7400 eBL..variableCt.
00000060: 124c 6a61 7661 2f6c 616e 672f 5374 7269 .Ljava/lang/Stri
00000070: 6e67 3b78 707f 0000 0444 7400 0a48 616c ng;xp....Dt..Hal
00000080: 6c6f 2057 656c 74 lo Welt

dann relativ leicht die Informationen des Objektes wiederfinden:

Klassenname:
6465 2e74 6775 6e6b 656c 2e4a 6176 6144 656d 6f2e 5365 7269 616c 697a
652e 5065 7273 6973 744d 65
d e . t g u n k e l . J a v a D e m o . S e r i a l i z e
. P e r s i s t M e

serialVersionUID:
01 23
291

Variablennamen:
4200 0976 6172 6961 626c 6541 
B v a r i a b l e A

4900 0976 6172 6961 626c 6542
I v a r i a b l e B

4c00 0976 6172 6961 626c 6543 7400 124c 6a61 7661 2f6c 616e 672f 5374
7269 6e67
L v a r i a b l e C L j a v a / l a n g / S t r
i n g


Variablenbelegung:
7f 
127

0444
1092

48 616c 6c6f 2057 656c 7
H a l l o W e l t

Serialisierung Links

07-09-2014 02.12

Java 7

Was ist eigentlich neu in Java 7?

Lesbare Konstanten

Konstanten können mit _ lesbarer gemacht werden und es ist möglich Binärkonstanten zu verwenden:

// make constant more readable
int one_million = 1_000_000;
int oneMillion = 1000000;
boolean equal=(one_million==oneMillion);

// add a binary constant 0b ...
int binaryNine=0b1001;
int nine=9;
boolean equal=(nine==binaryNine);

Switch mit Strings

In einem Switchblock können Strings verwendet werden

final String JOHN="john";
String result="String switch says the user is ";

switch(aString)
{
case "Foo":
result+="Mr. Foo";
break;
case "Bar":
result+="Mr. Bar";
break;
case JOHN:
result="John";
break;
default:
result="a surprise";
}

Diamond Operator

Es ist nicht mehr notwendig, den Datentyp bei der Instanziierung zu wiederholen

// pre Java 1.7
HashMap<Integer, String> prejva17=new HashMap<Integer, String>();

// Java 1.7
HashMap<Integer, String> products=new HashMap<>();
products.put(123456, "Gigant TV");
products.put(1, "DVD");

Mehr als eine Exception fangen

Man kann jetzt mehr als eine Exception auf einmal fangen und bearbeiten

try
{
if(bang==0)
{
throw new IllegalArgumentException();
}
else
{
throw new IllegalStateException();
}
}
// catch more than one exception at once
catch(IllegalArgumentException | IllegalStateException e)
{
System.out.println("got exception "+e);
}

Resourcen Management

Bisher war es recht aufwendig mit Ressourcen umzugehen, die auch wieder geschlossen werden müssen

// the pre Java 1.7 way
FileOutputStream fos=null;
try
{
fos=new FileOutputStream(filename);
// ...
}
catch (FileNotFoundException e)
{
e.printStackTrace();
// ...
throw new RuntimeException(e);
}
/* You needed a finally block to make sure your closeable resource
* is closed under all circumstances
*/
finally
{
try
{
if(fos!=null) fos.close();
} catch (IOException e)
{
e.printStackTrace();
// ...
throw new RuntimeException(e);
}
}

Jetzt können dieses Ressourcen automatisch geschlossen werden, wenn sie java.io.Closeable implementieren und innerhalb eines try Statements definiert und erzeugt werden:

/* a variable of a (sub) type of Closeable
* inside a try will automatically issue close()
* when the variable reaches its end of lifetime.
* Don't forget that even the implicit close()
* may issue an exception
*/
try(Closeable fos=new FileOutputStream(filename))
{
// ...
}
catch (IOException e) {
e.printStackTrace();
// ...
throw new RuntimeException(e);
}

Java 7 Links

17-11-2012 12.28

Software für Android entwickeln

http://developer.android.com/training/basics/firstapp/index.html

Android Entwicklungsumgebung installieren

Android SDK

Das Android SDK herunterladen. Nach dem Download zieht das noch unvollständige SDK den Rest via Internet:
Windows: Doppelklick auf SDK Manager.exe
Linux: cd tools/; android sdk

Eclipse Plugin

In einem aktuellen Eclipse via Help, Install new Software, den Link zum ADT Plugin von der Seite einfügen.

Fehler:
requires 'org.eclipse.wst.sse.core 0.0.0' but it could not be found

Für die Installation des Plugins einmalig Eclise als root / Administrator starten.

Nach erfolgreicher Installation wird man dann nach dem Android SDK gefragt und verweist auf die oben erfolgte Installation.

Fehler:
onclick must override ...

In Eclipse auf Java 1.6 umstellen
Einstellungen, Java, Compiler, Level: 1.6

Zielgerät

Wenn man den Code ausführen möchte, muss man entweder ein echtes Gerät per USB anschließen, oder ein emuliertes anschließen.
06-12-2012 18.42

Java Tipps und Tricks

Wie man Objekte erzeugt

Statische Factory Methoden

Es hat Vorteile in einer Klasse statt oder zusätzlich zu einem Konstruktor eine statische Factory Methode anzubieten.
  • hat einen sprechenden Namen
  • müssen nicht unbedingt ein neues Objekte erzeugen, z.B. muss es von Boolean nur zwei Instanzen geben
  • können auch einen anderen Typ zurückliefern (z.B. einen Subtypen)
  • Vor Java 1.7 ersparen sie auch Tippaufwand weil beim new Aufruf die Generics des Typen wiederholt werden müssen (siehe Diamon Operator)

Aber auch einige Nachteile
  • Ohne Konstruktoren kann von man einer Klasse nicht erben
  • Static Factory Methoden sehen aus wie normale static Methoden, Konstruktoren sind dafür immer als solche zu erkennen

Das ist nicht genau das Gleiche wie das Factory Pattern.

Viele optionale Parameter für den Konstruktor

Man hat für eine Klasse sehr viele oder optionale Parameter für den Konstruktor.
In diesem Fall kann man Telescoping Konstruktoren schreiben (verschieden Kontruktoren mit allen benötigten Kombinationen an Parametern). Das ist aber schreibaufwendig und schwer zu warten und zu verstehen (für den Benutzer unterscheiden sich die Kontruktoren nur durch die Typen der Paramter).
Alternativ könnte man nur für die immer erforderlichen Parameter einen Konstruktor anbieten und restlichen per Setter nachfüllen. Alledings ist das Objekt dann zeitweise in einem nicht fertigen Zustand und es ist durch die Setter immer veränderbar (häufig sind Objekte, die nach der Erzeugung nicht mehr verändert werden können sehr vorteilhaft).
Also nutzt man das Builder Pattern.
Dazu erzeugt man ein Hilfsobjekt aus einer Builder Klasse über deren Konstruktor und übergibt diesem alle erforderlichen Parameter. Zusätzlich hat die Builder Klasse noch Setter, die die optionalen Parameter setzen. Die eigentliche Klasse hat dann nur noch einen Konstruktor, der als Parameter die Hilfsklasse erwartet und sich aus ihr alle Paramter zieht. Liefern die Setter noch das Builder Objekt zurück, kann man den Builder sehr lesbar füllen. Außerdem hat die Builderklasse noch eine build() Methode, in der sie den Konstruktor der eigentlichen Klasse mit sich selbst als Argument aufrufen. Wenn die Builder Klasse eine innere Klasse der eigentlichen Klasse ist, kann der Konstruktor der eigentliche Klasse private werden und man muss den Builder nutzen. In der build() Methode kann man dann auch testen, ob alle Argumente sinnvoll gefüllt sind.

Foo f=new Builder(a,b,c).setOptionalD(d).setOptionalE(E).build();

Klasse von der es keine Instanz geben soll

Klasse bekommt einen private Konstruktor, der sicherheitshalber noch eine Exception wirft. Damit kann man von der Klasse allerdings auch nicht erben.

Singleton

Der Konstruktor ist private und damit von aussen nicht erreichbar, es gibt eine von außen abzufragende instance Variable, die irgendwann mal initial mit einem Objekt der Klasse initialisiert wird. Es wird also nur genau diese eine Instanz der Klasse geben und keine zweite. Der Konstruktor kann intern noch mal testen, dass er nicht schon mal eine Instanz erzeugt hat falls doch jemand über Reflektion an den privaten Konstruktor gekommen ist.

public class S
{
public static final S INSTANCE=new S();

private S()
{
...
}

public void doSomething() { ... }

}

Etwas flexibler ist die Variante die Instanz über einen Getter zu ermitteln

public class S
{
private static final S INSTANCE=new S();

public static S getInstance() { return INSTANCE; }

private S()
{
...
}

public void doSomething() { ... }
}

Achtung, wenn die Singleton Klasse serialisierbar sein soll wird beim Einlesen wird ohne einen Eingriff ein neues Objekt erzeugt. Also readResolve() überschreiben!

Die beste Variante für einen Singelton geht über ein Enum:

public enum S
{
INSTANCE;

public void doSomething() { ... }
}

Unnötige Objekterzeugung vermeiden


String s=new String("Hello World");
String s= "Hello World";

public void foo()
{
Calculator calc=new Calculator(...);
return calc(x);

return this.calc(c);
}

Achtung bei Autoboxing
Long i;
long i;
for(i=0; i<MAX; i++)

Nicht mehr benötigte Objektreferenzen

Bei Klassen, die folgendes beinhalten
  • einen eigenen Speicher
  • einen eigenen Cache
Muss man aufpassen, dass man nicht mehr benötigte Referenzen auf Objekte nicht dauerhaft behält. Ein Beispiel ist z.B. eine Stack Implementierung, die beim Entfernen eines Eintrages zwar die Nummer des höchstens Eintrages reduziert, aber nicht das freigewordene Objekt im Stackspeicher freigibt (also z.B. mit null überschreibt).
Auch Callbacks (z.B. Listener) sollte man wieder abhängen.


finalize()

finalize() wird aufgerufen, wenn der Garbage Collector ein Objekt wegräumt. Wann und ob das jemals passiert ist aber nicht sicher vorhersagbar, also nicht benutzen. Außerdem hat es einen Performance Verlust zur Folge. Statt dessen eine eigene Methode anbieten, die man manuell aufrufen muss.

Methoden die alle Objekte haben

equals

Siehe auch Java Gleichheit.

Equals zu überschreiben ist komplizierter als es aussieht. In folgenden Fällen sollte man es besser nicht überschreiben
  • Ein Objekt ist nur zu sich selbst (der selben Instanz, gleiche Adresse im Speicher) gleich (das leistet die equals Implementierung per Default)
  • Ein Test auf logische Gleichheit wird nicht benötigt
  • Unsere Vaterklasse implemtiert bereits ein equals und das ist auch für uns richtig

Falls man equals doch selbst implementieren möchte muss man das hier auf jeden Fall erfüllen

  • Reflexivität
    assertTrue(x.equals(x));
  • Symmetrie
    if(x!=null && y!=null) assertTrue(x.equals(y)==y.equals(x));
    Verletzt man leicht, wenn man versucht Objekte von verschiedenen Typen vergleichbar zu machen.
  • Transitivity
    if(x!=null && y!=null && z!=null) if(x.equals(y) && y.equals(z)) assertTrue(x.equals(z));
    Man kein keine Klasse von der es Instanzen geben kann mit Equals relevanten Attributen beerben und dabei weiterer solcher Attribute hinzufügen ohne hiergegen (oder gegen eine der anderen Regeln) zu verstossen. Also entweder abstrakte Vaterklassen oder die neue Klasse beinhaltet eine Instanz der alten Klasse.
  • Konsistenz
    Wiederholte Aufrufe von equals für unveränderte x,y sollten auch das gleiche Ergebnis liefern.
    Verletzt man vielleicht wenn man externe Resourcen für den Vergleich abfragt, die sich einfach ändern können.
  • Null
    if(x!=null) assertFalse(x.equals(null));
    D.h. keine Exception werfen! Ein expliziter Test auf null ist nicht notwendig wenn man schon mit instanceof testet, das liefert bei null auch falsch.

Achtung: hashCode() muss auch überschrieben werden, wenn equals überschrieben wird!

hashCode

Wenn zwei Objekte laut equals() gleich sind, muss auch der hashCode gleich sein.
Umgekehrt können zwei Objekte natürlich den gleichen hashCode haben, auch wenn sie gar nicht gleich sind (und equals entsprechend false liefern würde).
Während eines Programmlaufes darf sich der hashCode nicht ändern außer das Objekt wird in relevanten Attributen verändert.

Aus einem long einen int hashCode zu bauen
Long lng=...
int hash= (int) (lng ^ (lng >>> 32))
Dabei schiebt man den Long Wert erst um 32 Bit nach rechts:
lng >>> 32
Damit sind die oberen 32 Bits leer geworden, deren Inhalt steht jetzt in den unteren 32 Bits. Das verbindet man jetzt per XOR mit den ursprünglichen unteren 32 Bits und schreibt es in die unteren 32 Stellen
lng  ^ (lng >>> 32)
Schneidet man die oberen 32 Stellen jetzt noch einfach ab
(int) (lng  ^ (lng >>> 32))
Dann hat man 32 Bit die aus einer Mischung aus den oberen und unteren 32 Bit der Long Zahl bestehen.

toString()

Man sollte immer toString() überschreiben und alle relevanten Informationen (möglichst selbsterklärend) mit ausgeben. Erleichtert Debug und Fehlersuche enorm.

Falls man sich darauf einlassen will, dass das Format geparst werden können soll, ist es gut eine statische Methoden für die hin und her Konvertierung anzubieten.
Auf jeden Fall sollten die im toString() enthaltenen Informationen auch über direkte Methoden erreichbar sein damit niemand gezwungen ist, die Information durch Parsen zu ermitteln.

clone

Die Erwartungen an eine clone() Methode in Java sind normalerweise
foo.clone()!=foo;
foo.clone().getClass()==foo.getClass();
foo.clone().equals(foo);

In der Klasse Object ist eine generische clone() Methode implementiert:

protected native Object clone() throws CloneNotSupportedException;

Diese Methode ist außerhalb einer Klasse nicht erreichbar (nur protected) und muss erst mal verfügbar gemacht werden:

@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}

Allerdings wird jeder Aufruf der clone() Methode mit einer CloneNotSupportedException Exception quittiert, bis man das Interface Cloneable implementiert hat.

Da die Methode ein Objekt vom Typ Object zurückgibt, muss jeder Nutzer das Ergebnis auf den richtigen Typ casten. Solange jede clone() Methode das Objekt zurückgibt, welches die clone() Methode des Vaters zurückgegeben hat (bis hoch zur clone() Methode in Object) ist das Ergebnis (ab Java 1.5) aber vom selben Typ wie wir selbst. Der Rückgabetyp kann also einfach unsere Klasse sein.

Was leistet die clone() Methode in der Klasse Object für verschiedene Variablentypen?

Für Basistypen
long long_basic;
wird der Inhalt der Basistypen kopiert. Hier ist kein weiterer Eingriff notwendig.

Für echte Objekte
Long          long_object;
MyValue object_with_value;
wird nur die Referenz auf den Ort im Speicher kopiert, wo sich das Objekt befindet. Der Klon zeigt also genau auf dasselbe Objekt wie die Vorlage. Das ist dann ein großes Problem, wenn man den Inhalt des Objektes ändern kann. Long bietet z.B. keine Methoden um den Wert einer Long Variable zu ändern, beliebige andere Klassen aber natürlich schon. Ändert man dann den Wert eines solchen Objektes, ändert man es natürlich auch für alle Klone mit. Wenn das nicht gewünscht ist, muss man in der clone() Methode auch diese Objekte duplizieren.

Für Arrays
MyValue[]     array;
zeigen Klon und Original denselben Array im Speicher, Änderungen an dem Array haben Auswirkungen auf alle Klone. Dafür bietet jeder Array in Java ebenfalls eine clone() Methode, mit der man einen neuen Array erhält, der denselben Inhalt hat wie der original Array. Auch wenn man dann einen neuen Array hat, zeigen die Objekte im Array aber weiterhin auf dieselben Objekte. Will man das verhindern, muss man für alle Objekte im Array gegebenenfalls wieder clone() aufrufen.

Für Container
public List<MyValue> list;
gibt manchmal keine clone() Methode, List hat z.B. keine clone() Methode definiert, ArrayList hingegen schon. Einfache Lösung, statt clone(), einen neuen Container erzeugen und mit dem Inhalt des alten Containers füllen:
list=new ArrayList<MyValue>(list);
Allerdings zeigen auch hier die Einträge in der Liste auf dieselbe Stelle im Speicher, wie in der original Liste. Auch hier muss man also für die Objekte im Container gegebenenfalls wieder clone() aufrufen.
Wenn das zu klonende Objekt ein Interfacetyp hat, sich selbst fragen, ist das neue konkrete Objekt, welches das Interface implementiert, vom selben Typ wie das alte konkrete Objekte (z.B. ArrayList vs LinkedList). Falls nein, ist das ein Problem?

Beispiel
public class CopyMe implements Cloneable
{
public long long_basic;
public Long long_object;
public MyValue object_with_value;
public MyValue[] array;
public List<MyValue> list;

public CopyMe()
{
}

@Override
public CopyMe clone()
{
try
{
CopyMe result=(CopyMe) super.clone();

result.object_with_value=object_with_value.clone();

result.array=array.clone();
for(int i=0; i<array.length; i++)
{
result.array[i]=array[i].clone();
}

result.list=new ArrayList<MyValue>(list);
for(int i=0; i<list.size(); i++)
{
result.list.set(i, list.get(i).clone());
}
return result;
}
catch(CloneNotSupportedException e)
{
// this should never happen, as we implement Cloneable
throw new IllegalStateException("This class needs to implement Cloneable! "+this.getClass(), e);
}
}
}

Falls der Fokus der Klasse darauf liegt, dass man von Ihr erbt, und die Erben geklont werden können sollen, sollte man clone() auch überschreiben, protected lassen, CloneNotSupportedException werfen und Cloneable nicht implementieren
public class Father
{
@Override
protected Father clone() throws CloneNotSupportedException {
Father result=super.clone();
...
return result;
}
}

Probleme / Einschränkungen
  • alle Vaterklassen müssen clone() richtig implementiert
  • final Attribute können in der clone() Methode nicht überschrieben werden um sie zu duplizieren
  • man sollte in der clone() Methode keine Methoden des neuen Klons aufrufen, die nicht private oder final sind (weil es sonst in einem Erben überschrieben worden sein könnte)
  • Object.clone() ist nicht synchronized, also selbst absichern
  • Achtung, manchmal müssen beim clonen auch Inhalte verändert werden (z.B. IDs)

Alternativen:
Am besten nie Cloneable implementieren und nie clone() überschreiben. Statt dessen

Copy Constructor
public CopyMe(CopyMe pOriginal) { ... }

Oder Copy Factory
public static CopyMe getACopy(CopyMe pOriginal) { ... }

Comparable

Die Klasse implementiert Comparable<TYPE> und überschreibt die Methode compareTo(TYPE t)

Dabei gilt:

foo.compareTo(bar) istdann ist
<0foo<bar
>0foo>bar
==0beide haben die gleiche Position



Es müssen folgende Regeln eingehalten werden:
Richtung darf keine Rolle spielen:
a.compareTo(b)<0 dann b.compareTo(c)>0
a.compareTo(b)>0 dann b.compareTo(c)<0
a.compareTo(b)==0 dann b.compareTo(c)==0
a.compareTo(b) wirft Exception dann wirft auch b.compareTo(a) Exception

Transitivität
z.B. a.compareTo(b)>0, b.compareTo(c)>0 dann auch a.compareTo(c)>0

Gleiche verhalten sich gleich
Wenn x.compareTo(y)==0 müssen beide im Vergleich mit bel. anderen Objekten auch ein inhaltliches gleiches compareTo Ergebnis liefern.
x.compareTo(a) und y.compareTo(a) müssen sich also für alle a entsprechen.

Wenn man Comparable implementiert ist es oft sehr störend, dass man dann als Parameter jede beliebige andere Klasse akzeptieren muss. So kann man es nur für eine Bestimmte Klasse implementieren
public class Foo implements Comparable<Foo>
{
public int compareTo(Foo pOther)
{
}
}

Equals vs Comparable
Es wird empfohlen dass compareTo genau dann 0 liefert, wenn equals auch true liefert.

Vergleiche auch Comparator
Siehe auch Sortieren von Datencontainern.


06-12-2012 18.52
Powered by PHP Created with Xemacs Valid XHTML 1.0! Valid CSS!