Java 8: Obowiązkowe sprawdzanie wyjątków w wyrażeniach lambda. Dlaczego obowiązkowe, a nie opcjonalne?
Gram z nowymi funkcjami lambda w Javie 8 i odkryłem, że praktyki oferowane przez Javę 8 są naprawdę przydatne. Zastanawiam się jednak, czy istniejedobry sposób na obejście następującego scenariusza. Przypuśćmy, że masz wrapper puli obiektów, który wymaga pewnego rodzaju fabryki, aby wypełnić pulę obiektów, na przykład (używającjava.lang.functions.Factory
):
public class JdbcConnectionPool extends ObjectPool<Connection> {
public ConnectionPool(int maxConnections, String url) {
super(new Factory<Connection>() {
@Override
public Connection make() {
try {
return DriverManager.getConnection(url);
} catch ( SQLException ex ) {
throw new RuntimeException(ex);
}
}
}, maxConnections);
}
}
Po przekształceniu interfejsu funkcjonalnego w wyrażenie lambda powyższy kod wygląda tak:
public class JdbcConnectionPool extends ObjectPool<Connection> {
public ConnectionPool(int maxConnections, String url) {
super(() -> {
try {
return DriverManager.getConnection(url);
} catch ( SQLException ex ) {
throw new RuntimeException(ex);
}
}, maxConnections);
}
}
Nie tak źle, ale sprawdzony wyjątekjava.sql.SQLException
wymagatry
/catch
blok wewnątrz lambda. W mojej firmie używamy dwóch interfejsów przez długi czas:
IOut<T>
to jest odpowiednikjava.lang.functions.Factory
;oraz specjalny interfejs dla przypadków, które zwykle wymagają propagowania sprawdzonych wyjątków:interface IUnsafeOut<T, E extends Throwable> { T out() throws E; }
.ObieIOut<T>
iIUnsafeOut<T>
powinny zostać usunięte podczas migracji do Java 8, jednak nie ma dokładnego dopasowaniaIUnsafeOut<T, E>
. Jeśli wyrażenia lambda mogłyby poradzić sobie z zaznaczonymi wyjątkami, takimi jak te, które nie były zaznaczone, możliwe byłoby użycie po prostu w powyższym konstruktorze:
super(() -> DriverManager.getConnection(url), maxConnections);
To wygląda na znacznie czystsze. Widzę, że mogę przepisaćObjectPool
super klasa, aby zaakceptować nasząIUnsafeOut<T>
, ale o ile wiem, Java 8 jeszcze się nie skończyła, więc może być kilka zmian, takich jak:
IUnsafeOut<T, E>
? (szczerze mówiąc, uważam to za brudne - podmiot musi wybrać, co zaakceptować: alboFactory
lub „niebezpieczna fabryka”, która nie może mieć zgodnych podpisów metod)po prostu ignorując sprawdzone wyjątki w lambdach, więc nie ma potrzebyIUnsafeOut<T, E>
zastępcy? (dlaczego nie? np. inna ważna zmiana: OpenJDK, którego używam,javac
teraz nie wymaga deklarowania zmiennych i parametrów jakofinal
do przechwycenia w anonimowej klasie [interfejs funkcjonalny] lub wyrażeniu lambda)Zatem pytanie brzmi ogólnie: czy istnieje sposób na ominięcie sprawdzonych wyjątków w lambdach lub czy jest planowany w przyszłości, aż Java 8 zostanie ostatecznie wydana?
Aktualizacja 1
Hm-m-m, o ile rozumiem, co mamy obecnie, wydaje się, że w tej chwili nie ma sposobu, mimo że wspomniany artykuł pochodzi z 2010 roku:Brian Goetz wyjaśnia przejrzystość wyjątków w Javie. Jeśli w Javie 8 nic się nie zmieniło, można to uznać za odpowiedź. Również Brian tak mówiinterface ExceptionalCallable<V, E extends Exception>
(o czym wspomniałem jakoIUnsafeOut<T, E extends Throwable>
poza naszym dziedzictwem kodu) jest prawie bezużyteczny i zgadzam się z nim.
Czy wciąż tęsknię za czymś innym?