it-swarm.com.de

Wie kann eine generisch angegebene Ausnahme nicht ausgelöst werden?

Ich habe ein "Producer" -Interface erstellt (zur Verwendung mit Methodenreferenzen bzw. zum einfachen Verspotten für Komponententests):

@FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
    public R newInstanceFor(T t) throws X;
}

was ich so erstellt habe, da mein erster Anwendungsfall tatsächlich etwas WhateverException werfen musste.

Aber mein zweiter Use Case hat kein X zum werfen.

Das Beste, mit dem ich den Compiler glücklich machen konnte, ist:

Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;

Das kompiliert und macht, was ich brauche, aber immer noch hässlich. Gibt es eine Möglichkeit, diese einzelne Schnittstelle beizubehalten, jedoch kein X anzugeben, wenn bestimmte Instanzen deklariert werden?

22
GhostCat

Die einzige Möglichkeit, dies zu tun, ist die Unterklasse - aber ich wette, das wussten Sie. Um mein Argument stärker zu machen, betrachten Sie BinaryOperator, das BiFunction erweitert.

12
Eugene

In Java ist das nicht möglich. Die einzige Möglichkeit ist das Erstellen einer Subschnittstelle.

public interface DefaultExceptionFactory<R, T>
        extends Factory<R, T, RuntimeException>
12
Leo Aso

Dies ist eher eine "Social Engineering" -Antwort: Wir geben der Lambda-Form einen Vertrag, dass sie nichts wirft:

public interface Factory<T, R, X> {

    public R newInstanceFor(T arg) throws X;

    public static Factory<R, U, AssertionError> neverThrows(Factory<U, V, ?> input) {
        return u -> {
            try {
                return input.newInstanceFor(u);
            }
            catch(Throwable t) {
                throw new AssertionError("Broken contract: exception thrown", t);
            }
        };
    }
}

Die Nutzung ist wie folgt oder etwas in der Art von:

class MyClass {
    Factory<MyInput, MyOtherClass, AssertionError> factory;

    MyClass(Factory<MyInput, MyOtherClass, ?> factory) {
        this.factory = Factory.neverThrows(factory);
    }

    public void do() {
      factory.newInstanceFor(new MyInput()).do();
    }
}

Nachteil dieses Ansatzes: Sie können den Vertrag nicht wirklich in der Typensignatur angeben, der Vertrag ist dann ein Implementierungsdetail. Wenn Sie diese In-Typ-Signatur haben möchten, benötigen Sie eine zweite Subschnittstelle.

5
M. Prokhorov

Sie können die Methode wie folgt als generisch definieren, sofern dies für Sie möglich ist:

@FunctionalInterface
public interface Factory<R, T> {
    public <X extends Throwable> R newInstanceFor(T t) throws X;
}
3
Beno Arakelyan

Sie können Project Lombok s @SneakyThrows annotation verwenden:

@FunctionalInterface
public interface Factory<R, T> {

    @SneakyThrows
    R newInstanceFor(T t);
}

Auf diese Weise können Sie eine Ausnahme auslösen (aktiviert oder nicht markiert). Lesen Sie jedoch die Dokumentation, da diese Funktion mit Vorsicht behandelt werden muss.

0
foundationer