Java Enum – Das bessere Singleton

Das Singleton Pattern ist wohl eines der verbreitetsten Design Pattern in der Java Welt. Umso cooler ist es, dass sich Mithilfe einer Enum, ein Singleton erheblich einfacher implementieren lässt.

Vorteile

  • Weniger Code und bessere Lesbarkeit.
  • Enum Singleton kümmern sich um die Serialisierung.
  • Die Erstellung einer Enum Instanz ist Thread-safe.

Implementierung mit Enum

/*
* Singleton Pattern mit Enum
*/

public enum EasySingleton {
   INSTANCE;

   public String sayLala() {
      return "Lala";
   }
}

Aufruf einer Methode des Singletons:

EasySingleton.INSTANCE.sayLala();

Implementierung ohne Enum

/*
* Singleton Pattern ohne Enum
*/

public class EasySingleton {
   private static EasySingleton me = null;

   private EasySingleton() {}

   public static synchronized EasySingleton getInstance() {
      if (me == null) {
         me = new EasySingleton();
      }
      return me;
   }

   public String sayLala() {
      return "Lala";
   }
}

Aufruf einer Methode des Singletons:

EasySingleton.getInstance().sayLala();

Mehr zu dem Thema: http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html#ixzz3tSa2Bfnj

Advertisements

Top 10 der verborgenen Features von Java

1. Double Brace Initialization

Dieses Feature ist sehr praktisch, denn es vereinfacht die Initialisierung einer Map und eines Sets. Du erahnst sicher, dass dieses Feature Arbeit im Alltag eines Java-Programmierers erspart.

Wie im folgenden Beispiel zu sehen ist, kann im Aufruf des Konstruktors innerhalb von doppelte geschweiften Klassen (Double Braces) Methoden der erzeugte Instanz aufgerufen werden.

private static final Set<String> VALID_CODES = new HashSet<String>() {{	 	 

 add("XZ13s");	 	 

 add("AB21/X");	 	 

 add("YYLEX");	 	 

 add("AR2D");	 	 

 }};
private static final Set<String> VALID_CODES = new HashSet<String>();	 	 

static {	 	 

 validCodes.add("XZ13s");	 	 

 validCodes.add("AB21/X");	 	 

 validCodes.add("YYLEX");	 	 

 validCodes.add("AR2D");	 	 

}	 	 

Das funktioniert natürlich bei allen Instanzierungen, jedoch ist es bei einer Map oder Sets besonders praktisch, da das Erzeugen und die Initialisierung einer ArraysList mit folgenden Aufruf noch kompfortabler als mit der Double Brace Initialisation ist.

public static <T> List<T> asList(T... a)	 	 

Es soll nicht unerwähnt bleiben, dass Kritiker die „Double Brace Initialisation“ als Anit-Pattern bezeichnen (Anti Pattern – Double Brace Initialisation).

2. instanceof Operator überprüft auf null

null instanceof String; // false und KEINE NullPointerException

Über dieses Verhalten des instanceof Operators sollte man sich im klaren sein. Denn eine ideale Verwendung des Operators macht den Code etwas schmaler und reduziert potentielle Fehler.

  • Eine != null Bedingung wird in folgenden Szenario überflüssung
if ((obj != null) && (obj instanceof String) // null Check überflüssig!	 	 

if (obj instanceof String) // Kürzer und null Check bereits enthalten!

3. Joint union in type parameter variance

public static <A, B extends Collection<A> & Comparable<B>>	 	 

boolean foo(B b1, B b2, A a) {	 	 

 return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);	 	 

}

Mit der sogenannten „Joint union in type parameter variance“ können Typen definiert werden, die mehrere Interfaces implementieren müssen. In den obigen Beispiel müssen die beiden Parameter vom Typ B die beiden Interfaces Collection und Comparable implementieren.

4. enums können beliebige Methoden haben

public enum Direction {	 	 

 NORTH, SOUTH, EAST, WEST;	 	 

 private Direction opposite;	 	 

 static {	 	 

 NORTH.opposite = SOUTH;	 	 

 SOUTH.opposite = NORTH;	 	 

 EAST.opposite = WEST;	 	 

 WEST.opposite = EAST;	 	 

 }	 	 

 public Direction getOppositeDirection() {	 	 

 return opposite;	 	 

 }	 	 

}

5. enums können Interfaces implementieren

public interface Operator {	 	 

 int apply (int a, int b);	 	 

}	 	 

public enum SimpleOperators implements Operator {	 	 

 PLUS { 	 	 

 int apply(int a, int b) { return a + b; }	 	 

 },	 	 

 MINUS { 	 	 

 int apply(int a, int b) { return a - b; }	 	 

 };	 	 

}

6. Anonyme Subklassen Implementierung

Object obj = new Object() {	 	 

 void foo(String s) {	 	 

 System.out.println(s);	 	 

 }	 	 

}	 	 

System.out.println(obj.class); // Object$1	 	

7. Anonyme Subklassen implementieren und aufrufen

new Object() {	 	 

 void foo(String s) {	 	 

 System.out.println(s);	 	 

 }	 	 

}.foo("Hello");	 	 

8. type parameter können beim Methoden-Auruf von generischen Methoden direkt angegeben werden

Collections.<String,Integer>emptyMap()

9. covariant return types

Duch diese Eigentschaft kann eine Methode eine ArrayList zurück geben, die eine Methode der Basisklasse überschreibt, die jedoch eine List zurück gibt. Dazu ein kleines Beispiel:

public interface Listener {	 	 

 List<Integer> getAll();	 	 

}	 	 

public class ListenerImpl implements Listener {	 	 

 @Override	 	 

 public ArrayList<Integer> getAll() {	 	 

 return null;	 	 

 }	 	 

}

10. Labeled Blocks

Dieses Sprachelement ist mindestens so überraschend wie unbrauchbar. Ich lasse mich aber gerne eines besseren belehren.

// code goes here	 	 

getmeout:{	 	 

 for (int i = 0; i < N; ++i) {	 	 

 for (int j = i; j < N; ++j) {	 	 

 for (int k = j; k < N; ++k) {	 	 

 //do something here	 	 

 break getmeout;	 	 

 }	 	 

 }	 	 

 }	 	 

}