Replacing for-each loop with stream API call in Java - java

Having this code:
public Map<Job, Collection<JobTransform>> getPartitioning() {
Map<Job, Collection<JobTransform>> partitioning = new IdentityHashMap<>();
for (JobTransform jobTransform : content) {
Job job = jobTransform.getJob();
Collection<JobTransform> collection = partitioning.get(job);
if (collection == null) {
collection = new LinkedList<>();
partitioning.put(job, collection);
}
collection.add(jobTransform);
}
return partitioning;
}
and 'content' being a constructor parameter for the class this method is implemented in, how can I convert the for-each loop into code using Stream API in Java? For now I have only
content.stream().map(JobTransform::getJob)
and I don't know how can I use each job further. Do I use the API wrong? Please help me to improve my code!

content.stream().collect(Collectors.groupingBy(JobTransform::getJob, IdentityHashMap::new, Collectors.toCollection(LinkedList::new)));
This will do exactly the same thing as your non-stream code.

Related

How to apply Java Stream for existing forEach loop with if condition

I am new to Java stream and can use java stream on ArrayList. This time I don't have any clue and been trying since 2 hours. I am not getting any idea. I am not sure even if it is possible to use Java stream here. Can someone please guide me? I don't even know where to start. How shall I check for below condition transactions.getAvatarInfo() != null?
This for loop works as expected. and I need to use Java Streams here instead of for loop. I was able to use Java Streams at other for loops , it was straight forward. Here I don't even know where to start.
for (int i = 0; i < accountInfo.get().getTransactions().size(); i++) {
Transactions transactions = accountInfo.get().getTransactions().get(i);
AvatarInfo avatarInfo = new AvatarInfo ();
if (transactions.getAvatarInfo() != null) {
transations.setAvataruri(TransactionsConstant.PREFIX +
transactions.getAvatarInfo().getUserName().toLowerCase());
transactions.getAvatarInfo().setUserName(transactions.getAvatarInfo ().getUsername());
}
}
So far I have tried below but it gives error saying ; is expeccted after null. And if I add that there would be another error.
accountInfo.get().getTransactions().stream().filter(a -> {
AvatarInfo avatarInfo = new AvatarInfo ();
a.getAvatarInfo() != null
})
If you have only a single expression, you can write a lambda using just that expression, like this:
a -> (a.getAvatarInfo() != null) // returns a boolean for filter
However, when you introduce {}, you have a full embedded method that has to follow all the normal syntax for a method. In this case, since your lambda should return a boolean, you need
return a.getAvatarInfo() != null;
However, the new AvatarInfo() business appears to be completely unnecessary and can be removed, allowing you to use the simpler form.
ArrayList is a Collection. Since Java 8 Collection defines a stream() method which will return a Stream of the elements of your ArrayList.
See https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream--
To get the list we need a collector, so I think it should be like this:
transactions.stream()
.filter(account -> account.getAvatarInfo() != null)
.collect(Collectors.toList());
Otherwise it will only return a Stream instead of a List.

How to improve performance in recursive method with Loop in Java

I'm trying to use memoization pattern in my recursive operation, but something is going wrong.
Below is my method.
private Map<String, MyDTO> map = new ConcurrentHashMap<>();
private void searchRecursive(String uuid) {
if (!map.containsKey(uuid)) {
MyDTO obj = myClient.getMyObject(uuid);
if("one".equals(obj.getType()) || "two".equals(obj.getType())){
if(Objects.nonNull(obj.getChildren())){
obj.getChildren().forEach(child -> searchRecursive(child.getId()));
}
} else if("three".equals(obj.getType())) {
map.put(uuid, obj);
}
}
}
I would like to improve the performance of this operation!
Thank you very much for the help!
I think as #John3136 said, getType(), getChildren() called more than one time, better to create a reference and reduce call time for those methods.
I'm guessing the obj you are trying to search is like a graph or tree, so I think you can try to convert to iterate the child use the BFS method (Queue like data structure), that would be better.

Java: Return in a for loop

