I created a "producer" interface (to be used with method references, respectively to be easily mocked for unit tests):
#FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
public R newInstanceFor(T t) throws X;
}
which I created like that, as my first use case actually had to throw some checked WhateverException.
But my second use case doesn't have an X to throw.
The best I could come up with to make the compiler happy is:
Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;
That compiles, and does what I need, but still ugly. Is there a way to keep that single interface, but not provide an X when declaring specific instances?
You cannot do that in Java. The only way is to create a sub interface.
public interface DefaultExceptionFactory<R, T>
extends Factory<R, T, RuntimeException>
The only way to do it is subclassing - but I bet you knew that. To make my argument stronger, look at BinaryOperator that extends BiFunction.
This is more of a "social engineering" answer: we place a contract on the lambda form that it doesn't throw anything:
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);
}
};
}
}
Usage is like this, or something along the lines of:
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();
}
}
Downside of this approach: you can't really specify the contract in the type signature, the contract is then an implementation detail. If you want to have this in type signature, you will need a second sub-interface.
You can define the method as generic like below code, if it is possible for you:
#FunctionalInterface
public interface Factory<R, T> {
public <X extends Throwable> R newInstanceFor(T t) throws X;
}
You can use Project Lombok's #SneakyThrows annotation:
#FunctionalInterface
public interface Factory<R, T> {
#SneakyThrows
R newInstanceFor(T t);
}
This allows you to throw any exception (checked or unchecked). But read the documentation because this feature must be handled with care.
Do you have to make the exception generic? Why not define the interface as
#FunctionalInterface
public interface Factory<R, T> {
public R newInstanceFor(T t) throws Throwable;
}
You can always catch your exception and check the type if you need in your calling function.
Related
I am having hard time to understand the difference between two declarations on java generics.
lets say I have the following two interfaces
#FunctionalInterface
public interface CheckedFunction<T, R, E extends Throwable> {
R apply(T t) throws E;
}
public interface SomeInterface<DTO, E2 extends Throwable> {
<E extends Throwable> CheckedFunction<Object, String, E> firstFunction();
CheckedFunction<String, DTO, E2> secondFunction();
}
So now I created an implementation of those and an "unchecked" warning popped which is what I am trying to understand.
The implementation is the following
public class TmpImpl implements SomeInterface<TmpObj, IOException> {
final ObjectMapper objectMapper = new ObjectMapper();
#Override
public CheckedFunction<Object, String, JsonProcessingException> firstFunction() {
return objectMapper::writeValueAsString;
}
#Override
public CheckedFunction<String, TmpObj, IOException> secondFunction() {
return json -> objectMapper.readValue(json, TmpObj.class);
}
public static class TmpObj {
String s;
}
}
for this example I am using com.fasterxml.jackson.databind.ObjectMapper as it does exactly what I want and generates the warning.
So the firstFunction now has a warning
Unchecked overriding: return type requires unchecked conversion. Found 'CheckedFunction<java.lang.Object,java.lang.String,com.fasterxml.jackson.core.JsonProcessingException>', required 'CheckedFunction<java.lang.Object,java.lang.String,E>
while the second is just fine.
Why is this happening ? I am clearly missing something which I haven't noticed in order to fix it!
note JsonProcessingException extends IOException (declaration: public class JsonProcessingException extends IOException )
The short answer is that your implementation is dictating JsonProcessingException whereas the interface allows for E to be inferred.
In other words, according to the interface, this should be possible:
SomeInterface<String, RuntimeException> runtimeExceptionSomeInterface = null;
CheckedFunction<Object, String, RuntimeException> function =
runtimeExceptionSomeInterface.firstFunction();
This declaration:
<E extends Throwable> CheckedFunction<Object, String, E> firstFunction();
allows the caller to specify the concrete argument for E, which is exactly what I did in the above example (using RuntimeException).
However, your implementation is statically forcing JsonProcessingException:
public CheckedFunction<Object, String, JsonProcessingException> firstFunction() {
return objectMapper::writeValueAsString;
}
That is to say you've disregarded the incoming E type argument and forcefully substituting it with JsonProcessingException.
In short, if you want the firstFunction() to be generic, then implement it accordingly:
#Override
public <E extends Throwable> CheckedFunction<Object, String, E> firstFunction() {
return objectMapper::writeValueAsString;
}
However, the above fails return objectMapper::writeValueAsString; with an unhandled JsonProcessingException, which I suspect led to your implementation.
That simply means that your use of a generic Throwable parameter is wrong.
A first attempt at solving it would be to use SomeInterface's E2 variable:
interface SomeInterface<DTO, E2 extends Throwable> {
CheckedFunction<Object, String, E2> firstFunction();
CheckedFunction<String, DTO, E2> secondFunction();
}
which will solve the problem if implemented with:
class TmpImpl implements SomeInterface<TmpObj, IOException> {
//...
#Override
public CheckedFunction<Object, String, IOException> firstFunction() {
return objectMapper::writeValueAsString;
}
However, you would still have a problem because it's not the user of SomeInterface that knows what exception will be thrown, but the implementation. This means that you should declare the exception type on the API, rather than making it a generic argument:
interface SomeInterface<DTO> {
CheckedFunction<Object, String, IOException> firstFunction();
//...
}
class TmpImpl implements SomeInterface<TmpObj> {
//...
#Override
public CheckedFunction<Object, String, IOException> firstFunction() {
return objectMapper::writeValueAsString;
}
}
Which is to say that SomeInterface and its implementations know the range of exceptions to be dealt with, therefore the functions they return know of, in this case, IOException (which is selected because you know it includes JsonProcessingException, among other types)
Say I have this interface:
public interface IAsyncCallback<T, E> {
void done(E e, T v);
}
in a certain case, I want someone to be able to use:
IAsyncCallback<Void,Object> cb = e -> {};
such that it's clear that they shouldn't expect a second argument (the second argument v would always be null.
Is this possible somehow? Having a bit of trouble reconciling 2 argument and 1 argument methods so they can be interchangeable.
Basically would like to find a way to use optional arguments using generics, but I would be curious if there is a way to do this another way, since the above technique won't work, it expects 2 arguments, you can't ignore an argument, etc.
As an aside, if I have an interface like this:
public interface IEachCallback<T, E> {
void done(E e);
}
I was hoping you could cast either IAsyncCallback to IEachCallback or vice versa, maybe you can? Seems like you should be able to cast a method that takes a superset of the arguments of another method.
There really isn't a native way to make this easy.
One workaround can be to implement IEachCallback using default methods in the IEachCallback interface and allow users to pass single-argument lambdas:
public interface IEachCallback<T, E> extends IAsyncCallback<T, E> {
#Override
default void done(E e, T t) {
this.done(t);
}
void done(T e);
}
This allows the caller to pass a single-argument lambda, but it still poses the problem of assignment:
//there's no way to assign or pass as argument directly
//Otherwise users have to do this type cast:
IAsyncCallback<Void,Object> cb = (IEachCallback<Void, Object>) e -> {};
To go around this, I'd add a static factory method to IEachCallback:
public interface IEachCallback<E> extends IAsyncCallback<Void, E> {
#Override
default void done(E e, Void t) {
this.done(e);
}
void done(E e);
static <E> IAsyncCallback<Void, E> ofVoid(IEachCallback<E> callback) {
return (e, v) -> callback.done(e);
}
}
And that allows users to call it in a much simpler way:
IAsyncCallback<Void,Object> cb = IEachCallback.ofVoid( e -> {});
For even further improvement, you may want to move this to the parent interface, and eliminate the child interface altogether:
public interface IAsyncCallback<T, E> {
void done(E e, T v);
static <E> IAsyncCallback<Void, E> ofConsumer(Consumer<E> callback) {
return (t, e) -> callback.accept(t);
}
}
I am facing some difficulty to understand an expression in java generics.
Please help on this:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString();
}
The code you have given is legal, but useless.
It is useless for two reasons:
You have defined a generic type, T, as part of the method declaration that must implement the Enum<T> interface as well as the FunctionalInterface interface. However you haven't then used that type anywhere in the method's signature (i.e. arguments or return type) so it is effectively ignored.
Having an interface implement 'FunctionalInterface' is possible, but certainly not it's intended use. It is designed to be an annotation to an interface, not an interface itself.
You could make this combination work:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString(T value);
}
static class InterImpl implements Inter {
#Override
public <T extends Enum<T> & FunctionalInterface> String getString(T value) {
return value.name();
}
}
enum EnumImpl implements FunctionalInterface {
A, B, C;
#Override
public Class<? extends Annotation> annotationType() {
return null;
}
}
public static void main(String[] args) {
InterImpl impl = new InterImpl();
System.out.println(impl.getString(EnumImpl.B));
}
You'll see that the EnumImpl enumeration implemements Enum and FunctionalInterface so it can be used as an argument to getString.
So that's an explanation but, frankly, I can't think of any useful use case for such a piece of code.
I'm trying to create a functional interface that can throw an custom exception, what I've come up with is.
public class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
#FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T t) throws MyException;
}
This works great for using the apply function but the problem is I'd also like to use the andThen capabilities of Java's functions. When I try to do something like.
ThrowingFunction<Integer, Integer> times2WithException = (num) -> {
if(num == null) {
throw new MyException("Cannot multiply null by 2");
}
return num * 2;
};
times2WithException.andThen(times2WithException).apply(4);
I get the error
Cannot find symbol: method andThen(ThrowingFunction<Integer, Integer>)
Is there something I should use instead of FunctionalInterface? Or is there another function I need to implement to get it to work with andThen?
Thanks!
Functional interfaces are only allowed to specify one unimplemented function. But you can specify default functions that already have an implementation like this:
#FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T t) throws MyException;
default <U> ThrowingFunction<T, U> andThen(ThrowingFunction<R, U> follow) {
Objects.requireNonNull(follow); // Fail fast
return t -> follow.apply(this.apply(t));
}
}
Where are you expecting the andThen method to come from? You haven't defined it anywhere!
#FunctionalInterface
interface ThrowingFunction<T, R> {
R apply(T t) throws MyException;
default <V> ThrowingFunction<T, V> andThen(ThrowingFunction<R, V> after) {
return (T t) -> after.apply(apply(t));
}
}
Here, you can take advantage of default methods in interfaces to create an andThen function.
I want to defined a generic parameter, which should extend Map or Collection, but I don't know how to do it:
public <T> void test(T t) {}
I can write it as:
public <T extends Map> void test(T t) {}
or
public <T extends Collection> void test(T t) {}
But I don't know is it possible to let T extend Map or Collection in a single method.
Short answer: no.
What do you intend to do with the t parameter within the method? Since Map and Collection have only Object as their common supertype, the only methods you can call on t will be those on Object. (Even methods on both interfaces, such as size(), will be rejected by the compiler.)
With that in mind, is there any reason you can't overload the method in this case? That is, define one implementation for each desired parameter type:
public void test(Map<?,?> t) { ... }
public void test(Collection<?> t) { ... }
If you don't want to do that for whatever reason, then it seems that you could equally just declare the method to take Object and perform a run-time type check of the class. This is semantically equivalent since you'd have to cast to call Map or Collection-specific methods anyway, though it does mean that the type check is done at compile time instead of runtime. Java's type system doesn't let you express this union-type dependency though, so I don't see any other alternative.
No it is not possible, but you can create two separate methods:
public <T extends Map> void test(T t) {
// do the map part
}
public <T extends Collection> void test(T t) {
// do the collection part
}
If you want to mix them in a handling method you can also write it like this:
private void mixedTest(Object t) {
if (t instanceof Map) {
// map part
} else if (t instanceof Collection) {
// collection part
} else {
throw new RuntimeException("Unknown object");
}
}
and call:
public <T extends Map> void test(T t) {
mixedTest(t);
}
public <T extends Collection> void test(T t) {
mixedTest(t);
}
But I'm not sure it will lead to a nice code anyway. I would stick with the first part with the different implementation for the different type of objects.
What about
public <T extends Map> void test(Map t) {}
and
public <T extends Collection> void test(Collection t) {}
...and then let Java choose the correct one to use?