Use Generic Supplier to throw unchecked excpetion

Viewed 333

I have list of methods which has Supplier<T> arguments for returning default values of different types. However, in some cases I need to throw exception(unchecked) instead of values.

Currently, I have to pass the lambda for each function definition but I would like to create supplier instance for throwing the exception and re-use it in all function definition.

I have following code:

    public static void main(String[] args)
    {

        testInt("Key1", 10, () -> 99);
        testInt("Key2", -19, () -> 0);
        testInt("Key3", null, () -> {
            throw new UnsupportedOperationException(); //repetition
        });
        testBoolean("Key4", true, () -> Boolean.FALSE);
        testBoolean("Key5", null, () -> {
            throw new UnsupportedOperationException();//repetition
        });
    }

    static void testInt(String key, Integer value, Supplier<Integer> defaultValue)
    {
        if (value != null)
            System.out.printf("Key : %s, Value : %d" + key, value);
        else
            System.out.printf("Key : %s, Value : %d" + key, defaultValue.get());
    }

    static void testBoolean(String key, Boolean value, Supplier<Boolean> defaultValue)
    {
        if (value != null)
            System.out.printf("Key : %s, Value : %d" + key, value);
        else
            System.out.printf("Key : %s, Value : %d" + key, defaultValue.get());
    }

But I am looking to do something like :

final static Supplier<?> NO_VALUE_FOUND = () -> {
        throw new UnsupportedOperationException();
    };


testInt("Key3", null, NO_VALUE_FOUND);
testBoolean("Key5", null,NO_VALUE_FOUND);

Appreciate any help on this. Thanks.

3 Answers

Use a method to convert the NO_VALUE_FOUND value to the appropriate type:

static <T>  Supplier<T> NO_VALUE_FOUND() {
    return (Supplier<T>) NO_VALUE_FOUND;
}

public static void main(String[] args) {
    testInt("Key3", null, NO_VALUE_FOUND());
    testBoolean("Key5", null,NO_VALUE_FOUND());
}

Similar to @jon-hanson's answer, you can define a method which returns the lambda directly, with no cast needed:

private <T> Supplier<T> noValueFound() {
    return () -> {
        throw new UnsupportedOperationException();
    };
}

Better would be that you can use a more generic implementation like :

static <T> void test(String key, T value, Supplier<T> defaultValue) {
    if (value != null)
        System.out.println("Key : " + key + " Value " + value); // note the change from printf since that had type specific placeholders
    else
        System.out.println("Key : " + key + " Value " + defaultValue.get());
}

and further use it as :

public static void main(String[] args) {
    test("Key1", 10, () -> 99);
    test("Key2", -19, () -> 0);
    test("Key3", null, NO_VALUE_FOUND);
    test("Key4", true, () -> Boolean.FALSE);
    test("Key5", null, NO_VALUE_FOUND);
}

with NO_VALUE_FOUND as :

final static Supplier<?> NO_VALUE_FOUND = () -> {
    throw new UnsupportedOperationException();
};

Edit (from the comments): If you try to pass your NO_VALUE_FOUND of type Supplier<?> to your test function, and pass anything other than the literal value null as the second argument, you will get a compiler error.

So in order to solve for cases where any other value other than null can throw an UnsupportedOperationException, use a generic implementation as suggested in MikeFHay answer.

Related