I have two endpoints, one responsible for receive transactions and other responsible for generate stats based on transactions from the last minute only.
To store them, I'm using a ConcurrentNavigableMap:
@Component
@Log
public class DatastoreComponent {
private ConcurrentNavigableMap<Long, List<Transaction>> transactions;
public DatastoreComponent() {
this.transactions = new ConcurrentSkipListMap<>();
}
public synchronized List<Transaction> addTransaction(Transaction t){
log.info("Adding transaction: "+t);
List<Transaction> transactionAtGivenTime = transactions.get(t.getTimestamp());
if(transactionAtGivenTime == null) transactionAtGivenTime = new ArrayList<>();
transactionAtGivenTime.add(t);
return transactions.put(t.getTimestamp(), transactionAtGivenTime);
}
I use the timestamp as key, so that I can get all transactions from last minute just tailing the map, as follow:
public StatisticsFacade aggregate(){
List<Transaction> validTransactions = new ArrayList<>();
dataStore.getTransactions().tailMap(sixtySecondsAgo())
.values()
.parallelStream()
.forEach(list -> validTransactions.addAll(list));
statsAgg.aggreate(validTransactions);
return this;
}
so far, so good (I guess?). well anyway, the process happens in the statsAgg.aggreate() method, and this method should be O(1). My implementation is like that:
public synchronized void aggreate(List<Transaction> validTransactions) {
if(validTransactions == null || validTransactions.isEmpty())
return;
this.avg = validTransactions.parallelStream().mapToDouble(a -> a.getAmount()).average().getAsDouble();
this.sum = validTransactions.parallelStream().mapToDouble(a -> a.getAmount()).sum();
this.max = validTransactions.parallelStream().mapToDouble(a -> a.getAmount()).max().getAsDouble();
this.min = validTransactions.parallelStream().mapToDouble(a -> a.getAmount()).min().getAsDouble();
this.count = new Long(validTransactions.size());
}
I'm not really sure that this is O(1) since I'm running through the list 4 times...I tried extract validTransactions.parallelStream().mapToDouble(a -> a.getAmount()) to a variable and re-use it, but of course, once the stream is processed, it is closed and I can't do anything.
So the question is: is this O(1) and if not, is there a way to run through the stream and too all this calculations at once?
.collect(summarizingDouble(Transaction::getAmount))But how you figure this to have any chance of being O(1) as opposed toO(validTransactions.size()), eludes me.