Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Legacy lambda code

1 291 vues

Publié le

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.

Publié dans : Technologie
  • Soyez le premier à commenter

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

×