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));
}
}
Related
I need to transform an arbitrary Collection<T> into another arbitrary Collection<U>. For example, I would like to transform an ArrayList<String> into a HashSet<Integer>.
I wrote the following code, which gives me a compile-time error on UCollection::new (Cannot resolve constructor 'UCollection'). I tried replacing it with () -> new UCollection(), which gives me another compile-time error (Type parameter 'UCollection' cannot be instantiated directly).
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Utils {
public static <T, U, TCollection extends Collection<T>, UCollection extends Collection<U>>
UCollection MappedCollection(TCollection collection, Function<T, U> function) {
return MappedStream(collection.stream(), function).collect(Collectors.toCollection(UCollection::new));
}
public static <T, U> Stream<U> MappedStream(Stream<T> stream, Function<T, U> function) {
return stream.map(function);
}
}
UCollection::new is invalid because UCollection is a type variable. You can't construct a type that you don't know in the method.
The easiest fix here is to make your caller supply a UCollection factory:
public static <T, U, TCollection extends Collection<T>,
UCollection extends Collection<U>>
UCollection MappedCollection(TCollection collection,
Function<T, U> function,
Supplier<UCollection> uCollectionSupplier) {
return MappedStream(collection.stream(), function)
.collect(Collectors.toCollection(uCollectionSupplier));
}
As a side note, I think you have one type variable too many. You could dispense with TCollection (using C for UCollection below)...
public static <T, U, C extends Collection<U>>
C mappedCollection(Collection<T> collection,
Function<T, U> function,
Supplier<C> collectionSupplier) {
return MappedStream(collection.stream(), function)
.collect(Collectors.toCollection(collectionSupplier));
}
I would suggest an output parameter instead of a result, as it allows interface based variables, already providing the correct implementation class. The other answer requires actually passing an ArrayList::new which is a bit unfortunately, though a result is more functional programming style.
public <P, R> void convert(Collection<P> cp, Collection<R> cr, Function<P, R> mapper) {
cp.stream().map(mapper).forEach(cr::add);
}
List<String> slist = new ArrayList<>();
Collections.addAll(slist, "2", "3", "5", "7", "5", "3");
Set<Integer> iset = new HashSet<>();
convert(slist, iset, Integer::valueOf);
System.out.println(iset);
Stream aggregating and collecting often has such a new collection supplier as parameter as in the other answer. But where the resulting collection is created seems irrelevant. And a result sometimes requires type inference (no interface vars, or needing a cast).
I would suggest a different, in my opinion more readable, solution:
public static <T, U> List<U> convert(Collection<T> collection, Function<T, U> mapper) {
return collection.stream()
.map(mapper)
.collect(Collectors.toList());
}
Ideone Demo
If you really need to control the exact collection type, then use ernest_k's approach by passing a Supplier<UCollection> supplier to the method:
public static <T, U, UCollection extends Collection<U>> UCollection convert(
Collection<T> collection,
Function<T, U> mapper,
Supplier<UCollection> collectionSupplier) {
return collection.stream()
.map(mapper)
.collect(Collectors.toCollection(collectionSupplier));
}
Ideone Demo
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.
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());
});
Just like java.util.Optional<T> in Java 8 is (somewhat) equivalent to Scala's Option[T] type, is there an equivalent to Scala's Either[L, R]?
There is no Either type is Java 8, so you need to create one yourself or use some third-party library.
You may build such a feature using the new Optional type (but read to the end of this answer):
final class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
public <T> T map(
Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc)
{
return left.<T>map(lFunc).orElseGet(()->right.map(rFunc).get());
}
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc)
{
return new Either<>(left.map(lFunc),right);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> rFunc)
{
return new Either<>(left, right.map(rFunc));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc)
{
left.ifPresent(lFunc);
right.ifPresent(rFunc);
}
}
Example use case:
new Random().ints(20, 0, 2).mapToObj(i -> (Either<String,Integer>)(i==0?
Either.left("left value (String)"):
Either.right(42)))
.forEach(either->either.apply(
left ->{ System.out.println("received left value: "+left.substring(11));},
right->{ System.out.println("received right value: 0x"+Integer.toHexString(right));}
));
In retrospective, the Optional based solution is more like an academic example, but not a recommended approach. One problem is the treatment of null as “empty” which contradicts the meaning of “either”.
The following code shows an Either that considers null a possible value, so it’s strictly “either”, left or right, even if the value is null:
abstract class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<L,R>() {
#Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return lFunc.apply(value);
}
};
}
public static <L,R> Either<L,R> right(R value) {
return new Either<L,R>() {
#Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return rFunc.apply(value);
}
};
}
private Either() {}
public abstract <T> T map(
Function<? super L, ? extends T> lFunc, Function<? super R, ? extends T> rFunc);
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc) {
return this.<Either<T,R>>map(t -> left(lFunc.apply(t)), t -> (Either<T,R>)this);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> lFunc) {
return this.<Either<L,T>>map(t -> (Either<L,T>)this, t -> right(lFunc.apply(t)));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc) {
map(consume(lFunc), consume(rFunc));
}
private <T> Function<T,Void> consume(Consumer<T> c) {
return t -> { c.accept(t); return null; };
}
}
It’s easy to change that to a strict rejection of null by simply inserting an Objects.requireNonNull(value) at the beginning of both factory methods. Likewise, adding support for an empty either would be imaginable.
At the time of writing, vavr (formerly javaslang) is probably the most popular functional Java 8 library. It is pretty similar to lambda-companion's Either in my other answer.
Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
There is no Either in the Java Standard Library. However there is an implementation of Either in FunctionalJava, along with many other nice classes.
cyclops-react has a 'right' biased either implementation called Xor.
Xor.primary("hello")
.map(s->s+" world")
//Primary["hello world"]
Xor.secondary("hello")
.map(s->s+" world")
//Secondary["hello"]
Xor.secondary("hello")
.swap()
.map(s->s+" world")
//Primary["hello world"]
Xor.accumulateSecondary(ListX.of(Xor.secondary("failed1"),
Xor.secondary("failed2"),
Xor.primary("success")),
Semigroups.stringConcat)
//failed1failed2
There is also a related type Ior which can act as an either or a tuple2.
disclosure I am the author of cyclops-react.
No, there is none.
Java language developers explicitly state that types like Option<T> are intended to be used only as temporary values (e.g. in stream operations results), so while they are the same thing as in other languages, they are not supposed to be used as they are used in other languages. So it is not surprising that there is no such thing as Either because it does not arise naturally (e.g. from stream operations) like Optional does.
There is a stand-alone implementation of Either in a small library, "ambivalence": http://github.com/poetix/ambivalence
You can get it from Maven central:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
lambda-companion has an Either type (and a few other functional types e.g. Try)
<dependency>
<groupId>no.finn.lambda</groupId>
<artifactId>lambda-companion</artifactId>
<version>0.25</version>
</dependency>
Using it is easy:
final String myValue = Either.right("example").fold(failure -> handleFailure(failure), Function.identity())