Applying Pattern matching for Instanceof in the Stream - java

Suppose we have a Stream of Animals.
We have different Subclasses of Animals, and we want to apply a filter on the stream to only have the Zebras of the Stream. We now still have a Stream of Animals, but only containing Zebras. To get a stream of Zebras we still need to cast.
Stream<Zebra> zebraStream = animalStream
.filter(Zebra.class::isInstance)
.map(Zebra.class::cast);
Java 14 introduced pattern matching for instanceof, so we can now use:
if (animal instanceof Zebra zebra) {
System.out.println(zebra.countStripes());
}
Is there a way to use pattern matching in stream pipes?
Of course you could do something like this:
Stream<Zebra> zebraStream = animalStream.map(animal -> {
if (animal instanceof Zebra zebra) {
return zebra;
}
return null;
})
.filter(Objects::nonNull);
But IMHO this is really ugly.

Pattern matching + mapMulti
To coerce a Stream of supertype to a Stream of one of its subtypes, you can make use of the Pattern matching for instanceof in conjunction with Java 16 mapMulti(), which expects a stream element and a Consumer of the resulting type:
Stream<Animal> animalStream = Stream.of();
Stream<Zebra> zebraStream = animalStream
.mapMulti((animal, consumer) -> {
if (animal instanceof Zebra zebra) consumer.accept(zebra);
});
Pattern matching + flatMap
To use Pattern matching for instanceof you can also employ a classic stream operation flatMap(), which is like mapMulti() is meant to perform one-to-many transformations.
The important distinction between the two is that mapMulti() replace the initial stream element with zero or more elements via its Consumer, meanwhile flatMap() require a producing a new Stream to flatten the data. And in this case utilizing mapMulti() would be more advantages because if the list is large generating singleton-streams for every element might be costful.
Stream<Zebra> zebraStream = animalStream
.flatMap(animal ->
animal instanceof Zebra zebra ? Stream.of(zebra) : null
);
Note that according to the documentation instead of an empty stream, we can also return null (which is handy because Stream.empty() doesn't return constant but spawns a new object):
If a mapped stream is null an empty stream is used, instead.

I think you are almost done it! Just use filter instead of map:
Stream<Zebra> zebraStream = animalStream.stream()
.filter(animal -> animal instanceof Zebra)
.map(Zebra.class::cast);

Related

Java 8 removing an item from array/array list based on regex

Is there a better way to achieve the following in java 8?
String regex = "^SACHI";
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
You can use
personalNames.removeIf(Pattern.compile("^SACHI").asPredicate());
You could also use the simpler
personalNames.removeIf(s -> s.matches("^SACHI"));
but it will perform Pattern.compile("^SACHI") under the hood, for every element in the worst case. Note that the Pattern created by compile is immutable and can be shared, hence, you could also create it only once, like
static final Pattern REMOVAL_PATTERN = Pattern.compile("^SACHI");
and use it like
personalNames.removeIf(REMOVAL_PATTERN.asPredicate());
asPredicate() uses find() instead of matches(), but since your pattern has the ^ anchor, it makes no difference. The method asMatchPredicate() for getting a predicate using matches() has been added in JDK 11.
If all you want, is to match a literal string at the beginning, you can also use
personalNames.removeIf(s -> s.startsWith("SACHI"));
which does not have the regex initialization overhead.
Adding and/or removing elements from an existing container does not fit in nicely with the concepts of functional programming. More over that behavior is not thread safe in parallel and concurrent environment. Making it thread safe demands more effort too. Therefore prefer steteless lambdas to stateful lambdas as a good engineering practice. You can get the matching names by merely using filter operator. Here's how it looks.
private static final Pattern PATTERN = Pattern.compile("^SACHI");
List<String> validNames = personalNames.stream()
.filter(PATTERN.asPredicate())
.collect(Collectors.toList());
It depends did you need to modify existing list, or you need just get list without elements.
In first case, you can use stream to filter non matching objects and remove them from list
personalNames.removeAll(
personalNames
.stream()
.filter(x -> !x.matches(regex))
.collect(Collectors.toList())
);
In other case, you can just return new list with only matching objects
final List<String> matchingElements = personalNames.stream()
.filter(x -> x.matches(regex))
.collect(Collectors.toList());
also, this code
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
will throw
java.util.ConcurrentModificationException
They are equivalent:
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
and
personalNames.removeIf(name -> name.matches(regex));
You can extract errorProneNames by filtering and removing respective error names from personalNames iterating forEach:
List<String> errorProneNames = personalNames.stream()
.filter(name -> !name.matches(regex))
.collect(Collectors.toList());
errorProneNames.forEach(personalNames::remove);
String regex = "^SACHI";
Predicate<String> f = n-> n.matches(regex);
personalNames.stream().filter(x->f.test(x))
.forEach(n-> {
personalNames.remove(n);
});
Using Predicate<T> to filter out the names which do not matches to String regex.
test(T t)
evaluates this predicate on the given argument.

Java 8 filter by attribute

I have a class which is of the following definition
public class MyClass {
int val;
type t;
}
Where type is an enum with values A,B,C,D,....
I have a list of objects of MyClass and I want to filter out the first element of each type occurring in the list.
for example :-
Given list:
{{1,A},{2,A},{4,B},{5,B},{3,C}}
Output:
{{1,A},{4,B},{3,C}}
Is there a way to use filter() of a stream of the list to solve this problem?
I'm not sure if there's a way to do this with a single Stream pipeline, but you can do it with two.
The first pipeline groups the objects by the val property (producing a Map<Integer,List<MyClass>>) and the second takes the first object of each List produced by the first pipeline and collects them into the output List:
List<MyClass>
filtered = mycl.stream ()
.collect (Collectors.groupingBy (c -> c.val))
.values ()
.stream ()
.map (l -> l.get (0))
.collect (Collectors.toList ());
Here is a solution which is not as elegant I hoped for but it works:
Set<MyType> typeSet = new HashSet<>();
List<MyClass> result = list.stream()
.filter(c -> typeSet.add(c.getType())).collect(
Collectors.toList());
I'm not sure if there is any direct way of doing it but you can achieve it by doing
1) First use streams's findFirst method with filter (TypeOf type).
2) do above steps for all types.
3) Merge all above data into one list.
One of good way to achieve this override equals() and hashCode() in your MyClass class. Check equality on the basis of 'type'. Then put your List in Set it will remove all duplicate. :)