Is there a way to return some value from within a for loop without jumping out of the loop?
I am implementing a static analysis tool where I have to analyze a list of methods (CFGs) in a for loop. The size of CFG list is not known in advance. Each method in the for loop has to return some value. As asked above, is there a way to do it in a loop without breaking the loop? One possible alternative comes in mind is that I can unroll the loop, assuming the maximum list size could be some fixed value. But this does not solve the problem completely. Any help would be appreciated.
code looks like below.
for(CFG cfg: cfgList)
{
val = analyze(cfg);
return val; //I want for loop not to stop here.
}
P.S. I cannot store the values in a list to return values later.
Edit1:
For example, consider following statements.
call method1();
st2;
st3;
...
This method1() can be any of five different methods. For all five possible options, I want to analyze each of them, return their values and analyze rest of the statements accordingly. So, I would analyze these 5 methods as below.
call method1-option1();
st2;
st3;
...
call method1-option2();
st2;
st3;
...
call method1-option3();
st2;
st3;
...
Hope, it helps in understanding the question.
No you can not return value from loop without jumping out of it. According to your need you have to save value in other list and you can return that list after finishing the loop.
In Java 8, you can do:
Iterator<AnalysisResult> lazyAnalysisResults = cfgList.stream()
.map(cfg -> analyze(cfg))
.iterator();
And then the Iterator will supply new analyzed results one at a time, without you needing to collect them all into a list first.
Prior to Java 8, if you want your transformation to be lazy, the best you can do is to implement an Iterator yourself:
public final class AnalyzingIterator extends Iterator<AnalysisResult> {
private final Iterator<CFG> iter;
public AnalyzingIterator(Iterator<CFG> iter) {
this.iter = iter;
}
#Override public boolean hasNext() {
return iter.hasNext();
}
#Override public AnalysisResult next() {
return analyze(iter.next());
}
#Override public boolean remove() {
throw new UnsupportedOperationException();
}
}
If you don't want to store results in a List and return it all together you can use callback mechanism.
Use analyze() to start a new thread passing cfg as well as reference to this. When processing is over make that processing thread call a callback method on your current instance / thread passing the analyzed value. Continue to do whatever you intend to do with this returned value in the callback method. And you don't have to alter your for loop.

Java 8 - Streams Nested ForEach with different Collection

