I'm implementing a stream in which I use a collection listOfFoo to get ids of all items in that list and use them to get values of Bar instances.
I would like to ensure that this method will throw ResourceNotFoundException in case there is no items on bars list, although in the current state it checks if list bars is null and it is not, since it contains an empty list.
Could you please help me and suggest some solution?
List<Bar> bars = Optional.ofNullable(
listOfFoos.stream()
.map(Foo::getId)
.map(fooId -> service.getBars(fooId))
.filter(Objects::nonNull)
.collect(Collectors.toList()))
.orElseThrow(() -> new ResourceNotFoundException(Bar.class, OBJECT_NULL));
I don't really see the benefit of using Optional, it would be more readable without it :
List<Bar> bars = listOfFoos.stream()
.map(Foo::getId)
.map(service::getBars)
.collect(Collectors.toList());
if (bars.isEmpty()) {
throw new ResourceNotFoundException(Bar.class, OBJECT_NULL);
}
The book Effective Java mentions the following:
Container types, including collections, maps, streams, arrays, and
optionals should not be wrapped in optionals. (P.252)
Just add an Optional.filter for it then. You could do it as :
List<Bar> bars = Optional.ofNullable(
listOfFoos.stream().map(fooId -> service.getBars(fooId))
.filter(Objects::nonNull).collect(Collectors.toList()))
.filter(a -> !a.isEmpty())
.orElseThrow(() -> new ResourceNotFoundException(Bar.class, OBJECT_NULL));
Aside: By the implementation shared in the code, the list returned by the stream could not be null, so Optional.ofNullable could possibly be replaced by Optional.of.
Related
Please can you help me resolve this issue I am having when attempting to stream through an array list and call a setter based on a method which returns a Boolean.
Written as a for loop, it would look like this:-
for (final PersonDto person : personList) {
person.setUserCanEdit(userHasWriteRole(person));
}
private Boolean userHasWriteRole(final PersonDto person) {
return getUserRoles().contains(getReadRole());
}
I have tried a few variations with no success, along the following lines
final List<PersonDto> results = personList.stream().filter(a -> a.setUserCanEdit(this::userHasWriteRole)).collect(Collectors.toList());
... But it complains with
The target type of this expression must be a functional interface
I think I would go for:
personList.stream()
.filter(p -> userHasWriteRole(p))
.forEach(p -> p.setUserCanEdit(true));
I think this keeps the intent clear,
Since you are updating the objects in array list, you can use forEach
personList.forEach(person ->person.setUserCanEdit(userHasWriteRole(person)));
The filter() method is an intermediate operation of the Stream interface that allows us to filter elements of a stream that match a given Predicate. You can't update data in the filter.
Use forEach for this.
personList.stream().forEach(a -> a.setUserCanEdit(userHasWriteRole(a)));
And if you want to get in new arraylist make a copy of list and do this operations on new list
List<PersonDto> copy = new ArrayList<>(personList);
copy.stream().forEach(a -> a.setUserCanEdit(userHasWriteRole(a)));
If you want to have a list with filtered elements and do the setUserCanEdit on every elements in that list; you can do like this:
List<PersonDto> newList = personList.stream()
.filter(p -> userHasWriteRole(p))
.collect(Collectors.toList());
newList.forEach(p -> p.setUserCanEdit(true));
I want to set a List<String> to the field selectedResources.
getProtectionSet() returns a List<ProtectionSet>
ProtectionSet has a field List<UUID> resourceIds and this List<UUID> = List<String> I want to save in selectedResources.
getProtectionSet() is a list but I want to get values from first
element
I don't want to have NPE exception
when any list is empty, it makes no sense to go further.
private Mono<Protection> addProt(Protection protection) {
...
...
MyClass.builder()
.fieldA(...)
.fieldB(...)
.selectedResources( //-->List<String> is expected
protection.getProtectionSet().stream() //List<ProtectionSet>
.filter(Objects::nonNull)
.findFirst()
.map(ProtectionSet::getResourceIds) //List<UUID>
.get()
.map(UUID::toString)
.orElse(null))
.fieldD(...)
How to write my stream to avoid NPE exception?
Though you shouldn't really face a NullPointerException with your current code, there are still possibilities of getting a NoSuchElementException for performing a get on Optional without confirming the presence.
You should use orElse few stages ahead as I understand the problem such that you map the first element found and stream only its element if available :
protection.getProtectionSet().stream() //List<ProtectionSet>
.filter(Objects::nonNull)
.findFirst() // first 'ProtectionSet'
.map(p -> p.getResourceIds()) // Optional<List<UUID>> from that
.orElse(Collections.emptyList()) // here if no such element is found
.stream()
.map(UUID::toString) // map in later stages
.collect(Collectors.toList()) // collect to List<String>
I have this piece of code that filters from a list of objects based on a set of String identifiers passed in and returns a map of string-id and objects. Something similar to follows:
class Foo {
String id;
String getId() {return id};
};
// Get map of id --> Foo objects whose string are in fooStr
Map<String,Foo> filterMethod (Set<String> fooStr) {
List<Foo> fDefs; // list of Foo objects
Map<String,Foo> fObjMap = new HashMap<String, Foo>(); // map of String to Foo objects
for (Foo f : fDefs) {
if (fooStr.contains(f.getId()))
fObjMap.put(f.getId(),f);
}
return (fObjMap);
}
Is there a better Java8 way of doing this using filter or map?
I could not figure it out and tried searching on stackoverflow but could not find any hints, so am posting as a question.
Any help is much appreciated.
~Ash
Just use the filter operator with the same predicate as above and then the toMap collector to build the map. Also notice that your iterative solution precludes any possibility of key conflict, hence, I have omitted that, too.
Map<String, Foo> idToFooMap = fDefs.stream()
.filter(f -> fooStr.contains(f.getId()))
.collect(Collectors.toMap(Foo::getId, f -> f));
When including items conditionally in the final output use filter and when going from stream to a map use Collectors.toMap. Here's what you end up with:
Map<String,Foo> filterMethod (final Set<String> fooStr) {
List<Foo> fDefs; // list of Foo objects
return fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.collect(Collectors.toMap(Foo::getId, Function.identity()));
}
Though ggreiner has already provided a working solution, when there are duplicates you'd better handle it including a mergeFunction.
Directly using Collectors.toMap(keyMapper, valueMapper), one or another day you will encounter this following issue.
If the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function, Function, BinaryOperator) instead.
Based on the OP's solution, I think it would be better using
import static java.util.stream.Collectors.*; // save some typing and make it cleaner;
fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.collect(toMap(Foo::getId, foo -> foo, (oldFoo, newFoo) -> newFoo));
Maybe something like this?
Map<String,Foo> filterMethod (Set<String> fooStr) {
List<Foo> fDefs; // get this list from somewhere
Map<String, Foo> fObjMap = new HashMap<> ();
fDefs.stream()
.filter(foo -> fooStr.contains(foo.getId()))
.forEach(foo -> fObjMap.put(foo.getId(), foo))
return fObjMap;
}
I have a method which returns a Flowable<RealmResults<MyClass>>. For those not familiar with Realm, RealmResults is just a simple List of items.
Given a Flowable<RealmResults<MyClass>>, I'd like to emit each MyClass item so that I can perform a map() operation on each item.
I am looking for something like the following:
getItems() // returns a Flowable<RealmResults<MyClass>>
.emitOneAtATime() // Example operator
.map(obj -> obj + "")
// etc
What operator will emit each List item sequentially?
You would flatMap(aList -> Flowable.fromIterable(aList)). Then you can map() on each individual item. There is toList() if you want to recollect the items (note: this would be a new List instance). Here's an example illustrating how you can use these methods to get the different types using List<Integer>.
List<Integer> integerList = new ArrayList<>();
Flowable<Integer> intergerListFlowable =
Flowable
.just(integerList)//emits the list
.flatMap(list -> Flowable.fromIterable(list))//emits one by one
.map(integer -> integer + 1);
The question is, do you want to keep the results as a Flowable<List<MyClass>> or as a Flowable<MyClass> with retained order?
If the first,
getItems()
.concatMap(results -> Flowable
.fromIterable(results)
.map(/* do your mapping */)
.toList()
)
If the second, this should suffice:
getItems()
.concatMap(Flowable::fromIterable)
.map(/* do your mapping */)
Is there a way to parallelize this piece of code:
HashMap<String, Car> cars;
List<Car> snapshotCars = new ArrayList<>();
...
for (final Car car : cars.values()) {
if (car.isTimeInTimeline(curTime)) {
car.updateCalculatedPosition(curTime);
snapshotCars.add(car);
}
}
Update: This is what I tried before asking for assistance:
snapshotCars.addAll(cars.values().parallelStream()
.filter(c -> c.isTimeInTimeline(curTime))
.collect(Collectors.toList()));
How could I integrate this line? ->
car.updateCalculatedPosition(curTime);
Well, assuming that updateCalculatedPosition does not affect state outside of the Car object on which it runs, it may be safe enough to use peek for this:
List<Car> snapshotCars = cars.values()
.parallelStream()
.filter(c -> c.isTimeInTimeline(curTime))
.peek(c -> c.updateCalculatedPosition(curTime))
.collect(Collectors.toCollection(ArrayList::new));
I say this is "safe enough" because the collect dictates which elements will be peeked by peek, and these will necessarily be all the items that passed the filter. However, read this answer for the reason why peek should generally be avoided for "significant" operations.
Your peek-free alternative is to first, filter and collect, and then update using the finished collection:
List<Car> snapshotCars = cars.values()
.parallelStream()
.filter(c -> c.isTimeInTimeline(curTime))
.collect(Collectors.toCollection(ArrayList::new));
snapShotCars.parallelStream()
.forEach(c -> c.updateCalculatedPosition(curTime));
This is safer from an API point of view, but less parallel - you only start updating the positions after you have finished filtering and collecting.
If you want parallelized access to a List you might want to use Collections.synchonizedList to get a thread-safe list:
List<Car> snapshotCars = Collections.synchronizedList(new ArrayList<>());
Then you can use the stream API like so:
cars.values()
.parallelStream()
.filter(car -> car.isTimeInTimeline(curTime))
.forEach(car -> {
car.updateCalculatedPosition(curTime);
snapshotCars.add(car);
});
In addition to RealSkeptic’s answer, you can alternatively use your own collector:
List<Car> snapshotCars = cars.values().parallelStream()
.filter(c -> c.isTimeInTimeline(curTime))
.collect(ArrayList::new,
(l,c) -> { c.updateCalculatedPosition(curTime); l.add(c); },
List::addAll);
Note that .collect(Collectors.toList()) is equivalent (though not necessarily identical) to .collect(Collectors.toCollection(ArrayList::new)) which is equivalent to .collect(ArrayList::new, List::add, List::addAll).
So our custom collector does a similar operation, but replaces the accumulator with a function, which also performs the desired additional operation.