How to use Streams instead of do while loop? - java

How to avoid imperative loops and use the Java's Streaming API for the below mentioned implementation for the google directory API?
List<GroupMember> groupMemberList = new ArrayList<>();
Directory.Members.List listRequest = getDirectoryApi().members().list(groupEmailAddress);
Members members;
do {
members = listRequest.execute();
members.getMembers().forEach(member -> groupMemberList.add(new
GroupMember(member.getId(), member.getEmail())));
} while (null != members.getNextPageToken());
return groupMemberList;

Related

How to modify an Array on Java using without use a nested for loop?

I'm using Java 8 and Groovy, unfortunately I can't use lambdas and I have two different lists of objects with one attribute in common, on the first List I get the most of data I need and on the second list I get the data in common, I wrote a for nested loop in order to update the first list with the attribute in common from the second list, I just want to know if there is a better way to improve this code:
List<Object1> firstList = dao.something();
List<Object2> secondList = dao.something2();
List<Object1> thirdList = new ArrayList<Object1>();
for (Object1 obj1 : firstList){
for(Object2 obj2 : secondList){
if(obj1.getSomething().equals(obj2.getSomething())){
obj1.setAttribute(ojb2.getAttribute);
thirdList.add(obj1);
}
}
}
Any help will be useful, thank you.
You can use Iterable's forEach method to go through every element and search it in secondList and modify the content of the object
firstList.forEach(elem -> {
V2 found = secondList.stream().filter(v1 -> v1.getId() == elem.getId()).findAny().orElse(null);
if(found != null) {
elem.setAttribute(found);
}
});
Or you could use streams and map it into another list
List<V1> thirdList = firstList.stream().map(elem -> {
V2 found = secondList.stream().filter(v1 -> v1.getId() == elem.getId()).findAny().orElse(null);
if(found != null) {
elem.setAttribute(found);
}
return elem;
}).collect(Collectors.toList());
If you want to compare two lists you'll always need to iterate twice.
I hope this is helpful for you.
You can use Groovy's default collection methods:
List thirdList = firstList.findResults{ obj1 ->
def obj2attr = secondList.find{ obj1.something == it.something }?.attribute
if( obj2attr ){
obj1.attribute = obj2attr
obj1
}else
null
}
findResults() is a handy mix of filter, map and collect

Is it possible to replace nested loops on different collections with Stream API

I was wondering if it's possible to rewrite nested for loops using java.utils.stream in Java 8?
Here is a sample data type I'm working with:
class Folder {
private final String name;
private final Integer itemCound;
Folder(String name, Integer itemCount) {
this.name = name;
this.itemCount = itemCount;
}
public String getName() { return this.name; }
public Integer getItemCount() { return this.itemCount; }
}
Here's code in action:
List<Folder> oldFolders = new ArrayList<>();
List<Folder> newFolders = new ArrayList<>();
// Fill folder collections with sample data...
oldFolders.add(new Folder("folder1", 2));
oldFolders.add(new Folder("folder2", 4));
newFolders.add(new Folder("folder1", 0));
newFolders.add(new Folder("folder2", 100));
// This part should be rewrited using streams
for (Folder newFolder : newFolders) {
for (Folder oldFolder : oldFolders) {
if (newFolder.getName().equals(oldFolder.getName())
&& !newFolder.getItemCount().equals(oldFolder.getItemCount())) {
// do stuff...
}
}
}
P.S: I've seen other questions on SO, but all of them had 1 collection or a collection with it's own nested collection instead of two different collections like in my example.
Thanks in advance!
That not much of an improvement to be fair unless if you can parallelize the first iteration (commented in this example)
List<String> oldList = new ArrayList<>();
List<String> newList = new ArrayList<>();
oldList
//.stream()
//.parallel()
.forEach(s1 ->
newList
.stream()
.filter(s2 -> s1.equals(s2)) //could become a parameter Predicate
.forEach(System.out::println) //could become a parameter Consumer
);
Replacing the if with a filter and his Predicate then executing a method on it.
This would give a solution that can be dynamic providing different Predicate and Consumer to the filter and forEach method. That would be the only reason to work on this conversion.
Yeah you can:
newFolders.forEach((newFolder) -> {
oldFolders.forEach((oldFolder) -> {
if (newFolder.getName().equals(oldFolder.getName())
&& !newFolder.getItemCount().equals(oldFolder.getItemCount())) {
// do stuff...
}
})
})
EDIT: But as #Kayaman mentions in the comments below this is not necessarily better than just using nested for loops.
This is a good read for when you should and shouldn't consider using streams:
In Java, what are the advantages of streams over loops?
Try with this:
newFolders.stream().filter(newFolder ->
oldFolders
.stream()
.anyMatch(oldFolder->
newFolder.getName().equals(oldFolder.getName()) &&
!newFolder.getItemCount().equals(oldFolder.getItemCount())
)).forEach(folder -> {
//dostuff
});

Passing objects through streams and flatmaps

