Je me demande si quelqu'un pourrait m'expliquer la bizarrerie suivante. J'utilise Java 8 update 11.
Étant donné cette méthode
private <F,T> T runFun(Function<Optional<F>, T> fun, Optional<F> opt) {
return fun.apply(opt) ;
}
Si je construis d'abord une fonction Object et que je la transmets à la méthode ci-dessus, les choses se compilent.
private void doesCompile() {
Function<Optional<String>, String> fun = o -> o.orElseThrow(() -> new RuntimeException("nah"));
runFun(fun, Optional.of("foo"));
}
Mais, si j'intègre la fonction en tant que lambda, le compilateur dit
exception X non déclarée; doit être attrapé ou déclaré comme jeté
private void doesNotCompile () {
runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo"));
}
Update: Il s'avère que le message d'erreur a été abrégé par maven. Si compilé directement avec javac, l'erreur est la suivante:
error: unreported exception X; must be caught or declared to be thrown
runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo"));
^
where X,T are type-variables:
X extends Throwable declared in method <X>orElseThrow(Supplier<? extends X>)
T extends Object declared in class Optional
Voir aussi ici pour le code de test exécutable.
Cela ressemble à un cas de bogue JDK-8054569 , qui n'affecte pas Eclipse.
J'ai pu le réduire en remplaçant Function par Supplier et en extrayant la méthode orElseThrow
:
abstract <T> void f(Supplier<T> s);
abstract <T, X extends Throwable> T g(Supplier<? extends X> x) throws X;
void bug() {
f(() -> g(() -> new RuntimeException("foo")));
}
et ensuite en supprimant les fournisseurs et les lambdas:
abstract <T> void f(T t);
abstract <T, X extends Throwable> T g(X x) throws X;
void bug() {
f(g(new RuntimeException("foo")));
}
ce qui est en fait un exemple plus propre que celui du rapport de bogue. Cela montre la même erreur si compilé en Java 8, mais fonctionne bien avec -source 1.7
.
J'imagine que le fait de passer un type de retour de méthode générique à un paramètre de méthode générique provoque l'échec de l'inférence de type pour l'exception. Il suppose donc que le type est Throwable et se plaint que ce type d'exception cochée n'est pas géré. L'erreur disparaît si vous déclarez bug() throws Throwable
ou si vous modifiez la liaison à X extends RuntimeException
(elle est donc décochée).
C'est ce qui a résolu le problème pour moi:
au lieu d'écrire
optional.map(this::mappingFunction).orElseThrow(() -> new BadRequestException("bla bla"));
J'ai écrit:
optional.map(this::mappingFunction).<BadRequestException>orElseThrow(() -> new BadRequestException("bla bla"));
L'ajout du <BadRequestException>
explicite aide ces cas Edge lambda (qui sont assez ennuyeux ...)
UPDATE: C'est au cas où vous ne pourriez pas mettre à jour la dernière version du JDK, si vous le pouvez vous devriez.
Si vous essayez de compiler le projet de quelqu'un d'autre, essayez de passer à la version 1.8.0_92.
Semblable à @keisar, je pourrais résoudre mon problème (voir maven-compiler-plugin ne parvient pas à compiler un fichier avec lequel Eclipse n'a pas de problème avec ) en spécifiant le paramètre type.
Cependant, j’ai trouvé beaucoup plus pratique (puisque j’utilise NotFoundException
dans un certain nombre d’endroits) de simplement faire en sorte que ma classe d’exception soit sa propre Supplier
:
public class NotFoundException extends RuntimeException
implements Supplier<NotFoundException> {
// Rest of the code
@Override
public NotFoundException get() {
return this;
}
}
Ensuite, vous pouvez simplement faire:
// Distribution.rep().get(id) returns a Java.util.Optional
Distribution distro = Distribution.rep().get(id).orElseThrow(
new NotUniqueException("Exception message"));