Java Streams - Sort if Comparator exists

I have a class where optionally a Comparator can be specified.
Since the Comparator is optional, I have to evaluate its presence and execute the same stream code, either with sorted() or without:
if(comparator != null) {
[...].stream().map()[...].sorted(comparator)[...];
} else {
[...].stream().map()[...];
}
Question:
Is there a more elegant way to do this without the code duplication?
Note:
A default Comparator is not an option, I just want to keep the original order of the values I am streaming.
Besides, the elements are already mapped at the point of sorting, so I can not somehow reference the root list of the stream, as I do not have the original elements anymore.
You can do something like this:
Stream<Something> stream = [...].stream().map()[...]; // preliminary processing
if(comparator != null) {
stream = stream.sorted(comparator); // optional sorting
}
stream... // resumed processing, which ends in some terminal operation (such as collect)
Another way would be to use Optional:
Stream<Whatever> stream = [...].stream().map()[...];
List<WhateverElse> result = Optional.ofNullable(comparator)
.map(stream::sorted)
.orElse(stream)
.[...] // <-- go on with the stream pipeline
.collect(Collectors.toList());
You could define a comparator of your type (I used E as a placeholder here) that will not change the order:
Comparator<E> NO_SORTING = (one, other) -> 0;
If the comparator field is an Optional of Comparator, you can then use
.sorted(comparator.orElse(NO_SORTING))
If you don't mind use third party library StreamEx
StreamEx(source).[...].chain(s -> comparator == null ? s : s.sorted(comparator)).[...];
You can accomplish this using an auxiliary function.
static <T, R> R applyFunction(T obj, Function<T, R> f) {
return f.apply(obj);
}
and
applyFunction([...].stream().map()[...],
stream -> comparator == null ? stream : stream.sorted(comparator))
[...];
You don't need to know intermediate stream type.

RxJava - zip list of Observable

I have a list of Observables (RxJava 1).
List<Observable> observableList = new ArrayList<>();
It can contain at least 1 Observable. Each has the same type of the result.
How can I zip results of the all Observables?
I thought about zip-operator but it doesn't support List and I don't know quantity of observables (it can be 1,2,3,4....)
You can use the static zip(java.lang.Iterable<? extends Observable<?>> ws,FuncN<? extends R> zipFunction) method.
It is a zip method that takes an Iterable of Observables and a FuncN (which takes a varargs parameter for its call method) and uses it to combine the corresponding emitted Objects into the result to be omitted by the new returned Observable.
So for example you could do:
Observable.zip(observableList, new FuncN(){
public ReturnType call(java.lang.Object... args){
ReturnType result; //to be made
//preparatory code for using the args
for (Object obj : args){
ReturnType retObj = (ReturnType)obj;
//code to use the arg once at a time to combine N of them into one.
}
return result;
}
});
ReactiveX - Zip operator
Zip beyond BiFunction
Zip combine the emissions of multiple Observables together via a
specified function and emit single items for each combination based on
the results of this function
Here, list is an Array List of Observables of whichever type you want to pass.
val list = arrayListOf<Observable<ImageUrlResponse>>()
Observable.zip(list) { args -> Arrays.asList(args) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
val response = it[0]
val imageUrlResponse = imageUrlObject as ImageUrlResponse
urls.add(imageUrlResponse.imageUrl)}
}, {
val c = it
})
The Result of the following subscription is this image below. Just like we expect it to be zipped together. Also can you notice it returns all the responses to be zipped in a single java.lang.Object[].
Note I had to type cast my Array List to access my single object because it is of type Any!
I struggled with this as well, and used Sharan's solution as a base for mine.
My use case was doing API calls to several 3rd party providers, and then putting each individual result in a List. Each item in the list contains what the API returned, be it success or failure.
In the end it actually looks quite elegant. In my specific case "ResultType" was replaced with something like "ApiGenericResponseObject".
Observable.zip(listOfObservables, args -> {
List<ResultType> result = new ArrayList<>();
for (Object o: args) {
ResultType c = (ResultType) o;
// additional code here, I am just concatenating them together
// This gives me a list with the individual result of each Observable (for instance an API call)
result.add(c);
}
return result;
});
Alternatively, as a Lambda it looks neater. Though I wonder whether someone reading this will understand what is going on:
Observable.zip(listOfObservables, args -> Arrays.stream(args)
.map(object -> (ResultType) object)
.collect(Collectors.toList())
);
Hope it helps!