I'm dealing with Java 8 streams and I wondering if I could resolve this problem in a fancy way.
That's my scenario:
Suppose I have a list of parties and inside each element I have the names of the members. I want to iterate over the list and make a new one with the names and which party they belong to.
My first approach was:
#Test
public void test(){
Party firstParties = new Party("firstParty",Lists.newArrayList("Member 1","Member 2","Member 3"));
Party secondParty = new Party("secondParty",Lists.newArrayList("Member 4","Member 5","Member 6"));
List<Party> listOfParties = Lists.newArrayList();
listOfParties.add(firstParty);
listOfParties.add(secondParty);
List<Elector> electors = new ArrayList<>();
listOfParties.stream().forEach(party ->
party.getMembers().forEach(memberName ->
electors.add(new Elector(memberName,party.name))
)
);
}
class Party {
List<String> members = Lists.newArrayList();
String name = "";
public Party(String name, List<String> members) {
this.members = members;
this.name = name;
}
public List<String> getMembers() {
return members;
}
}
class Elector{
public Elector(String electorName,String partyName) {
}
}
In my second approach I tried to use maps an flatmap's operations:
#Test
public void test(){
Party firstParty = new Party("firstParty",Lists.newArrayList("Member 1","Member 2","Member 3"));
Party secondParty = new Party("secondParty",Lists.newArrayList("Member 4","Member 5","Member 6"));
List<Party> listOfParties = Lists.newArrayList();
listOfParties.add(firstParty);
listOfParties.add(secondParty);
List<Elector> people = listOfParties.stream().map(party -> party.getMembers())
.flatMap(members -> members.stream())
.map(membersName -> new Elector(membersName, party.name)) #Here is my problem variable map doesn't exist
.collect(Collectors.toList());
}
The problem is I can't access to the party object inside the map operation.
So the question again is Can I do in a more functional way? (like the second approach)
Thanks!
You decomposed too much into individual operations:
List<Elector> people = listOfParties.stream()
.flatMap(party -> party.getMembers().stream()
.map(membersName -> new Elector(membersName, party.name)))
.collect(Collectors.toList());
This works by moving both map steps into the flatMap step, where only the second one survives, now being applied to the returned “substream”. As pointed out in the comments of your question, you need some kind of Pair type to map the “substream” elements to, but your Elector type fulfills exactly that, as it is constructed using the two values you are interested in. So there is no need to map to a generic Pair(member,party) just to map to Elector afterwards.
To keep everything readable I would add a helper method in the Party class (or a static method somewhere else) to get a Stream<Elector>:
public Stream<Elector> electors() {
return getMembers().stream().map(member -> new Elector(member, name));
}
// Alternatively
public static Stream<Elector> electors(final Party p) {
return p.getMembers().stream().map(member -> new Elector(member, p.name));
}
And then just use that in your flatmap
final List<Elector> people = listOfParties.stream()
.flatMap(Party::electors)
.collect(Collectors.toList());

Limit a stream and find out if there are pending elements