I try to understand the new Java 8 Streams and I tried for days to transfer nested foreach loops over collection in Java 8 Streams.
Is it possible to refactor the following nested foreach loops including the if-conditions in Java-8-Streams?
If yes what would it look like.
ArrayList<ClassInq> Inq = new ArrayList<>();
TreeMap<String, SalesQuot> Quotations = new TreeMap<>();
ArrayList<ClassInq> tempInqAndQuot = new ArrayList<>();
ArrayList<SalesQuot> tempQuotPos = new ArrayList<>();
for(ClassInq simInq : this.Inq) {
if(!simInq.isClosed() && !simInq.isDenied()) {
for(Map.Entry<String, SalesQuot> Quot: Quotations.entrySet()) {
SalesQuot sapQuot = Quot.getValue();
if(sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber()) == 0) {
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
for(Map.Entry<String, SalesQuotPosition> quotp : sapQuot.getPosition().entrySet()) {
tempQuotPos.add(quotp.getValue());
}
}
}
}
}
Thanks a lot for your help.
BR
First, try to adhere to the Java naming conventions, as your upper case variable names make it really hard to read your code. Second, it’s a good thing that you want to learn about Stream API but you should not ignore the basics of the pre-Java 8 Collection APIs.
It’s not useful to iterate over an entrySet() when you are only interested in either, keys or values. You do it two times within a small piece of code.
At the first appearance you can replace
for (Map.Entry<String, SalesQuot> Quot: Quotations.entrySet()){
SalesQuot sapQuot = Quot.getValue();
with the simpler
for (SalesQuot sapQuot: Quotations.values()){
At the second, the entire
for(Map.Entry<String,SalesQuotPosition> quotp: sapQuot.getPosition().entrySet()){
tempQuotPos.add(quotp.getValue());
}
can be replaced by
tempQuotPos.addAll(sapQuot.getPosition().values());
Thus even without streams, your code can be simplified to
for (ClassInq simInq : this.Inq){
if (!simInq.isClosed() && !simInq.isDenied()){
for (SalesQuot sapQuot: Quotations.values()){
if (sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber()) == 0){
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
tempQuotPos.addAll(sapQuot.getPosition().values());
}
}
}
}
though it’s still not clear what it is supposed to do and whether it’s correct. Besides the errors and suspicions named in the comments to your question, modifying the incoming values (esp. from the outer loop) does not look right.
It’s also not clear why you are using ….compareTo(…)==0 rather than equals.
However, it can be straight-forwardly rewritten to use streams without changing any of the code’s logic:
this.Inq.stream().filter(simInq -> !simInq.isClosed() && !simInq.isDenied())
.forEach(simInq -> Quotations.values().stream().filter(sapQuot ->
sapQuot.getInquiryDocumentNumber().compareTo(simInq.getSapInquiryNumber())==0)
.forEach(sapQuot -> {
simInq.setSAPQuotationNumber(sapQuot.getQuotationDocumentNumber());
tempInqAndQuot.add(simInq);
tempQuotPos.addAll(sapQuot.getPosition().values());
})
);
Still, I recommend cleaning up the original logic first before rewriting it for using other APIs. The stream form would greatly benefit from a more precise definition of what to achieve.

Language Tricks to Shorten My Java Code? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
I am currently rediscovering Java (working with Ruby a lot recently), and I love the compilation-time checking of everything. It makes refactoring so easy. However, I miss playing fast-and-loose with types to do an each loop. This is my worst code.
Is this as short as it can be? I have a collection called looperTracks, which has instances that implement Looper. I don't want to modify that collection, but I want to iterate through its members PLUS the this (which also implements Looper).
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1);
for (LooperTrack track : looperTracks) {
allLoopers.add(track);
}
allLoopers.add(this);
for (Looper looper : allLoopers) {
// Finally! I have a looper
I'm particularly concerned about any features that are new to Java from 1.5 on that I may have missed. For this question I am not asking about JRuby nor Groovy, though I know that they would work for this.
Edit: Sorry (too much Ruby!)... looperTracks is of type LooperTrack[] and LooperTrack implements Looper.
You could at least use the fact that you can construct one collection using another as the base values. According to the docs:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator. The ArrayList instance has an initial capacity of 110% the size of the specified collection.
Which means that there is probably going to be room forthis without having to do any resizing.
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
allLoopers.add(this);
for (Looper looper : allLoopers) {
// Finally! I have a looper
There are at least two possible built-in ways to shorten your code:
You could use Collection.addAll(Collection) that appends each element in the collection passed as parameter to the end of the collection.:
List<Looper> allLoopers = new ArrayList<Looper>();
...
allLoopers.addAll(looperTracks);
allLoopers.add(this);
for(Looper looper : allLoopers) {
...
}
or you can use a constructor that takes a collection as a parameter:
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
Due to the change of question: All arrays can easily be converted to collections using java.util.Arrays e.g.
List<Looper> someLooperTracks = Arrays.asList(looperTracks).
This will wrap the array in a fixed-size list.
I don't think you can make it shorter than this...
for (Looper looper : new ArrayList<Looper>(looperTracks){{ add(EnclosingClass.this); }}) {
// Finally! I have all loopers
}
Guava makes this pretty easy:
for (Looper looper : ObjectArrays.concat(looperTracks, this)) {}
Here is the documentation for the method ObjectArrays#concat.
I've just implemented an Iterator of Iterables (it is implemented in a more robust/tested/reviewed way by Guava Iterables.concat(Iterable...)):
// make a concatenation of iterables
public static <T> Iterable<T> $(final Iterable<T> first, final Iterable<T>... iterables) {
List<Iterator<T>> allIterables = new LinkedList<Iterator<T>>();
allIterables.add(first.iterator());
for (Iterable<T> iterable : iterables) {
allIterables.add(iterable.iterator());
}
final Iterator<Iterator<T>> iterators = allIterables.iterator();
return new Iterable<T>() {
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private Iterator<T> current = iterators.next();
#Override
public boolean hasNext() {
if (current.hasNext()) {
return true;
} else {
if (iterators.hasNext()) {
current = iterators.next();
return current.hasNext();
} else {
return false;
}
}
}
#Override
public T next() {
return current.next();
}
#Override
public void remove() {
}
};
}
};
}
using it your code becomes:
for (Looper looper : $($(looperTracks), this)) {
}
in the case you care the implementation is being part of my Dollar library (relesead as LGPL3).
Why can't you just add them all as part of the constructor call?
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
allLoopers.add(this);
for(Looper looper : allLoopers) {
...
}
Depending on typing, you could use:
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
allLoopers.add(this);
or:
List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1);
allLoopers.addAll(looperTracks);
allLoopers.add(this);
In case you don't want to use Groovy or JRuby because of their dynamic nature, you should consider using Scala. Scala is statically typed but more concise than Java.
Is it a requirement that you assemble everything into one list? If not, what's wrong with this?
for (Looper looper : looperTracks) {
doSomething(looper);
}
doSomething(this);
Try
Looper[] loop = new Looper[looperTracks.length + 1];
System.arraycopy(looperTracks, 0, loop, 0, looperTracks.length);
loop[looperTracks.length] = this;
for (Looper l : loop) { ... }
but honestly, why not just loop through the existing array, and then do whatever you want to do with the loop to this afterwards?
The List-version of the above looks like:
List<Looper> loop = new ArrayList<Looper>(Arrays.asList(looperTracks));
loop.add(this);
for (Looper l : loop) { ... }
You can try using an immutable list by using the nCopies() method. Quoting from the API reference,
public static <T> List<T> nCopies(int n, T o)
Returns an immutable list consisting
of n copies of the specified object.
The newly allocated data object is
tiny (it contains a single reference
to the data object). This method is
useful in combination with the
List.addAll method to grow lists. The
returned list is serializable.
this will avoid the first foreach iteration.
I'm just going to throw this out there but don't try and make your code shorter at the expense of making it readable.
Readable code is always my aim when I start writing code, simply because I know that at some point in the future either myself or someone else is going to look at it and have to understand it.

Categories