public <Z, T extends Iterable<Z>, R> T<R> process(T, Function<Z,R>)
change the type parameter of T<Z> to T<R> and return an instance of T<R>, but the best I can do is return an instance of Iterable<R> because I cannot define T to have a type parameter.
public <A, B, T extends Iterable<A>, R extends Iterable<B>> R process(T input, Function<? super A, ? extends B> transformer,
Function<Iterable<B>, R> helper) {
return helper.apply(StreamSupport.stream(input.spliterator(), false)
.map(transformer)
.collect(toList()));
}
@Test
public void testProcess() {
Iterable<Integer> ints = process(Arrays.asList("1", "2", "3"), Integer::parseInt, identity());
System.out.println(ints);
}
Outputs nicely integers nicely converted from strings:
[1, 2, 3]:-P
`identity()` is a static import of `Function.identity()`
class SpecialIterator<R> extends Iterator<R>{}
SpecialIterator<String> strings =...;
SpecialIterator<Integer> ints = process(string, magicFunc);
The Iterator example starts to break down, so here's a more concrete example:
I have 3 classes: AbstractTester, StringTester, and ListTester
class AbstractTester<R, T extends AbstractTester<R, ? super T>>
class StringTester<R> extends AbstractTester<R, StringTester<R>>
class ListTester<R, T extends AbstractTester<R, ? super T>>
I want to make a method in AbstractListTest like this: public <Z> T<Z> convert(Z z)
I have supporting code in my classes to create an return an instance of type T<Z>, but I cannot express the type T<Z> in the type system. The type parameter T can extend something with a type parameter, and be passed a type with a type parameter, but it cannot be defined to have a type parameter itself.
This is for a fluent api framework, where I need the compiler to know the type T<Z> without casting
I can do something like this: public <Z, Y extends AbstractTester<Z, ? super T>> Y convert(Z z);
but that will return an AbstractTester<Z> which can be cast to a StringTester<Z>, but the compiler does not know it is a StringTester<Z>
A subclass of AbstractTester is not required to have any type parameters itself. Converting a T to a T<Z> would not be legal for a T without a type parameter. To do what I want, Java would need to add a new type bounds operator to restrict a type parameter to subclasses with a particular type parameter.
Java would need to allow me to define ListTester like this to restrict T to only subclasses with a type parameter:
class ListTester<R, T<_> extends AbstractTester<_, ? super T<_>>
I'd love to be wrong, and would be very grateful to find a way to do this.
baz(bar(foo(t, f)));
T<A> should go into foo(..) and come out (e.g. as T<B>) such that I can then call bar(..) on it.But in this case it leaves foo(..) as R extends Fooable, which is not something I can pass into bar(..).
foo.doSomething() // returns Iterable.
.doSomethingElse(); // Iterable doesn't implement doSomethingElse();I'm curious what your were working on where you ran into this?
* At the same job, a coworker expressed a desire to rewrite it with Observables.
* At a different job, a different coworker rewrote a chunk of code from Observables into futures.
* At my current job, we use micronaut, which has announced it's switching from rxjava2 to project reactor.
In the above cases, having interfaces would really help in changing the code piece-by-piece. And the rewrites wouldn't be necessary if they were behind interfaces.
In the general case I just want to program to the interface, and not pin my business logic to any particular implementation.
public <Z, T extends Collection<Z>> List<Z> process(T collectionOfInteger) { return collectionOfInteger.stream() .collect(toList()); }
These are the three implementations I want to hide behind a single abstraction:
// java.util.Optional
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
// java.util.concurrent.CompletionStage:
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
// java.util.stream.Stream:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Any suggestions? public <T, Z, F extends Function<? super T, Z>> Z apply(Function<F, Z> target, F fn) {
return target.apply(fn);
}
@Test
public void test() throws Exception {
Stream<String> stream = Stream.of("foo", "bar", "baz");
stream = apply(stream::flatMap, s -> Stream.of(s + "_a", s + "_b"));
System.out.println(stream.collect(toList()));
Optional<String> bean = Optional.of("bean");
bean = apply(bean::flatMap, b -> Optional.of("soy"));
System.out.println(bean);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> future2 = apply(future1::thenCompose, string -> CompletableFuture.supplyAsync(() -> string + " world"));
System.out.println(future2.get());
}
Output:[foo_a, foo_b, bar_a, bar_b, baz_a, baz_b]
Optional[soy]
hello world
I'm trying to figure out how to refer to flatMap directly from the abstract function, e.g.
flatMapTwice(x, fun) {
return x.flatMap(fun).flatMap(fun);
}
or chain(x, fun1, fun2) {
return x.flatMap(fun1).flatMap(fun2);
}
It should also preserve the type information (just like you did above). I don't want the caller to need to downcast from FlatMappable.It doesn't need to be x.flatMap(f) - I'd be interested seeing a flatMap(x, f) version.
public interface FlatMappable<T> {
<U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper);
}
public class FlatMappableOption<T> implements FlatMappable<T> {
private final Option<T> value;
public FlatMappableOption<T>(Option<T> value) {
this.value = value;
}
<U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
return value.flatMap(mapper);
}
}
// similar wrappers for CompletionStage and Stream
Now whenever you want to pass a Stream/CompletionStage/Option to something that accepts FlatMappable, you either a) already has it wrapped in FlatMappable, so pass that wrapper in; or b) has a naked value of known type, so wrap it in the propper wrapper class and pass the resulting wrapper in.Of course, it would be nice to have this wrapping done automatically instead of manually, but that's pretty much how it's actually implemented behind the scenes (dictionary passing, or look at Go's way to wrap things inside interface{}).
public <T extends Collection<Integer>> T process(T collectionOfInteger) { return collectionOfInteger; }
And basically your T will be as wide as the interface/class it extends in the generic parameter.
I guess the most Java way to do that would be using Iterable:
public <Z, T extends Iterable<Z>> T process(T iterable) { return iterable; }