Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Legacy lambda code

1,298 views

Published on

After migrating a three year old C# project to Java we ending up with a significant portion of legacy code using lambdas in Java. What was some of the good use cases, code which could be written better and the problems we had migrating from C#. At the end we look at the performance implications of using Lambdas.

Published in: Technology
  • Be the first to comment

Legacy lambda code

  1. 1. Javaland 2015 Peter Lawrey Legacy Lambda Code in Java
  2. 2. Agenda • Lambdas: A complicated way to do something simple? • Lambda Patterns we used. • Lambda Patterns we shouldn’t have used. • Lambda Patterns we have used since.
  3. 3. Counting elements in a Stream long count = list.stream().count();
  4. 4. Counting elements in a Stream long count = list.stream().count(); // Stream.count() @Override public final long count() { return mapToLong(e -> 1L).sum(); }
  5. 5. Counting elements in a Stream long count = list.stream().count(); // LongStream.sum() @Override public final long sum() { // use better algorithm to compensate for intermediate overflow? return reduce(0, Long::sum); }
  6. 6. Counting elements in a Stream long count = list.parallelStream().count(); When the examples get more complex, lambdas become much more interesting.
  7. 7. Porting a legacy C# application For the last 8 months, Higher Frequency Trading ported 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?
  8. 8. Summing BigDecimal getResults().stream() .reduce(BigDecimal.ZERO, (bd, t) -> bd.add(t.getRequirement()), BigDecimal::add);
  9. 9. Validate all entries positions.stream().forEach(Position::validate); Validate throws an exception.
  10. 10. Sorting by multiple fields. setTrades(trades.stream() .sorted(comparing(t -> t.getInfo().getDate()) .thenComparing(Position::getCUSIP) .thenComparing(Position::getQuantity) .reversed()) .collect(toList()));
  11. 11. Sorting by multiple fields, Quantity reversed setTrades(trades.stream() .sorted(comparing(t -> t.getInfo().getDate()) .thenComparing(Position::getCUSIP) .reversed() .thenComparing(Position::getQuantity) .reversed()) .collect(toList()));
  12. 12. Group By Map<String, List<Position>> positionBySymbol = positions.values().stream() .filter(p -> p.getQuantity() != 0) .collect(groupingBy(Position::getSymbol));
  13. 13. Streaming Maps pos.entrySet().stream() .filter(p -> p.getValue().getQuantity() != 0.0) .forEach(p -> pos2.put(p.getKey(), p.getValue()));
  14. 14. Contains 2.0 if (list.stream() .anyMatch(p -> p.getType() == Type.Cash)) {
  15. 15. Deep copy List<Position> newPositions = classPos.stream() .map(Position::clone) .collect(toList())
  16. 16. To collect or not to collect (anti-pattern) getTrades().stream() .filter(t -> getDate().equals(t.getInfo().getDate())) .collect(toList()) .forEach(t -> trades.add(t.getInfo()));
  17. 17. To collect or not to collect (solution) List<TradeInfo> trades = getTrades().stream() .filter(t -> getDate().equals( t.getInfo().getDate())) .map(Trade::getInfo) .collect(toList());
  18. 18. Sort of sorted (anti-pattern) Map<Date, List<Trade>> groupTrades = trades.stream() .sorted(comparing(Trade::getDate)) .collect(groupingBy(Trade::getDate));
  19. 19. Sorting (solution) Map<Date, List<Trade>> groupTrades = trades.stream() .collect(groupingBy( TradeDetail::getTradeDate, TreeMap::new, toList()));
  20. 20. 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()); See slide 2 example for solution.
  21. 21. Concurrent removal ? anti-pattern ? input.stream() .filter(t -> t.getParent() == p.getParent()) .forEach(input::remove);
  22. 22. Optional Denial Position todayPos = newPos.stream() .filter(pos -> pos.getCUSIP() .equals(p.getCUSIP())) .findFirst().orElse(null); if (todayPos != null) {
  23. 23. 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){
  24. 24. Optional for equals public boolean equals(Object obj) { return Optional.ofNullable(obj) .filter(that -> that instanceof Test) .map(that -> (Test)that) .filter(that -> Objects.equals(this.s1, that.s1)) .filter(that -> Objects.equals(this.s2, that.s2)) .isPresent(); } Posted by Marko Topolnik
  25. 25. Find the twenty most frequent words in a file To use parallel or not? 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());
  26. 26. Lambdas and templates (before Java 8) long value; this.lock.lock(); try { value = doSomething(); } finally { this.lock.unlock(); }
  27. 27. Lambdas and templates (with Java 8) public static <R> R with(Lock lock, Callable<R> work) { lock.lock(); try { return work.call(); } finally { lock.unlock(); } }
  28. 28. Lambdas and templates (with Java 8) long value = with(lock, this::doSomething); Note: with inlining, the temporary “Long” object can be eliminated.
  29. 29. Lambdas and performance public void readMarshallable(Wire wire) { wire.read(Fields.I).int32(x -> i = x) .read(Fields.J).int32(x -> j = x) .read(Fields.K).int32(x -> k = x) .read(Fields.L).int32(x -> l = x) .read(Fields.M).int32(x -> m = x) .read(Fields.N).int32(x -> n = x) .read(Fields.O).int32(x -> o = x) .read(Fields.P).int32(x -> p = x); }
  30. 30. Lambdas and performance garbage in bytes per lambda
  31. 31. Lambdas and performance -XX:BCEATraceLevel=3 Prints messages like Skipping method because: code size (271) exceeds MaxBCEAEstimateSize (150). So I raised the -XX:MaxBCEAEstimateSize=300
  32. 32. Lambda type inference • Java 8 uses type inference much more than before. • Inference can appear to be as a cast. // error type is not known. Object o = () -> System.out::println; // type is inferred. Runnable o = () -> System.out::println; // type is inferred not cast at runtime. Object o = (Runnable & Serializable) () -> System.out::println;
  33. 33. Lambda internals • Classes for Lambdas are generated at runtime. lambda.getClass() still works. • The contents of code in a lambda is added as a static method, except … • When a lambda expression refers to a method e.g. this::method or Class::new no additional method is created. • Provided your code is inlined, the lambda “object” can be eliminated. This also works for anonymous inner classes.
  34. 34. End randomly (Don’t try this at home) IntStream.range(0, 128).parallel() .forEach(System::exit);
  35. 35. Q & A http://vanillajava.blogspot.com/ Peter Lawrey @PeterLawrey

×