Make argument optional using <Void> type? - java

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);
}
}

Related

Label a generic type argument bounded with super

To specify my rather tricky problem, a bit of explanation is required so please bear with me.
I'm designing minimalist interfaces for an observable pattern that uses managing ListenerHandles instead of a removeListener(...) method in the observable class.
This is the idea:
public interface ListenerHandle<T> {
boolean isRemoved();
void remove();
Listener<T> managedListener();
Observable<T> containingObservable();
}
public interface Observable<T> {
T get();
void set(T value);
ListenerHandle<T> addListener(Listener<T> listener);
}
public interface Listener<T> {
void onChange(ListenerHandle<T> handle, T value);
}
Now this works perfectly fine.
But what if I wanted Observable<T> to accept more general Listeners? Listener<? super T>s to be precise. This makes sense, since a listener that expects ? super T will also accept T (it is contravariant).
As a consequence, ListenerHandle would need to differentiate between T of the Observable it was obtained from, and T of the managed Listener:
public interface ListenerHandle<TL, TO> {
// ...
Listener<TL> managedListener();
Observable<TO> containingObservable();
}
public interface Observable<TO> {
// ...
<TL> ListenerHandle<TL, TO> addListener(Listener<TL> listener);
}
public interface Listener<TL> {
void onChange(ListenerHandle<TL, ? extends TL> handle, TL value);
}
Even though these interfaces will compile, we know that TL in
<TL> ListenerHandle<TL, TO> addListener(Listener<TL> listener);
is a bit too generic, because it can now be anything. However, Observable should only be able to take listeners, that expect TO or its super types:
<TL super TO> ListenerHandle<TL, TO> addListener(Listener<TL> listener);
This will not work since super can only be used on wildcards. So another option is:
ListenerHandle<? super TO, TO> addListener(Listener<? super TO> listener);
In this case, however, the caller will lose the information that the returned ListenerHandle's ? super TO and listener's ? super TO will be identical:
Observable<Number> o = ...;
Listener<Object> l = ...;
// does not work, but should (since we know that we passed a Listener<Object>)
ListenerHandle<Object, Number> h = o.addListener(l);
// works but Object is now generalized to ? super Number
ListenerHandle<? super Number, Number> h2 = o.addListener(l);
l = h2.managedListener(); // fails because ? super Number is not (necessarily) Object
So, what I need is a way to specify a labeled type argument bounded with super, to demonstrate, that the bounded generic type of the argument is identical to the bounded generic type of the return type. How could I do this?
Instead of adding a generic parameter TL for the type of Listener, you could make it a Listener<? super T>:
public interface ListenerHandle<T> {
boolean isRemoved();
void remove();
Listener<? super T> managedListener();
Observable<T> containingObservable();
}
public interface Observable<T> {
T get();
void set(T value);
ListenerHandle<T> addListener(Listener<? super T> listener);
}
public interface Listener<T> {
<TO extends T> void onChange(ListenerHandle<TO> handle, TO value);
// or:
// void onChange(ListenerHandle<? extends T> handle, T value);
}
If you really need to add the TL parameter to ListenerHandle, I think the only way to do it would be the static method workaround:
public interface ListenerHandle<TL, TO extends TL> {
boolean isRemoved();
void remove();
Listener<TL> managedListener();
Observable<TO> containingObservable();
}
public interface Observable<TO> {
TO get();
void set(TO value);
// #Deprecated
ListenerHandle<?, TO> addListener(Listener<? super TO> listener); // implies ListenerHandle<? super TO, TO>
#SuppressWarnings("unchecked")
static <TL, TO extends TL> ListenerHandle<TL, TO> addListener(Observable<TO> observer, Listener<TL> listener) {
return (ListenerHandle<TL, TO>) observer.addListener(listener);
}
}
public interface Listener<TL> {
void onChange(ListenerHandle<TL, ?> handle, TL value); // implies ListenerHandle<TL, ? extends TL>
}
You would have to remember never to call obs.addListener(lis) directly, but instead use Observable.addListener(obs, lis). Marking it as #Deprecated would give you a warning, but you'd need to put that on all the overriding methods as well.

How to not throw a generically specified exception?

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.

In java, how do I sort a generic class T on a Field variable sent to me

