Java 8'de istisna türü çıkarımın kendine özgü bir özelliği


85

Bu sitede başka bir cevap için kod yazarken şu tuhaflıkla karşılaştım:

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
  nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static <T extends Throwable> void nonSneakyThrow(T t) throws T {
  throw t;
}

İlk olarak, sneakyThrowaramanın neden derleyici için uygun olduğu konusunda oldukça kafam karıştı . TDenetlenmemiş bir istisna türünden hiçbir yerde bahsedilmediği zaman, hangi olası tür için sonuç çıkardı ?

İkincisi, bunun işe yaradığını kabul ederek, derleyici neden nonSneakyThrowaramadan şikayet ediyor ? Birbirlerine çok benziyorlar.

Yanıtlar:


66

T'nin sneakyThrowolduğu anlaşılır RuntimeException. Bu, tür çıkarımındaki dil spesifikasyonundan takip edilebilir ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html )

İlk olarak 18.1.3 bölümünde bir not var:

Formun bir throws αsınırı tamamen bilgi amaçlıdır: çözünürlüğü, α'nın somutlaştırılmasını optimize etmeye yönlendirir, böylece mümkünse, kontrol edilen bir istisna türü olmaz.

Bu hiçbir şeyi etkilemez, ancak bizi özel bir durumla çıkarılan istisna türleri hakkında daha fazla bilgi içeren Çözüm bölümüne (18.4) işaret eder:

... Aksi halde, ciltli set içeriyorsa throws αive αi uygun üst sınırları, en fazla olan Exception, Throwableve Objectdaha sonra Ti = RuntimeException.

Bu durum için geçerlidir sneakyThrow- tek üst sınır Throwable, yani spesifikasyona göre Tolduğu sonucuna RuntimeExceptionvarılır, böylece derlenir. Yöntemin gövdesi önemsizdir - denetlenmemiş dönüştürme, çalışma zamanında başarılı olur çünkü gerçekte gerçekleşmez ve derleme zamanı denetlenen istisna sistemini yenebilecek bir yöntem bırakır.

nonSneakyThrowBu yöntem en olarak derleme değil Tbir alt sınırı var Exception(yani Tbir üst tip olmalı Exceptionveya Exceptionböylece nedeniyle onunla denilen varlık türüne, bir kontrol istisna olan kendisi) Tolarak anlaşılmaktadır alır Exception.


1
@Maksym sneakyThrowAramayı kastetmelisiniz . throws TFormların çıkarılmasıyla ilgili özel düzenlemeler Java 7 şartnamesinde mevcut değildi.
Marko Topolnik

1
Küçük nitpick: In nonSneakyThrow, "bir süpertipi" Tolmamalıdır , çünkü bu tam olarak çağrı sitesinde derleme zamanında bildirilen argümanın tipidir. ExceptionException
llogiq

1
@llogiq Spesifikasyonu doğru okuduysam, bir alt sınırı Exceptionve bir üst sınırı var Throwable, bu nedenle sonuçta ortaya çıkan tür olan en küçük üst sınır Exception.
thecoop

1
@llogiq Bağımsız değişkenin türünün yalnızca daha düşük bir tür sınırı belirlediğine dikkat edin, çünkü bağımsız değişkenin herhangi bir üst türü de kabul edilebilir.
Marko Topolnik

2
"veya Exceptionkendisi" ifadesi okuyucuya yardımcı olabilir, ancak genel olarak, belirtimin her zaman "kendini dahil etme" anlamında "alt tip" ve "süper tip" terimlerini kullandığı unutulmamalıdır ...
Holger

17

Tür çıkarımı bir tür değişkeni için tek bir üst sınır üretirse, genellikle çözüm olarak üst sınır seçilir. Örneğin T<<Number, çözüm ise T=Number. Her ne kadar Integer, Floataynı zamanda kısıtlamasını tatmin olabilir vb onları seçmek için iyi bir neden yoktur Number.

Yani için de böyleydi throws Tjava 5-7 içinde: T<<Throwable => T=Throwable. (Sinsi atış çözümlerinin hepsinde açık <RuntimeException>tip argümanları vardı , aksi takdirde<Throwable> çıkarılır.)

Java8'de lambda'nın tanıtılmasıyla bu sorunlu hale geliyor. Bu davayı düşünün

interface Action<T extends Throwable>
{
    void doIt() throws T;
}

<T extends Throwable> void invoke(Action<T> action) throws T
{
    action.doIt(); // throws T
}    

Boş bir lambda ile çağırırsak, ne Tolarak çıkarılır?

    invoke( ()->{} ); 

Tek kısıtlama Tüst sınırdır Throwable. Java8'in önceki aşamasında, T=Throwableçıkarsama yapılacaktır. Dosyaladığım bu rapora bakın .

Ancak bu, Throwableboş bir bloktan kontrol edilmiş bir istisna olduğu sonucuna varmak için oldukça aptalca . Raporda bir çözüm önerildi (görünüşe göre JLS tarafından benimsenmiştir) -

If E has not been inferred from previous steps, and E is in the throw clause, 
and E has an upper constraint E<<X,
    if X:>RuntimeException, infer E=RuntimeException
    otherwise, infer E=X. (X is an Error or a checked exception)

yani üst sınır Exceptionveya ise çözüm olarak Throwableseçin RuntimeException. Bu durumda, orada olan üst sınır belli bir alt türünün seçilmesi iyi bir neden.


X:>RuntimeExceptionSon örnek kod parçanızın anlamı nedir ?
marsouf

1

İle sneakyThrow, tür T, belirli bir türü olmayan sınırlı bir genel tür değişkendir (çünkü türün gelebileceği bir yer yoktur).

İle nonSneakyThrow, tür Tbağımsız değişkenle aynı türdedir, bu nedenle örneğinizde, T/ nonSneakyThrow(e);eşittir Exception. As testSneaky()a atılan bildirmiyor Exceptionbir hata gösterilir.

Bunun, kontrol edilen istisnalarla Generics'in bilinen bir müdahalesi olduğunu unutmayın.


Öyleyse sneakyThrow, aslında herhangi bir spesifik türe göre çıkarılmamış ve "döküm" böyle tanımlanmamış bir tip için mi? Bununla gerçekte ne olacağını merak ediyorum.
Marko Topolnik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.