Strona główna > Java > Konstrukcja try inaczej

Konstrukcja try inaczej

Sposób na przedstawienie inaczej tego co jest wyrażana za pomocą konstrukcji try. Normalnie try w całej okazałości prezentuje się tak:

try {
   // wykonywane w try
} catch (NullPointerException e) { 
   // wykonywane w catch, w tym przypadku dla NullPointerException 
} finally { 
   // wykonywane w finally 
}

A ostatnio wpadłem na sposób jak można to zrobić zastępując całość specjalnym obiektem. W kodzie wygląda to jak poniżej:

// deklaracja
OtherTry otherTry = new OtherTry();
otherTry.addCatchBlock(new CatchBlock<NullPointerException>() {
    public void doWith(NullPointerException e) {
        // wykonywane w catch, w tym przypadku dla NullPointerException 
    }
});
otherTry.addFinallyBlock(new FinallyBlock() {
    public void doIt() {
        // wykonywane w finally 
    }
});
// użycie
otherTry.start();
    // wykonywane w try
otherTry.close();

Jest to trochę „sztuka dla sztuki”🙂 choćby z powodu tego że zapis jest bardziej rozwlekły. Choć obiekt można zdefiniować tylko raz i potem używać w wielu miejscach (wtedy to tylko 2 linijki).
Całość ma jednak jedną wadę: nie zadziała z checked exception (kompilator nie pozwoli, i trzeba użyć starego try_a).

Ciekawej jest to, że można takie dziwo wyprodukować. W przypadku wyjątku pożądany kod obsługi się wykona, i jeszcze można zdefiniować sekcje finally. Możliwe jest to poprze dobranie się do bieżącego wątku i czasowe zmodyfikowanie domyślnego sposobu w jaki obsługiwane są nieprzechwycone wyjątki.

Klasa która to robi:

public class OtherTry {
	
	@SuppressWarnings("rawtypes")
	Map <Class,CatchBlock> catchBlock = new HashMap<Class, CatchBlock>();
	UncaughtExceptionHandler currentUncaughtExceptionHandler;
	FinallyBlock finallyBlock;
	
	public <E extends Throwable> void addCatchBlock(CatchBlock<E> value) {
		Class key = getKey(value);
		if (key != null) {
			catchBlock.put(key, value);
		}
	}
	
	public void addFinallyBlock(FinallyBlock value) {
		this.finallyBlock = value;
	}

	public void start(){
		Thread currentThread = Thread.currentThread();
		currentUncaughtExceptionHandler = currentThread.getUncaughtExceptionHandler();
		currentThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			public void uncaughtException(Thread t, Throwable e) {
				executeFinally();
				if (catchBlock.containsKey(e.getClass())){
					CatchBlock<Throwable> curentCatchBlock = catchBlock.get(e.getClass());
					if (curentCatchBlock != null) {
						try {
							curentCatchBlock.doWith(e);
						} catch (Throwable e2) {
							currentUncaughtExceptionHandler.uncaughtException(t, e2);
						}
						return;
					}
				}
				currentUncaughtExceptionHandler.uncaughtException(t, e);
			}
		});
	}
	
	public void close(){
		Thread.currentThread().setUncaughtExceptionHandler(currentUncaughtExceptionHandler);
		executeFinally();
	}

	private <E extends Throwable> Class getKey(CatchBlock<E> value) {
		Type[] type = value.getClass().getGenericInterfaces();
		Class key =  null;
		if (type.length == 1) {
			key =  (Class)((ParameterizedType)type[0]).getActualTypeArguments()[0];
		}
		return key;
	}
	
	private void executeFinally() {
		if (finallyBlock != null) {
			finallyBlock.doIt();
		}
	}
	
	public interface CatchBlock<E extends Throwable> {
		void doWith(E e);
	}
	
	public interface FinallyBlock {
		void doIt();
	}
}

Kategorie:Java Tags: ,
  1. Brak komentarzy.
  1. No trackbacks yet.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

%d bloggers like this: