5 Ocak 2021 Salı

Lombok @SneakyThrows Anotasyonu

Giriş
Checked exception'ları RuntimeException ile sarmalar. Açıklaması şöyle
A common critique of Java is the verbosity created by throwing checked exceptions. Lombok has an annotation to remove the need for those pesky throws keywords: @SneakyThrows. As you might expect, the implementation is quite sneaky. It does not swallow or even wrap exceptions into a RuntimeException. Instead, it relies on the fact that at runtime, the JVM does not check for the consistency of checked exceptions. Only javac does this. So Lombok uses bytecode transformations to opt out of this check at compile time.
Üretilen Kod
Şuna benzer
@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    // No Errors
}
Neden Çalışıyor
Language specification section 18.4 için açıklama şöyle
… Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, Exception, Throwable, and Object, then Ti = RuntimeException
Bu şu anlama gelir. T tipi Throwable olarak tanımlandığı için RuntimeException olarak anlamlandırılıyor.
This exact case applies to sneakyThrows, It states that if the type’s only upper bound is almost Exception, Throwable, and Object, then T will be inferred to be a RuntimeException as per the specification, so it compiles.
Örnek
Şöyle yaparız. Burada checked exception olan Exception, RuntimeException ile sarmalanıyor
public class SneakyThrows {
@SneakyThrows public void sneakyThrow() { throw new Exception(); } }
Örnek
Şöyle yaparız. Burada  checked exception olan ParseException, RuntimeException ile sarmalanıyor
@SneakyThrows
public static Date parseDate(String dateStr) {
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  return format.parse(dateStr);
}
Aslında kodu şu hale getiriyor
public static Date parseDate(String dateStr) {
  try {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    return format.parse(dateStr);
  } catch (ParseException e) {
    throw new RuntimeException(e); 
  }
}
value Alanı
Fırlatılmasını istediğimiz exception belirtilebilir.

Örnek
Şöyle yaparız. Burada kod IOException fırlatıyor. Biz de yine aynısı fırlatılsın istiyoruz ama metod imzasında bu exception kullanılsın istemiyoruz.
@SneakyThrows(IOException.class)
void throwException(String a) {
  ...
  throw new IOException();
}

Hiç yorum yok:

Yorum Gönder