Upload
peter-lawrey
View
576
Download
2
Embed Size (px)
DESCRIPTION
Based on a six month migration of C# code to Java 8, what is legacy lambda code likely to look like and what mistakes can be made. Good use cases. Bad use cases with solutions Ugly use cases.
Citation preview
Streams and Lambdas – The Good, The Bad and the Ugly
Peter LawreyHigher Frequency Trading Ltd
Introduction
For the last 6 months, Higher Frequency Trading has been porting a legacy C# application with over 25K lines of code to Java.
We have translated many LINQ statements into Java 8 Stream + Lambda.
What are some common patterns and anti-patterns we have seen?
Contains 2.0
if (list.stream().anyMatch(p -> p.getType() == Type.Cash)) {
Deep Copy
List<Position> newPositions = classPos.stream()
.map(Position::clone)
.collect(toList())
Validate all entries
positions.forEach(Position::validate);
Validate throws an InvalidStateException if invalid
Summing BigDecimal
BigDecimal sum = getResults().stream()
.reduce(BigDecimal.ZERO,
(bd, t) -> bd.add(t.getRequirement()),
BigDecimal::add);
Sorting by multiple fields
setTrades(getTrades().stream()
.sorted(comparing(t -> t.getInfo().getDate())
.thenComparing(Position::getCUSIP)
.thenComparing(Position::getQuantity).reversed())
.collect(Collectors.toList()));
Group By
Map<String, List<Position>> positionBySymbol =
positions.values().stream()
.filter(p -> p.getQuantity() != 0)
.collect(groupingBy(Position::getSymbol));
Streaming Maps
pos.entrySet().stream()
.filter(p -> p.getValue().getQuantity() != 0.0)
.forEach(p -> pos2.put(p.getKey(), p.getValue()));
To collect or not (anti-pattern)
getTrades().stream()
.filter(t -> getDate().equals(t.getInfo().getDate()))
.collect(toList())
.forEach(t -> trades.add(t.getInfo()));
To collect or not (solution)
List<Trade> trades = getTrades().stream()
.filter(t -> getDate().equals(t.getInfo().getDate()))
.map(t → t.getInfo())
.collect(Collectors.toList());
Sort of sorted (anti pattern)
Map<Date, List<Trade>> groupTrades =
trades.stream()
.sorted(comparing(Trade::getDate))
.collect(groupingBy(Trade::getDate));
Sort of sorted (solution)
Map<Date, List<Trade>> groupTrades =
trades.stream()
.collect(groupingBy(
TradeDetail::getTradeDate,
TreeMap::new,
toList()));
Multi-sorted (anti-pattern)
return trade.stream()
.filter(t -> !isExcluded(t))
.sorted(comparing(Trade::getDate))
.sorted(comparing(Trade::getCUSIP))
.sorted(comparing(Trade::getNetAmount))
.collect(toList());
Multi-sorted (solution)
return trade.stream()
.filter(t -> !isExcluded(t))
.sorted(comparing(Trade::getNetAmount)
.thenComparing(Trade::getCUSIP)
.thenComparing(Trade::getDate))
.collect(toList());
Top twenty words (Ugly)
List<String> words =
Files.lines(path).parallel()
.flatMap(line -> Arrays.asList(line.split("\\b")).stream())
.collect(groupingBy(w -> w, counting()))
.entrySet().stream()
.sorted(comparing(Map.Entry<String, Long>::getValue).reversed())
.limit(20)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
I must use streams (Ugly)
combinedList.addAll(
balances.stream().collect(Collectors.toList()));
List<Trade> allTrades = new ArrayList<>();
trades1.forEach(t -> allTrades.add(t));
trades2.forEach(t -> allTrades.add(t));
Optional denial
Position todayPos = newPos.stream()
.filter(pos -> pos.getCUSIP().equals(p.getCUSIP()))
.findFirst().orElse(null);
if (todayPos != null) {
Optional denial
Optional<MTrade> otodayTrade = trades.stream()
.filter(t -> t.getCUSIP().equals(p.getCUSIP())).findFirst();
MTrade todayTrade = null;
if (otodayTrade.isPresent()) todayTrade = otodayTrade.get();
if (todayTrade != null && todayTrade.getClosingPrice() != null) {
Q & A
Peter Lawrey
http://vanillajava.blogspot.com/
@PeterLawrey