Java stream of optionals to optional stream

I need to convert Stream<Optional<Integer>> to Optional<Stream<Integer>>.
The output Optional<Stream<Integer>> should be an empty value when at least one value ofStream<Optional<Integer>> is empty.
Do you know any functional way to solve the problem? I tried to use collect method, but without success.
Well, the tricky thing here is that if you're just given a Stream, you can only use it once.
To be stateless and avoid redundant copying, one way is to just catch NoSuchElementException:
static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
try {
return Optional.of(
stream.map(Optional::get)
.collect(Collectors.toList())
.stream());
} catch (NoSuchElementException e) {
return Optional.empty();
}
}
A simple inversion would be:
static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
return Optional.of(stream.map(Optional::get));
}
But to find out if it contains an empty element, you need to actually traverse it which also consumes it.
If you're given the source of the stream, you can traverse it without collecting it:
static <T> Optional<Stream<T>> invert(
Supplier<Stream<Optional<T>>> supplier) {
// taking advantage of short-circuiting here
// instead of allMatch(Optional::isPresent)
return supplier.get().anyMatch(o -> !o.isPresent()) ?
Optional.empty() : Optional.of(supplier.get().map(Optional::get));
}
List<Optional<Integer>> myInts =
Arrays.asList(Optional.of(1), Optional.of(2), Optional.of(3));
Optional<Stream<Integer>> inverted = invert(myInts::stream);
That's probably a more interesting approach. (But it's prone to a race condition because the stream() is taken twice. If some other thread adds an empty element in between and gets away with it, we have a problem.)
Though this has already been answered yet to add to the list, with Java-9 introducing Optional.stream, this should be achievable as:
// initialized stream of optional
Stream<Optional<Integer>> so = Stream.empty();
// mapped stream of T
Stream<Integer> s = so.flatMap(Optional::stream);
// constructing optional from the stream
Optional<Stream<Integer>> os = Optional.of(s);
Similar to Radiodef's answer, though this one avoids the exception handling and the intermediate list.
private static <T> Optional<Stream<T>> invertOptional(Stream<Optional<T>> input) {
return input.map(integer -> integer.map(Stream::of))
.collect(Collectors.reducing((l, r) -> l.flatMap(lv -> r.map(rv -> Stream.concat(lv, rv)))))
.orElse(Optional.empty());
}
The way this works is it maps to a Stream of Optional Streams of T. The Optional.map is used in this case, so each one of the Optional<Stream<T>> items in the resultant stream is a either a Stream of 1, or an empty Optional.
Then it collects these streams by reducing them together. the l.flatMap will return an empty Optional if l is empty or the r.map returns an empty. if r.map isn't empty, it calls the Stream.concat, which combines the left and right stream values.
The whole collect reduction produces an Optional<Optional<Stream<T>>>, so we narrow that down with the .orElse(Optional.empty)
Note: Code is tested, and appears to work. The unspecified "edge case" of an empty input Stream is treated as an an empty Optional, but can be easily changed.
final Stream<Optional<Integer>> streamOfInts = Stream.of(Optional.of(1), Optional.of(2), Optional.of(3), Optional.of(4), Optional.of(5));
// false - list of Optional.empty(); true -> list of Optional.of(Integer)
final Map<Boolean, List<Optional<Integer>>> collect = streamOfInts.collect(Collectors.partitioningBy(Optional::isPresent));
final Function<List<Optional<Integer>>, Stream<Integer>> mapToStream = List->List.stream().filter(o->o.isPresent()).map(o->o.get());
Optional<Stream<Integer>> result = Optional
.of(Optional.of(collect.get(false)).filter(list->list.size()>0).orElse(collect.get(true)))
.filter(list->list.size()>0)
.filter(list->list.get(0).isPresent())
.map(mapToStream)
.map(Optional::of)
.orElse(Optional.empty());

Categories

Resources