Java 8 Streams Filter a list based on a condition - java-8

I am trying to extract a filtered list on top of the original list based on some condition. I am using backport version of Java 8 and am not pretty sure how to do this.I get the Set from ccarReport.getCcarReportWorkflowInstances() call. I need to iterate and filter this set based on a condition match( I am comparing the date attribute in each object with the request date being passed. Below is the code
Set<CcarReportWorkflowInstance> ccarReportWorkflowInstanceSet = ccarReport.getCcarReportWorkflowInstances();
List<CcarReportWorkflowInstance> ccarReportWorkflowInstances = StreamSupport.stream(ccarReportWorkflowInstanceSet).filter(ccarReportWorkflowInstance -> DateUtils.isSameDay(cobDate, ccarReportWorkflowInstance.getCobDate()));
The routine which is doing the job
public List<CcarRepWfInstDTO> fetchReportInstances(Long reportId, Date cobDate) {
List<CcarRepWfInstDTO> ccarRepWfInstDTOs = null;
CcarReport ccarReport = validateInstanceSearchParams(reportId, cobDate);
Set<CcarReportWorkflowInstance> ccarReportWorkflowInstanceSet = ccarReport.getCcarReportWorkflowInstances();
List<CcarReportWorkflowInstance> ccarReportWorkflowInstances = StreamSupport.stream(ccarReportWorkflowInstanceSet).filter(ccarReportWorkflowInstance -> DateUtils.isSameDay(cobDate, ccarReportWorkflowInstance.getCobDate()));
ccarRepWfInstDTOs = ccarRepWfInstMapper.ccarRepWfInstsToCcarRepWfInstDTOs(ccarReportWorkflowInstances);
return ccarRepWfInstDTOs;
}
Error I get when I tried to use streams.

Assuming I understood what you are trying to do, you can replace your method body with a single line :
return
validateInstanceSearchParams(reportId, cobDate).getCcarReportWorkflowInstances()
.stream()
.filter(c -> DateUtils.isSameDay(cobDate, c.getCobDate()))
.collect(Collectors.toList());
You can obtain a Stream from the Set by using the stream() method. No need for StreamSupport.stream().
After filtering the Stream, you should collect it into the output List.
I'd use shorter variable and method names. Your code is painful to read.

Related

Replacing Inner for loop with Java Stream

I am learning Java Streams and want to replace the below code with java 8 features.
i was able to use stream.filter() and stream.map features , but i could not replace the below code with java 8 features.
List<Subject> subjects= null;
Set<SubjectData> subjectData= new SubjectData();
for (String name: studentNames)
{
//subjects = student.getSubjects(name);
// consider instead of above line , which returns a collection of <Subject>
for (Subject subject : subjects)
{
subjectData.add(new SubjectData(subject.syllabus(), subject.code()));
}
}
any pointers would be appreciated
I imagine something like this is what you intend:
Set<SubjectData> subjectData = studentNames.stream()
.flatMap(name -> student.getSubjects(name).stream())
.map(subject -> new SubjectData(subject.syllabus(), subject.code()))
.collect(Collectors.toSet());
This streams the student names, maps them to their subjects while concatenating those streams, and then creates SubjectData objects for each. Lastly, those objects are collected into a set.

ArrayIndexOutOfBounds, while using Java 8 streams to iterate a list

I have a List of Objects called md. Each of this objects has an activityName, a startTime and an endTime(for the activity).
I want to iterate over this list and for each activity, get the startTime and endTime.
Map<String,Long> m1 = new HashMap<String,Long>();
m1 = md
.stream()
.map(s->s.activityName)
.collect(HashMap<String,Long>::new,
(map,string)->{
String d1 = md.get(md.indexOf(string)).startTime;
String d2 = md.get(md.indexOf(string)).endTime;
.
.
.
},HashMap<String,Long>::putAll);
It gives me java.lang.ArrayIndexOutOfBoundsException: -1 when I try to get the index of string String d1 = md.get(md.indexOf(string)).startTime;
Is there any other way to simplify the code using Lambda expressions?
What if I have two activities with the same name (Drinking for ex).Will it only return the index of the first Drinking activity it finds?
It seems that you are missing that fact that once you do:
md.stream().map(s -> s.activityName)
your Stream has become Stream<String>; while your md is still List<YourObject>
And in the map operation you are trying to find a String inside md, this obviously does not exist, thus a -1.
So you need a Map<String, Long> that is activitaName -> duration it takes(could be Date/Long)
md.stream()
.collect(Collectors.toMap(s -> s.activityName, x -> {
Date start = // parse s.startTime
Date end = // parse s.endTime
return end.minus(start);
}));
Now the parsing depends on the dates you use.

Java 8 stream compare two objects and run a function on them

I've a a stream which I want to partition into smaller parts based on matching Id and then apply some proccessing logic on each of the part/element.
class BigRequest{
String bId;
List<Parts> parts;
//getters and setter here
}
Class Parts{
String pId;
String partId;
//getters and setter here
}
I want to segregate and create a list of Parts of size 10 when the partId of different parts are same.
How to use the filter or reduce or groupingBy function to compare the two elements and put them to a list?
I've tried filter like below, doesn't take p1 variable:
big.stream().filter( p -> p.getPartId() == p1.getPartId()) //error
Tried groupingBy like this
big.stream().collect(Collectors.groupingBy(Parts::getPartId) //error
I want to iterate over the filtered/reduced list a another and call another function called abc(). How can I do it using Java Streams?
pseudo:
big.getParts().stream.
//dividing logic logic
for(i < parts.size)
abc(p)
Thanks
You might use something like this:
Map<String,List<Parts>> commonId = big.getParts().
stream().
collect(
Collectors.groupingBy(
Parts::getPartId,
Collectors.mapping(
Function.identity(),
Collectors.toList()
)
)
);
and after it, you will just need to iterate over the map and apply your function.
commonId.entrySet().stream().map(entry -> apply(entry))...
Updated
We can omit Collectors.mapping(Function.identity(),Collectors.toList()) part, since it is a default behaviour of groupingBy
Map<String,List<Parts>> commonId = big.getParts().
stream().
collect(
Collectors.groupingBy(
Parts::getPartId
)
);

Java8 stream average of object property in collection

I'm new to Java so if this has already been answered somewhere else then I either don't know enough to search for the correct things or I just couldn't understand the answers.
So the question being:
I have a bunch of objects in a list:
try(Stream<String> logs = Files.lines(Paths.get(args))) {
return logs.map(LogLine::parseLine).collect(Collectors.toList());
}
And this is how the properties are added:
LogLine line = new LogLine();
line.setUri(matcher.group("uri"));
line.setrequestDuration(matcher.group("requestDuration"));
....
How do I sort logs so that I end up with list where objects with same "uri" are displayed only once with average requestDuration.
Example:
object1.uri = 'uri1', object1.requestDuration = 20;
object2.uri = 'uri2', object2.requestDuration = 30;
object3.uri = 'uri1', object3.requestDuration = 50;
Result:
object1.uri = 'uri1', 35;
object2.uri = 'uri2', 30;
Thanks in advance!
Take a look at Collectors.groupingBy and Collectors.averagingDouble. In your case, you could use them as follows:
Map<String, Double> result = logLines.stream()
.collect(Collectors.groupingBy(
LogLine::getUri,
TreeMap::new,
Collectors.averagingDouble(LogLine::getRequestDuration)));
The Collectors.groupingBy method does what you want. It is overloaded, so that you can specify the function that returns the key to group elements by, the factory that creates the returned map (I'm using TreeMap here, because you want the entries ordered by key, in this case the URI), and a downstream collector, which collects the elements that match the key returned by the first parameter.
If you want an Integer instead of a Double value for the averages, consider using Collectors.averagingInt.
This assumes LogLine has getUri() and getRequestDuration() methods.

Linq statement fails with dynamic where clause

I want to retrieve commissions with a certain order number.
This works:
var expression = from commission in db.Auftraege
where commission.Auftragsnummer == orderNbr
select new Commission() { EF_Commission = (commission as Auftrag) };
return expression.ToList();
However, if i transform this to use a dynamic where clause (because i want to apply some more filters), the where-clause does not seem to be applied. Instead, all commissions are returned instead of only those with a specific number:
//base query
var expression = from commission in db.Auftraege select new Commission() { EF_Commission = (commission as Auftrag) };
//now add a where clause if the input parameter was specified
if (orderNbr >= 0)
expression.Where(commission => commission.EF_Commission.Auftragsnummer == orderNbr);
return expression.ToList();
I have looked at a dozen examples but they all seem to do it this way. Does anybody have an idea why the second query ignores the where clause?
You need to assign the interim expression to something (perhaps to itself). expression.Where() does not alter the existing query - it returns a new one.
So:
expression = expression.Where(...);

Resources