Java-8 – sum and max values in a single iteration
I have a list of custom callrecord objects
public class CallRecord { private String callId; private String aNum; private String bNum; private int seqNum; private byte causeForOutput; private int duration; private RecordType recordType; . . . }
There are two logical conditions, and the output of each is:
>Maximum seqnum, sum (duration) > maximum seqnum, sum (duration), maximum causeoutput
According to my understanding, stream max(),Collectors. Summarizingint () and others will require multiple iterations of the above results I also met thread suggested custom collectors, but I'm not sure
Here is the simple pre Java 8 code provided for this purpose:
if (...) { for (CallRecord currentRecord : completeCallRecords) { highestSeqNum = currentRecord.getSeqNum() > highestSeqNum ? currentRecord.getSeqNum() : highestSeqNum; sumOfDuration += currentRecord.getDuration(); } } else { byte highestCauseForOutput = 0; for (CallRecord currentRecord : completeCallRecords) { highestSeqNum = currentRecord.getSeqNum() > highestSeqNum ? currentRecord.getSeqNum() : highestSeqNum; sumOfDuration += currentRecord.getDuration(); highestCauseForOutput = currentRecord.getCauseForOutput() > highestCauseForOutput ? currentRecord.getCauseForOutput() : highestCauseForOutput; } }
Solution
It's unreasonable for you to expect everything to be done in one iteration You should first consider simplicity and improve performance if necessary, but sticking to a single iteration is neither
Performance depends on too many factors to predict in advance The process of iteration (through ordinary sets) itself is not necessarily an expensive operation, and may even benefit from a simpler loop body, so that multiple iterations have direct operations, which is more effective than a single traversal attempt to perform all operations The only way to find out is to use actual operation for measurement
Converting an operation to a stream operation simplifies the code if you use it directly, that is
int highestSeqNum= completeCallRecords.stream().mapToInt(CallRecord::getSeqNum).max().orElse(-1); int sumOfDuration= completeCallRecords.stream().mapToInt(CallRecord::getDuration).sum(); if(!condition) { byte highestCauseForOutput = (byte) completeCallRecords.stream().mapToInt(CallRecord::getCauseForOutput).max().orElse(0); }
If you are still uncomfortable with the fact of multiple iterations, you can try to write a custom collector and perform all operations at the same time, but the result will not be better than your loop, both in readability and efficiency
However, I'd rather avoid code duplication than try to do everything in a loop, that is
for(CallRecord currentRecord : completeCallRecords) { int nextSeqNum = currentRecord.getSeqNum(); highestSeqNum = nextSeqNum > highestSeqNum ? nextSeqNum : highestSeqNum; sumOfDuration += currentRecord.getDuration(); } if(!condition) { byte highestCauseForOutput = 0; for(CallRecord currentRecord : completeCallRecords) { byte next = currentRecord.getCauseForOutput(); highestCauseForOutput = next > highestCauseForOutput? next: highestCauseForOutput; } }