I'm playing around Java code in order to create a functional style monad, but I get struck while using generics and the Java compiler gives me a compilation error if I don't cast my object (though Generics would solve this problem!)
This is the usage:
//COMPILATION ERROR! It requires a cast to String
String message = If.of("Hi", s->s!=null).apply(s->s+" guys!").get();
Allowed:
This is my monad:
import java.util.function.Function;
import java.util.function.Predicate;
public class If<T, R> {
private T t;
private Predicate predicate;
private If(T t, Predicate predicate) {
this.t = t;
this.predicate = predicate;
}
public static<T> If of(T t, Predicate predicate) {
return new If(t, predicate);
}
public If<R,R> apply(Function<T, R> function) {
if(predicate!=null && predicate.test(t)){
return new If<R, R>(function.apply(t), null);
}
return If.of(this.t, null);
}
public T get() {
return t;
}
}
The direct issue is that the return type of the of method is raw:
public static<T> If of(T t, Predicate predicate) {
You presumably need it to be something like:
public static<T> If<T, Something> of(T t, Predicate<T> predicate) {
I would suggest you don't really want to bake the R into the If's type. If you declare it on the method instead, you then have the flexibility to apply it to whatever type you need:
public class If<T> {
// ...
public <R> If<R> apply(Function<T, R> function) {
if(predicate!=null && predicate.test(t)){
return new If<>(function.apply(t), null);
}
return If.of(this.t, null);
}
// ...
}
Then your of signature can be simply:
public static<T> If<T> of(T t, Predicate<T> predicate) {
If you want your API to be a bit more flexible, add wildcards:
public static<T> If<T> of(T t, Predicate<? super T> predicate) {
and
public <R> If<R> apply(Function<? super T, ? extends R> function) {
Andy Turner's answer explained the immediate why your current code does not compile, but your monad seems to have a more fundamental problem - it is not very useful.
According to you, the first call to apply should either return the transformed object wrapped in the monad if the condition is true, or the original object wrapped in a monad if the condition is false. But since you are passing null as the condition for both cases, any subsequent calls to apply will cause the second return to be reached, hence always returning the result of the first call to apply.
In fact, it is not possible to either return the original object or the transformed object (not in a useful and type-safe way, anyway). To do it type-safely, you'd need an Either<If<T>, If<R>> (assuming such a type existed). But to extract the values out of an Either, you'd still need an if statement, defeating the purpose of the If<T> class.
Apparently, this is just an exercise to practice writing monads. With that being the case, I recommend that you choose another monad to implement, such as Either. I also suggest you look at this post first.
Related
When you have a Stream of Objects you can filter on them pretty elegantly.
swimmingAnimalStream = animalStream
.filter(Animal::canSwim);
When you have slightly more complex filters instead of using Method references you have to use Lambdas.
greenAnimals = animalStream
.filter(animal -> animal.getColor().equals(Colors.GREEN));
Is there a way to map the value before filtering on it, but still have the complete object after the filter?
So the fallowing is not what I want:
animalStream
.map(Animal::getColor)
.filter(Colors.GREEN::equals)
With this I would be left with color information only.
What I also would like to avoid is extracting the method. I am looking for a more streamlined way of doing this. Something like this for example:
animalStream
.filter(Colors.GREEN::equals, Animal::getColor);
The method signature of this filter method would look like this.
<MAPPED> Stream<T> filter(Predicate<MAPPED> filter, Function<? super T, MAPPED> mappingFunction);
Even better would be a version where you could join multiple mapping functions. On the fly one could maybe use a varargs for the mappingFunction. But I honestly don’t know how that would be possible with Generics. But that’s a different story.
The solution should also be able to use whatever Predicate that one could imagine. Equals is just an Example. Another example would be to check if a field from the object is present.
animalWithMotherStream = animalStream
.filter(Optional::isPresent, Animal::getMother);
Does anyone now a cleaner Solution, or a library that does this already?
Java 16
Yes, there is a solution using Stream#mapMulti as of Java 16.
animalStream
.mapMulti((animal, consumer) -> {
if (Colors.GREEN.equals(animal.getColor())) { // condition
consumer.accept(animal); // qualify the instance
}
})
... // further operations
The provided Consumer<R> accepts the instance that is qualified based on your criteria.
Pros: The performance-wise advantage of this imperative approach is that you don't necessarily invoke the two Stream operations but just one, for example, a combination of Stream#map and Stream#filter can be substituted. Though the biggest advantage is that Consumer#accept can be invoked as many times as you want, so you can effectively increase a number of entries in a Stream.
Cons: However, you lost a bit of the declarative approach and if used only as on the snippet without further processing, it's worth using rather a simple for-loop or sticking with the filter operation (see below):
Older Java versions
Simply write the condition down to Stream#filter, it's a correct Stream usage:
animalStream
.filter(animal -> Colors.GREEN.equals(animal.getColor()))
...
You can use Guava's Predicates.compose(), or create your own:
public static <A, B> Predicate<A> compose(
Predicate<B> predicate, Function<A, ? extends B> function) {
return a -> predicate.test(function.apply(a));
}
Now just pass that into your filter:
animalStream.filter(compose(Colors.GREEN::equals, Animal::getColor))
As for the varargs concept, I doubt that's possible under Java's generics, unless they're all of the same type, in which case you'd just apply() each in a loop or reduce them with Function.andThen().
StreamEx, a library that provides extended stream methods and classes, has filterBy:
public <K> StreamEx<T> filterBy(Function<? super T,? extends K> mapper, K value)
Returns a stream consisting of the elements of this stream for which the supplied mapper function returns the given value.
This method behaves like filter(t -> Objects.equals(value, mapper.apply(t))).
filter accepts a Predicate, whose function can only return a boolean. There's no other method signature.
If you want to filter by all green animals, you'd use
animalStream
.filter(a -> Colors.GREEN.equals(a.getColor()))
or
Predicate<Animal> isGreen = (a) -> Colors.GREEN.equals(a.getColor());
Stream<Animal> greenAnimals = animalStream.filter(isGreen);
Don't use map unless you want a Stream<COLOR>
join multiple mapping functions
You can chain them, rather than join - .stream().map().map(), but as you discovered, this does not preserve the original type.
Operation Stream.filter() expects a Predicate which is a function producing a boolean result. This definition of the filter is very intuitive and self-contained, and there are no other flavors of filter (and I doubt if they will appear in the future).
However, you can create your implementation of Predicate and give it all the behavior you need. And as a Predicate, it would be eligible to be used in the filter.
Before introducing the implementation, I'll show some of the capabilities that can be given to such custom Predicate.
Stream<Animal> greenAnimals = animalStream
.filter(
MultiPred.ofOr(Animal::getColor, Color.WHITE::equals, Color.GREEN::equals)
.or(
MultiPred.of(Animal::getType, AnimalType.CARNIVORE::equals)
.and(Animal::canFly) // we can chain custom Predicates with regular ones
)
.or(
MultiPred.of(Animal::getType, AnimalType.HERBIVORE::equals)
.and(MultiPred.of(Animal::getColor, Color.PURPLE::equals)
.or(Animal::canSwim)
)
)
);
Here's a dummy class Animal and enums used in the example above:
public class Animal {
private AnimalType type;
private boolean canSwim;
private boolean canFly;
private Color color;
// getters
}
public enum AnimalType {
CARNIVORE, HERBIVORE
}
public enum Color {
GREEN, WHITE, PURPLE
}
Implementation
You can provide a custom Predicate with any capabilities you require.
The following predicate expects exposes methods expecting a keyExtractor function and a predicate, or a group of predicates that has to be chained with either logical OR ||, or logical AND &&.
public class MultiPred<T, K> implements Predicate<T> {
private final BiFunction<Function<T, K>, Predicate<K>, Predicate<T>>
predicateProducer = (f, p) -> t -> p.test(f.apply(t));
private final Predicate<T> p;
private MultiPred(Function<T, K> keyExtractor,
Predicate<K> predicate) {
this.p = predicateProducer.apply(keyExtractor, predicate);
}
#SafeVarargs
public static <T, K> MultiPred<T, K> ofAnd(Function<T, K> keyExtractor,
Predicate<K>... predicates) {
return of(keyExtractor, k -> true, Predicate::and, predicates);
}
#SafeVarargs
public static <T, K> MultiPred<T, K> ofOr(Function<T, K> keyExtractor,
Predicate<K>... predicates) {
return of(keyExtractor, k -> false, Predicate::or, predicates);
}
#SafeVarargs
public static <T, K> MultiPred<T, K> of(Function<T, K> keyExtractor,
Predicate<K> identity,
BinaryOperator<Predicate<K>> op,
Predicate<K>... predicates) {
Objects.requireNonNull(predicates);
Predicate<K> predicate = Arrays.stream(predicates).reduce(identity, op);
return new MultiPred<>(keyExtractor, predicate);
}
public static <T, K> MultiPred<T, K> of(Function<T, K> keyExtractor,
Predicate<K> predicate) {
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(predicate);
return new MultiPred<>(keyExtractor, predicate);
}
#Override
public boolean test(T t) {
Objects.requireNonNull(t);
return p.test(t);
}
#Override
public Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return p.and(other);
}
#Override
public Predicate<T> negate() {
return p.negate();
}
#Override
public Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return p.or(other);
}
}
Utility Class for constructing Predicates
The logic from the class above can materialized as a utility class exposing a bunch static method for generating Predicates. It would preserve all the capacities shown in usage example at the beginning.
(Credits for this idea belong to #Holger and #shmosel, since he posted the static method producing a predicate earlier, hence the code shown below should be considered as built on the answer by #shmosel)
public static class MultiPred {
private MultiPred() {}
#SafeVarargs
public static <T, K> Predicate<T> ofAnd(Function<T, K> keyExtractor,
Predicate<K>... predicates) {
return of(keyExtractor, k -> true, Predicate::and, predicates);
}
#SafeVarargs
public static <T, K> Predicate<T> ofOr(Function<T, K> keyExtractor,
Predicate<K>... predicates) {
return of(keyExtractor, k -> false, Predicate::or, predicates);
}
#SafeVarargs
public static <T, K> Predicate<T> of(Function<T, K> keyExtractor,
Predicate<K> identity,
BinaryOperator<Predicate<K>> op,
Predicate<K>... predicates) {
Objects.requireNonNull(predicates);
Predicate<K> predicate = Arrays.stream(predicates).reduce(identity, op);
return getPredicateProducer(keyExtractor, predicate);
}
public static <T, K> Predicate<T> of(Function<T, K> keyExtractor,
Predicate<K> predicate) {
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(predicate);
return getPredicateProducer(keyExtractor, predicate);
}
private static <T, K> Predicate<T> getPredicateProducer(Function<T, K> keyExtractor,
Predicate<K> predicate) {
return t -> predicate.test(keyExtractor.apply(t));
}
}
I'm looking for a "proper" way to reduce the Java boilerplate involved in retrieving/modifying the generic type arguments at compile time. Usually, this boilerplate involves:
Using #SuppressWarnings("unchecked").
Spelling out explicitly the target generic type arguments.
Usually, creating an otherwise useless local variable just so that the supression can be applied to that staement only.
As a theoretical example, suppose I want to keep a map of Class to Supplier such that for each keyClass, its associated valueSupplier produces objects extending keyClass.
Edit 2: I changed the example from a map of Class to Class, to a map of Class to Supplier, because (the value) Class objects are special with respect to casts, and the original example had another solution not involving unchecked casts (thanks #Holger). Again, I'm only adding an example to illustrate the problem, I don't need to solve any particular example.
Edit 1: More precisely, a single SupplierMap object is populated say from a config file, and holds info such as "objects implementing interface I1 are provided by supplier S1", "I2 by S2", and so on. At runtime, we get calls such as I1 i1 = supplierMap.get(I1.class).get() which should produce an object with i1.getClass() == C1.class. I'm not interested in fixes/shortcuts, e.g. moving the cast to where it does not belong, such as having get() return Supplier<Object>. The cast belongs conceptually inside the SupplierMap. Also, I don't much care about this specific example, but about the general language problem.
With SupplierMap, I don't believe there is a way to capture the key-value generic parameter relation in Java so that the get() does not involve an unchecked compile-time cast. Concretely I could have:
class SupplierMap {
// no way to say in Java that keys and values are related
Map<Class<?>, Supplier<?>> map;
// can check the relation at compile time for put()
<T> void put(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, valueSupplier);
}
// but not for get()
<T> Supplier<? extends T> get(Class<T> keyClass) {
#SuppressWarnings("unchecked")
final Supplier<? extends T> castValueSupplier = (Supplier<? extends T>) map.get(keyClass);
return castValueSupplier;
}
}
As an alternative, one could have:
#SupressWarnings("unchecked")
<T> T uncheckedCast(Object o) {
return (T) o;
}
<T> Supplier<? extends T> get(Class<T> keyClass) {
return uncheckedCast(map.get(keyClass));
}
That looks much better, but the problem is that uncheckedCast is arguably too powerful: it can potentially cast anything into anything else at compile time (by hiding warnings). At runtime we'd still get CCE's, but that's not the point here. (The argument goes that ...) If one were to put this uncheckedCast into a library, the function could be abused to hide problems otherwise detectable at compile-time.
Is there a way to define such a similar unchecked cast function so that the compiler can enforce that it is only used to change generic type parameters?
I tried:
// error at T<U>: T does not have type parameters
<T, U> T<U> uncheckedCast(T t) {
return (T<U>) t;
}
also
<T, U extends T> U uncheckedCast(T t) {
return (U) t;
}
void test() {
Class<?> aClass = String.class;
// dumb thing to do, but illustrates cast error:
// type U has incompatible bounds: Class<capture of ?> and Class<Integer>
Class<Integer> iClass = uncheckedCast(aClass);
}
Edit: Have you seen this kind of an unchecked cast (even the all-powerful one above) in a common library? I looked in Commons Lang and Guava, but the only one I could find is Chronicle Core's ObjectUtils.convertTo(): there, passing eClass == null is equivalent to the all-powerful uncheckedCast, except that it also produces an undesired #Nullable (that is used by other branches).
You said
Also, I don't much care about this specific example, but about the general language problem.
but actually, this kind of problem should always be handled in relation to the actual problem you’re trying to solve. I’d go that far to say that this happens rarely enough, so a general utility method for doing unchecked casts regardless of the actual use case would not be justified.
Considering the SupplierMap, you said
I don't believe there is a way to capture the key-value generic parameter relation in Java so that the get() does not involve an unchecked compile-time cast.
That’s nailing the problem and pointing to the clean solution. You have to create a relationship between the key and value, e.g.
class SupplierMap {
static final class SupplierHolder<T> {
final Class<T> keyClass;
final Supplier<? extends T> valueSupplier;
SupplierHolder(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
this.keyClass = keyClass;
this.valueSupplier = valueSupplier;
}
#SuppressWarnings("unchecked") // does check inside the method
<U> SupplierHolder<U> cast(Class<U> type) {
if(type != keyClass) throw new ClassCastException();
return (SupplierHolder<U>)this;
}
}
Map<Class<?>, SupplierHolder<?>> map = new HashMap<>();
<T> void put(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, new SupplierHolder<>(keyClass, valueSupplier));
}
<T> Supplier<? extends T> get(Class<T> keyClass) {
return map.get(keyClass).cast(keyClass).valueSupplier;
}
}
Here, the unchecked type cast is inside a method that performs an actual check allowing the reader to be confident about the correctness of the operation.
That’s a pattern that is actually used in real life code. Which hopefully addresses your question “Have you seen this kind of an unchecked cast (even the all-powerful one above) in a common library?”. I don’t think that any library uses a “do-entirely-unchecked” method, but rather, they have methods with a visibility as narrow as possible and likely tailored to the actual use case.
Yes, that means “boilerplate”. Which is not bad for an operation that the developer should really spend some seconds, before proceeding.
Note that this can be expanded to examples completely working without using Class as token:
interface SomeKey<T> {}
class SupplierMap {
static final class SupplierHolder<T> {
final SomeKey<T> keyClass;
final Supplier<? extends T> valueSupplier;
SupplierHolder(SomeKey<T> keyToken, Supplier<? extends T> valueSupplier) {
this.keyClass = keyToken;
this.valueSupplier = valueSupplier;
}
#SuppressWarnings("unchecked") // does check inside the method
<U> SupplierHolder<U> cast(SomeKey<U> type) {
if(type != keyClass) throw new ClassCastException();
return (SupplierHolder<U>)this;
}
}
Map<SomeKey<?>, SupplierHolder<?>> map = new HashMap<>();
<T> void put(SomeKey<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, new SupplierHolder<>(keyClass, valueSupplier));
}
<T> Supplier<? extends T> get(SomeKey<T> keyClass) {
return map.get(keyClass).cast(keyClass).valueSupplier;
}
}
Which allows more than one key with the same type:
enum MyStringKeys implements SomeKey<String> {
SAY_HELLO, SAY_GOODBYE
}
public static void main(String[] args) {
SupplierMap m = new SupplierMap();
m.put(MyStringKeys.SAY_HELLO, () -> "Guten Tag");
m.put(MyStringKeys.SAY_GOODBYE, () -> "Auf Wiedersehen");
System.out.println(m.get(MyStringKeys.SAY_HELLO).get());
Supplier<? extends String> s = m.get(MyStringKeys.SAY_GOODBYE);
String str = s.get();
System.out.println(str);
}
The crucial part is that the now-unavoidable unchecked cast is still augmented with an actual check for the key validity. I’d never allow it without.
This doesn’t preclude scenarios where you really can’t check the correctness at all. But then, it is a good think that verbose artifacts like the #SuppressWarnings("unchecked") annotation indicate this right at the point where it is needed. A convenience method would only hide the problem, which is still there, even if we had a possibility to restrict its usage to generic types.
Answer to the previous revision of the question:
That’s actually easier than you think:
class ImplMap {
Map<Class<?>, Class<?>> map;
<T> void put(Class<T> keyClass, Class<? extends T> valueClass) {
map.put(keyClass, valueClass);
}
<T> Class<? extends T> get(Class<T> keyClass) {
final Class<?> implClass = map.get(keyClass);
return implClass.asSubclass(keyClass);
}
}
This is not an unchecked operation, as the method asSubclass really checks whether the implClass class is a subclass of keyClass. Assuming that the map has been populated via the put method only, without any unchecked operations, this test will never fail.
The only thing that differs, is the treatment of null, e.g. when the key was not present in the map. Unlike a cast, this would throw an exception, as it is a method invocation.
So if calling this method with absent keys is allowed and should result in null, it must be handled explicitly:
<T> Class<? extends T> get(Class<T> keyClass) {
final Class<?> implClass = map.get(keyClass);
return implClass == null? null: implClass.asSubclass(keyClass);
}
Note that likewise, the method
#SupressWarnings("unchecked")
<T> T uncheckedCast(Object o) {
return (T) o;
}
is unnecessary if you have the Class object, as then, you can invoke cast on it.
E.g., the following would be a valid addition to your ImplMap class:
<T> T getInstance(Class<T> keyClass) {
try {
return keyClass.cast(map.get(keyClass).getConstructor().newInstance());
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}
As an additional note, registering interface implementation via configuration files sounds like you should have a look at the ServiceLoader API and the underlying mechanisms. See also the Creating Extensible Applications chapter of the Java tutorial.
Why don't you try something like this, instead of declaring the types individually for functions, make the class generic and class handles this T types of Class instances.
class ImplMap<T> {
// Values are already related here
Map<Class<T>, Class<? extends T>> map;
// Already compiler aware of the type.
void put(Class<T> keyClass, Class<? extends T> valueClass) {
map.put(keyClass, valueClass);
}
// Compiler already aware of the type just like with 'put'.
Class<? extends T> get(Class<T> keyClass) {
return map.get(keyClass);
}
}
This doesn't involve unchecked cast since the type relationship already defined with the Map declaration and no need to SuppressWarning (Compiler doesn't warn).
Although compiler would warn about unchecked call when invoke the put and get function if you don't define type on ImplMap object creation as it not takes a type at all and if you define a type, you can put that type of keys only into that map which duplicates.
I have a set of domain objects that inherit from a shared type (i.e. GroupRecord extends Record, RequestRecord extends Record). The subtypes have specific properties (i.e. GroupRecord::getCumulativeTime, RequestRecord::getResponseTime).
Further, I have a list of records with mixed subtypes as a result of parsing a logfile.
List<Record> records = parseLog(...);
In order to compute statistics on the log records, I want to apply math functions only on a subset of the records that matches a specific subtype, i.e. only on GroupRecords. Therefore I want to have a filtered stream of specific subtypes. I know that I can apply a filter and map to a subtype using
records.stream()
.filter(GroupRecord.class::isInstance)
.map(GroupRecord.class::cast)
.collect(...
Apply this filter&cast on the stream multiple times (especially when doing it for the same subtype multiple times for different computations) is not only cumbersome but produces lots of duplication.
My current approach is to use a TypeFilter
class TypeFilter<T>{
private final Class<T> type;
public TypeFilter(final Class<T> type) {
this.type = type;
}
public Stream<T> filter(Stream<?> inStream) {
return inStream.filter(type::isInstance).map(type::cast);
}
}
To be applied to a stream:
TypeFilter<GroupRecord> groupFilter = new TypeFilter(GroupRecord.class);
SomeStatsResult stats1 = groupFilter.filter(records.stream())
.collect(...)
SomeStatsResult stats2 = groupFilter.filter(records.stream())
.collect(...)
It works, but I find this approach a bit much for such a simple task. Therefore I wonder, is there a better or what is the best way for making this behavior reusable using streams and functions in a concise and readable way?
It depends on what do you find "more concise and readable". I myself would argue that the way you already implemented is fine as it is.
However, there is indeed a way to do this in a way that is slightly shorter from the point of where you use it, by using Stream.flatMap:
static <E, T> Function<E, Stream<T>> onlyTypes(Class<T> cls) {
return el -> cls.isInstance(el) ? Stream.of((T) el) : Stream.empty();
}
What it would do is it will convert each original stream element to either a Stream of one element if the element has expected type, or to an empty Stream if it does not.
And the use is:
records.stream()
.flatMap(onlyTypes(GroupRecord.class))
.forEach(...);
There are obvious tradeoffs in this approach:
You do lose the "filter" word from your pipeline definition. That may be more confusing that the original, so maybe a better name than onlyTypes is needed.
Stream objects are relatively heavyweight, and creating so much of them may result in performance degradation. But you should not trust my word here and profile both variants under heavy load.
Edit:
Since the question asks about reusing filter and map in slightly more general terms, I feel like this answer can also discuss a little more abstraction. So, to reuse filter and map in general terms, you need the following:
static <E, R> Function<E, Stream<R>> filterAndMap(Predicate<? super E> filter, Function<? super E, R> mapper) {
return e -> filter.test(e) ? Stream.of(mapper.apply(e)) : Stream.empty();
}
And original onlyTypes implementation now becomes:
static <E, R> Function<E, Stream<R>> onlyTypes(Class<T> cls) {
return filterAndMap(cls::isInstance, cls::cast);
}
But then, there is yet again a tradeoff: resulting flat mapper function will now hold captured two objects (predicate and mapper) instead of single Class object in above implementation. It may also be a case of over-abstracting, but that one depends on where and why you would need that code.
You don’t need an entire class to encapsulate a piece of code. The smallest code unit for that purpose, would be a method:
public static <T> Stream<T> filter(Collection<?> source, Class<T> type) {
return source.stream().filter(type::isInstance).map(type::cast);
}
This method can be used as
SomeStatsResult stats1 = filter(records, GroupRecord.class)
.collect(...);
SomeStatsResult stats2 = filter(records, GroupRecord.class)
.collect(...);
If the filtering operation isn’t always the first step in your chain, you may overload the method:
public static <T> Stream<T> filter(Collection<?> source, Class<T> type) {
return filter(source.stream(), type);
}
public static <T> Stream<T> filter(Stream<?> stream, Class<T> type) {
return stream.filter(type::isInstance).map(type::cast);
}
However, if you have to repeat this operation multiple times for the same type, it might be beneficial to do
List<GroupRecord> groupRecords = filter(records, GroupRecord.class)
.collect(Collectors.toList());
SomeStatsResult stats1 = groupRecords.stream().collect(...);
SomeStatsResult stats2 = groupRecords.stream().collect(...);
not only eliminating the code duplication in source code, but also performing the runtime type checks only once. The impact of the required additional heap space depends on the actual use case.
WHAT you actually need is a Collector to collecting all elements in the stream that is instance of special type. It can solving your problem easily and avoiding filtering the stream twice:
List<GroupRecord> result = records.stream().collect(
instanceOf(GroupRecord.class, Collectors.toList())
);
SomeStatsResult stats1 = result.stream().collect(...);
SomeStatsResult stats2 = result.stream().collect(...);
AND you can do something as further like as Stream#map by using Collectors#mapping, for example:
List<Integer> result = Stream.of(1, 2L, 3, 4.)
.collect(instanceOf(Integer.class, mapping(it -> it * 2, Collectors.toList())));
| |
| [2,6]
[1,3]
WHERE you only want to consuming the Stream once, you can easily composing the last Collector as below:
SomeStatsResult stats = records.stream().collect(
instanceOf(GroupRecord.class, ...)
);
static <T, U extends T, A, R> Collector<T, ?, R> instanceOf(Class<U> type
, Collector<U, A, R> downstream) {
return new Collector<T, A, R>() {
#Override
public Supplier<A> supplier() {
return downstream.supplier();
}
#Override
public BiConsumer<A, T> accumulator() {
BiConsumer<A, U> target = downstream.accumulator();
return (result, it) -> {
if (type.isInstance(it)) {
target.accept(result, type.cast(it));
}
};
}
#Override
public BinaryOperator<A> combiner() {
return downstream.combiner();
}
#Override
public Function<A, R> finisher() {
return downstream.finisher();
}
#Override
public Set<Characteristics> characteristics() {
return downstream.characteristics();
}
};
}
Why did you need to composes Collectors?
Did you remember Composition over Inheritance Principle? Did you remember assertThat(foo).isEqualTo(bar) and assertThat(foo, is(bar)) in unit-test?
Composition is much more flexible, it can reuses a piece of code and composeing components together on runtime, that is why I prefer hamcrest rather than fest-assert since it can composing all possible Matchers together. and that is why functional programming is most popular since it can reuses any smaller piece of function code than class level reusing. and you can see jdk has introduced Collectors#filtering in jdk-9 that will make the execution routes shorter without losing its expressiveness.
AND you can refactoring the code above according to Separation of Concerns as further, then filtering can be reused like as jdk-9 Collectors#filtering:
static <T, U extends T, A, R> Collector<T, ?, R> instanceOf(Class<U> type
, Collector<U, A, R> downstream) {
return filtering(type::isInstance, Collectors.mapping(type::cast, downstream));
}
static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate
, Collector<T, A, R> downstream) {
return new Collector<T, A, R>() {
#Override
public Supplier<A> supplier() {
return downstream.supplier();
}
#Override
public BiConsumer<A, T> accumulator() {
BiConsumer<A, T> target = downstream.accumulator();
return (result, it) -> {
if (predicate.test(it)) {
target.accept(result, it);
}
};
}
#Override
public BinaryOperator<A> combiner() {
return downstream.combiner();
}
#Override
public Function<A, R> finisher() {
return downstream.finisher();
}
#Override
public Set<Characteristics> characteristics() {
return downstream.characteristics();
}
};
}
I want to create an IdentityHashMap<Class<T>, Consumer<T>>. Basically, I want to map a type with a method saying what to do with this type.
I want to dynamically be able to say with objects X, execute Y. I can do
private IdentityHashMap<Class<?>, Consumer<?>> interceptor = new IdentityHashMap<>();
but it sucks because then I have to cast the object in the lamba when using it.
Example:
interceptor.put(Train.class, train -> {
System.out.println(((Train)train).getSpeed());
});
What I would like to do is
private <T> IdentityHashMap<Class<T>, Consumer<T>> interceptor = new IdentityHashMap<>();
But it doesn't seem to be allowed. Is there a way to do this ? What is the best workaround to map types with a method for this type ?
This is essentially just like the type-safe heterogeneous container described by Joshua Bloch, except you can't use the Class to cast the result.
Weirdly, I can't find a great example existing on SO, so here is one:
package mcve;
import java.util.*;
import java.util.function.*;
class ClassToConsumerMap {
private final Map<Class<?>, Consumer<?>> map =
new HashMap<>();
#SuppressWarnings("unchecked")
public <T> Consumer<? super T> put(Class<T> key, Consumer<? super T> c) {
return (Consumer<? super T>) map.put(key, c);
}
#SuppressWarnings("unchecked")
public <T> Consumer<? super T> get(Class<T> key) {
return (Consumer<? super T>) map.get(key);
}
}
That's type-safe, because the relation between keys and values is enforced by the signature of the put method.
One annoying thing about the limitations of Java's generics is that one of these containers can't be written for a generic value type, because there's no way to do e.g.:
class ClassToGenericValueMap<V> {
...
public <T> V<T> put(Class<T> key, V<T> val) {...}
public <T> V<T> get(Class<T> key) {...}
}
Other notes:
I would use a regular HashMap or a LinkedHashMap for this. HashMap is better maintained and has many optimizations that IdentityHashMap doesn't have.
If it's necessary to use generic types, like Consumer<List<String>>, then you need to use something like Guava TypeToken as the key, because Class can only represent the erasure of a type.
Guava has a ClassToInstanceMap for when you need a Map<Class<T>, T>.
Sometimes people want to do something like this, with a class-to-consumer map:
public <T> void accept(T obj) {
Consumer<? super T> c = get(obj.getClass());
if (c != null)
c.accept(obj);
}
That is, given any object, find the consumer in the map bound to that object's class and pass the object to the consumer's accept method.
That example won't compile, though, because getClass() is actually specified to return a Class<? extends |T|>, where |T| means the erasure of T. (See JLS §4.3.2.) In the above example, the erasure of T is Object, so obj.getClass() returns a plain Class<?>.
This issue can be solved with a capturing helper method:
public void accept(Object obj) {
accept(obj.getClass(), obj);
}
private <T> void accept(Class<T> key, Object obj) {
Consumer<? super T> c = get(key);
if (c != null)
c.accept(key.cast(obj));
}
Also, if you want a modified version of get which returns any applicable consumer, you could use something like this:
public <T> Consumer<? super T> findApplicable(Class<T> key) {
Consumer<? super T> c = get(key);
if (c == null) {
for (Map.Entry<Class<?>, Consumer<?>> e : map.entrySet()) {
if (e.getKey().isAssignableFrom(key)) {
#SuppressWarnings("unchecked")
Consumer<? super T> value =
(Consumer<? super T>) e.getValue();
c = value;
break;
}
}
}
return c;
}
That lets us put general supertype consumers in the map, like this:
ctcm.put(Object.class, System.out::println);
And then retrieve with a subtype class:
Consumer<? super String> c = ctcm.findApplicable(String.class);
c.accept("hello world");
Here's a slightly more general example, this time using UnaryOperator and no bounded wildcards:
package mcve;
import java.util.*;
import java.util.function.*;
public class ClassToUnaryOpMap {
private final Map<Class<?>, UnaryOperator<?>> map =
new HashMap<>();
#SuppressWarnings("unchecked")
public <T> UnaryOperator<T> put(Class<T> key, UnaryOperator<T> op) {
return (UnaryOperator<T>) map.put(key, op);
}
#SuppressWarnings("unchecked")
public <T> UnaryOperator<T> get(Class<T> key) {
return (UnaryOperator<T>) map.get(key);
}
}
The ? super bounded wildcard in the first example is specific to consumers, and I thought an example without wildcards might be easier to read.
It is possible to implement this in a type-safe manner without any unchecked cast. The solution resides in wrapping the Consumer<T> into a more general Consumer<Object> that casts and then delegates to the original consumer:
public class ClassToConsumerMap {
private final Map<Class<?>, Consumer<Object>> map = new IdentityHashMap<>();
public <T> Consumer<? super T> put(Class<T> key, Consumer<? super T> c) {
return map.put(key, o -> c.accept(key.cast(o)));
}
public <T> Consumer<? super T> get(Class<T> key) {
return map.get(key);
}
}
Depending on your needs, get() could also simply return a Consumer<Object>. This would be necessary if you only know the type at runtime, e.g.
classToConsumerMap.get(someObject.getClass()).accept(someObject);
I am pretty sure I saw this solution (or something similar) in a talk # Devoxx Belgium 2016, possibly from Venkat Subramaniam, but I definitively cannot find it back…
I can just let the IdentityHashMap with the usual Class<?> and Consumer<?>
private IdentityHashMap<Class<?>, Consumer<?>> interceptor = new IdentityHashMap<>();
And then I wrap the put operation in a method. This method accepts a type and a consumer of the same generic.
public <T> void intercept(Class<T> type, Consumer<T> consumer)
{
interceptor.put(type, consumer);
}
This lets me write
intercept(Train.class, train -> {
System.out.println(train.getSpeed());
});
The title basically says it all: if I have a java method that is generic in T, can I find out anything about T? In particular, can I check whether T implements a certain interface or extends a certain class?
I would like to do something like
public <T> List<T> doSth(List<T> l) {
if(T extends Comparable) {
// do one thing
} else {
// do another
}
return l;
}
Any hints?
Thanks a lot,
Johannes
It's not clear whether you want to perform the check at compile-time or at runtime. If you simply want to ensure that the list parameter passed to the method contains certain types of objects, then redefine T appropriately.
For example, to ensure that the compiler will only allow a List<Comparable> to be passed to this method, redefine T as:
public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
// Method body omitted
}
You can then use method-overloading (instead of an if-else statement), to ensure the correct code is called for any value of T. In other words, replace this:
public <T> List<T> doSth(List<T> l) {
if(T extends Comparable) {
// do one thing
} else {
// do another
}
return null
}
with these:
public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
// do one thing
return null;
}
public <T> List<T> doSth(List<T> l, Class<T> clazz) {
// do another
return null;
}
However, you need to remember choosing which overloaded method to call and generic-type checking is compile-time only! For example, the following code:
List<? extends Serializable> alist = new ArrayList<Integer>();
doSth(alist);
will actually call the second doSth method, because the compile-time type parameter (? extends Serializable) does not implement Comparable, even though the runtime type parameter (Integer) does.
No - due to type erasure. At execution time, you don't know the type of T at all.
One option would be to specify the type as another parameter:
public <T> List<T> doSth(List<T> l, Class<T> clazz) {
if (Comparable.class.isAssignableFrom(clazz)) {
...
}
}
yes, you can:
public <T> List<T> doSth(List<T> l) {
//You could also check every element, if there is a chance only some will be comparable
if (l.size() >0 && l.get(0) instanceof Comparable) {
// do one thing
} else {
// do another
}
return l;
}
Note that you are checking what type the elements in "l" are, NOT T - that is the key.
Edit: Changed the code to handle the fact that it was a list - I had missed that in my original reading.
You should already know at (even before! :) compile time whether T extends Comparable or not, so why not make two methods?
public <T extends Comparable<T>> List<T> doSthComp(List<T> l) {
// do one thing
return l;
}
public <T> List<T> doSth(List<T> l) {
// do another
return l;
}
You can do a
public <T extends Comparable<T>> List<T> doSth(List<T> l)
which will allow you to use the Comparable interface on items in 'l'
Well for compile time check Don already gave an answer. For the runtime it's only possible if you also pass a explicit object representing T, for example:
static <T> List<T> doSth(List<T> l, Class<T> tClass)
having tClass object representing real class of T you can check if it have implemented comparable via reflection. But compile-time check is much, much better from my point of view.