I have the following code that I want to translate to Java 8 streams:
public ReleaseResult releaseReources() {
List<String> releasedNames = new ArrayList<>();
Stream<SomeResource> stream = this.someResources();
Iterator<SomeResource> it = stream.iterator();
while (it.hasNext() && releasedNames.size() < MAX_TO_RELEASE) {
SomeResource resource = it.next();
if (!resource.isTaken()) {
resource.release();
releasedNames.add(resource.getName());
}
}
return new ReleaseResult(releasedNames, it.hasNext(), MAX_TO_RELEASE);
}
Method someResources() returns a Stream<SomeResource> and ReleaseResult class is as follows:
public class ReleaseResult {
private int releasedCount;
private List<String> releasedNames;
private boolean hasMoreItems;
private int releaseLimit;
public ReleaseResult(List<String> releasedNames,
boolean hasMoreItems, int releaseLimit) {
this.releasedNames = releasedNames;
this.releasedCount = releasedNames.size();
this.hasMoreItems = hasMoreItems;
this.releaseLimit = releaseLimit;
}
// getters & setters
}
My attempt so far:
public ReleaseResult releaseReources() {
List<String> releasedNames = this.someResources()
.filter(resource -> !resource.isTaken())
.limit(MAX_TO_RELEASE)
.peek(SomeResource::release)
.map(SomeResource::getName)
.collect(Collectors.toList());
return new ReleasedResult(releasedNames, ???, MAX_TO_RELEASE);
}
The problem is that I can't find a way to know if there are pending resources to process. I've thought of using releasedNames.size() == MAX_TO_RELEASE, but this doesn't take into account the case where the stream of resources has exactly MAX_TO_RELEASE elements.
Is there a way to do the same with Java 8 streams?
Note: I'm not looking for answers like "you don't have to do everything with streams" or "using loops and iterators is fine". I'm OK if using an iterator and a loop is the only way or just the best way. It's just that I'd like to know if there's a non-murky way to do the same.
Since you don’t wanna hear that you don’t need streams for everything and loops and iterators are fine, let’s demonstrate it by showing a clean solution, not relying on peek:
public ReleaseResult releaseReources() {
return this.someResources()
.filter(resource -> !resource.isTaken())
.limit(MAX_TO_RELEASE+1)
.collect(
() -> new ReleaseResult(new ArrayList<>(), false, MAX_TO_RELEASE),
(result, resource) -> {
List<String> names = result.getReleasedNames();
if(names.size() == MAX_TO_RELEASE) result.setHasMoreItems(true);
else {
resource.release();
names.add(resource.getName());
}
},
(r1, r2) -> {
List<String> names = r1.getReleasedNames();
names.addAll(r2.getReleasedNames());
if(names.size() > MAX_TO_RELEASE) {
r1.setHasMoreItems(true);
names.remove(MAX_TO_RELEASE);
}
}
);
}
This assumes that // getters & setters includes getters and setters for all non-final fields of your ReleaseResult. And that getReleasedNames() returns the list by reference. Otherwise you would have to rewrite it to provide a specialized Collector having special non-public access to ReleaseResult (implementing another builder type or temporary storage would be an unnecessary complication, it looks like ReleaseResult is already designed exactly for that use case).
We could conclude that for any nontrivial loop code that doesn’t fit into the stream’s intrinsic operations, you can find a collector solution that basically does the same as the loop in its accumulator function, but suffers from the requirement of always having to provide a combiner function. Ok, in this case we can prepend a filter(…).limit(…) so it’s not that bad…
I just noticed, if you ever dare to use that with a parallel stream, you need a way to reverse the effect of releasing the last element in the combiner in case the combined size exceeds MAX_TO_RELEASE. Generally, limits and parallel processing never play well.
I don't think there's a nice way to do this. I've found a hack that does it lazily. What you can do is convert the Stream to an Iterator, convert the Iterator back to another Stream, do the Stream operations, then finally test the Iterator for a next element!
Iterator<SomeResource> it = this.someResource().iterator();
List<String> list = StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false)
.filter(resource -> !resource.isTaken())
.limit(MAX_TO_RELEASE)
.peek(SomeResource::release)
.map(SomeResource::getName)
.collect(Collectors.toList());
return new ReleaseResult(list, it.hasNext(), MAX_TO_RELEASE);
The only thing I can think of is
List<SomeResource> list = someResources(); // A List, rather than a Stream, is required
List<Integer> indices = IntStream.range(0, list.size())
.filter(i -> !list.get(i).isTaken())
.limit(MAX_TO_RELEASE)
.collect(Collectors.toList());
List<String> names = indices.stream()
.map(list::get)
.peek(SomeResource::release)
.map(SomeResource::getName)
.collect(Collectors.toList());
Then (I think) there are unprocessed elements if
names.size() == MAX_TO_RELEASE
&& (indices.isEmpty() || indices.get(indices.size() - 1) < list.size() - 1)

Java concurrency support using java.util.concurrent semantics

I'm trying to support modification (deactivate() function call) of the following data structure in a thread safe manner -
private static Map<String, Set<Integer>> dbPartitionStatus = new HashMap<String, Set<DBPartitionId>>();
public void deactivate(DBPartitionId partition) throws Exception {
synchronized (dbPartitionStatus) {
Set<DBPartitionId> partitions = dbPartitionStatus.get(serviceName);
if (partitions == null) {
partitions = new HashSet<DBPartitionId>();
}
partitions.add(partition);
dbPartitionStatus.put(serviceName, partitions);
}
}
If I were to replace the synchronization with ConcurrentHashMap & ConcurrentSkipListSet duo, there would be some race condition.
I was wondering if there was a cleaner way of achieving synchronization here (using java.util.concurrent)
Should be no race conditions with the following implementation:
private final static ConcurrentMap <String, Set <DBPartitionId>> dbPartitionStatus =
new ConcurrentHashMap <String, Set <DBPartitionId>> ();
public void deactivate (DBPartitionId partition) {
Set <DBPartitionId> partitions = dbPartitionStatus.get (serviceName);
if (partitions == null)
{
partitions = new ConcurrentSkipListSet <DBPartitionId> ();
Set <DBPartitionId> p =
dbPartitionStatus.putIfAbsent (serviceName, partitions);
if (p != null) partitions = p;
}
partitions.add (partition);
}
I personally cannot see a issues with this sort of approach:
private static ConcurrentHashMap<String, ConcurrentSkipListSet<DBPartitionId>> dbPartitionStatus = new ConcurrentHashMap<>();
public bool deactivate(DBPartitionId partition) throws Exception {
ConcurrentSkipListSet<DBPartitionId> partitions = dbPartitionStatus.get(serviceName);
if (partitions == null) {
// Create a new set
partitions = new ConcurrentSkipListSet<DBPartitionId>();
// Attempt to add, if we add, ev will be null.
ConcurrentSkipListSet<DBPartitionId> ev = dbPartitionStatus.put(serviceName, partitions);
// If non-null, someone else has added it, so now use it.
if (ev != null)
partitions = ev;
}
// will return true if added succesfully...
return partitions.add(partition);
}
There is also the putIfAbsent() method in map which can do the get/put onthe map in an "atomic" operation, however it has the additional overhead in this case that you have to construct an empty set to pass in each time.

Categories