// this function can be called if the objects sent is Comparable (they have
// already chosen the field and how it compares)
public void mySort(Object [] obj) {
Arrays.sort(obj, null); // this sorts based on compareTo()
// method of comparable object
}
My question is how would the following function need to be changed to sort the array by the Field field. I have tried many different ways of implementing it and just put code below which represents what I was trying to do.
// this function should be used to sort a generic array of T objects, to be
// compared on the Field field
public static <T> void mySort2(T [] obj, Field field) {
Collections.sort(obj, new Comparator<T>(){
public int compare(T obj1, T obj2)
{
return obj1.field.compareTo(obj2.field); // this does not work
// since I need to the name of the field and
// not a variable, however I do not know what
// T will be when it is sent to me
}
});
}
You need to use Field::get to reflectively access the field. After that, you will need to cast to Comparable.
Do you really need to pass a Field instance and look up the field reflectively? As a possible alternative (which may be more performant, depending on your JVM implementation), you can pass a lambda or method reference for accessing the field:
public static <T, U extends Comparable<? super U>> void mySort(
T[] array,
Function<T, U> func) {
Arrays.sort(array, (a, b) -> func.apply(a).compareTo(func.apply(b));
}
Which you would call like:
Foo[] foos = ...
mySort(foos, Foo::getMyField);
If you're stuck with Java 7, you can do the same thing but it's a bit more verbose:
public interface Function<I, O> {
O apply(I input);
}
public static <T, U extends Comparable<? super U>> void mySort(
T[] array,
final Function<T, U> func) {
Arrays.sort(array,
new Comparator<T>() {
#Override public int compareTo(T a, T b) {
return func.apply(a).compareTo(func.apply(b));
}
});
}
Which you would call like:
Foo[] foos = ...
mySort(foos,
new Function<Foo, Integer>() {
#Override public Integer apply(Foo foo) {
return foo.getMyField();
}
});
You asked how to do it with Field, and an answer was given. If this is a strict requirement for whatever reason then my answer is moot, but if it is not it is a nicer way to do it without reflection.
First, a quick mention, instead of T[] obj, it will need to be List<T> obj.
Now for the rest of the changes,
The method's type-parameter was <T>, I have changed it to <T, F extends Comparable<F>>. F stands for "field". F needs to be comparable to itself which is why it needs to be Comparable<F>.
You need a way to get the F from the T. So you give a Function<T, F> which I will give an example of below.
The compare method needs to return getter.apply(obj1).compareTo(getter.apply(obj2)).
Here is your finished product
public static <T, F extends Comparable<F>> void mySort2(List<T> obj, final Function<T, F> getter) {
Collections.sort(obj, new Comparator<T>() {
public int compare(T obj1, T obj2) {
return getter.apply(obj1).compareTo(getter.apply(obj2));
}
});
}
Here is an example of calling it to sort strings by length.
List<String> list = getSomeListOfStringsSomehow();
mySort2(list, (String s) -> g.length());

Converting the type of a generic Collection in Java

In several spots in my code I have ArrayLists and TreeSets whose generic type I wish to convert. So for example I have an ArrayList<Integer> which I wish to convert to an ArrayList<Long>. Or I have a TreeSet<BigInteger> which I wish to convert to a TreeSet<String>.
All of these conversions can be made, but then I have to create for each type conversion a different function. Therefore I want to create a generic function whose signature looks something like this:
public static <Q,T> Collection<Q> convert(Collection<T> col, Class<Q> Q)
What I want is to get the class from col (e.g. ArrayList), create a new collection of that class and type Q (called newCol), and then iterate through col and convert each element which is of type T to type Q and add it to newCol and lastly return newCol.
How can I do this?
There's no special mechanism like casting of incompatible classes in Java. You need to specify an explicit function which will perform a conversion. Using Java 8 it's really easy:
public static <Q,T,C extends Collection<Q>> C convert(Collection<T> col, Function<T, Q> fn,
Supplier<C> supplier) {
return col.stream().map(fn).collect(Collectors.toCollection(supplier));
}
Use it like this:
TreeSet<BigInteger> values = // fill them somehow
TreeSet<String> converted = convert(values, BigInteger::toString, TreeSet::new);
#Tagir Valeev is right. You can do it easily in Java 8. But if you use Java 7, you can try to do something like this:
public static <F, T> Collection<T> transform(Collection<F> fromCollection, Function<? super F, T> function) {
return new TransformedCollection<F, T>(fromCollection, function);
}
static class TransformedCollection<F, T> extends AbstractCollection<T> {
final Collection<F> fromCollection;
final Function<? super F, ? extends T> function;
TransformedCollection(Collection<F> fromCollection, Function<? super F, ? extends T> function) {
this.fromCollection = checkNotNull(fromCollection);
this.function = checkNotNull(function);
}
#Override public void clear() {
fromCollection.clear();
}
#Override public boolean isEmpty() {
return fromCollection.isEmpty();
}
#Override public Iterator<T> iterator() {
return Iterators.transform(fromCollection.iterator(), function);
}
#Override public int size() {
return fromCollection.size();
}
}
It's code from Guava library.

How to define a generic parameter which should extend Map or Collection?

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?

Categories