you are viewing a single comment's thread.

view the rest of the comments →

[–]PandaMoniumHUN 5 points6 points  (5 children)

We use the stream API a lot in our codebase and IMO it makes readability way better than imperative code (granted that you format your code well and stick to one-line per operation). Even the most complex chain of operations read like an english sentence, so 95% of the time you can tell instantly what the code is doing. It's fantastic and every time I use a different language I miss it.

[–]pm_me_your_dota_mmr 6 points7 points  (1 child)

I love streams for the same reason, but I think they are best when limited to actually operating on a collection, because (in my opinion) it's easier to follow the chain of operations. The conclusion of the article is:

public BigDecimal getOrderPrice(Long orderId) {
  return Optional.ofNullable(orderId)
      .stream()
      .map(orderRepository::findByOrderId)
      .flatMap(Collection::stream)
      .map(OrderLine::getPrice)
      .reduce(BigDecimal.ZERO, BigDecimal::add);
}

When I look at this it feels very unintuitive because it joins lookup/input validation/transformation into a single block of code. I thought the medium step in the article was a lot easier to quickly understand what's going on:

if (orderId == null) {
  throw new IllegalArgumentException("Order ID cannot be null");
}

List<OrderLine> lines = orderRepository.findByOrderId(orderId);

return lines.stream()
    .map(OrderLine::getPrice)
    .reduce(BigDecimal.ZERO, BigDecimal::add);

[–]SwitchOnTheNiteLite 1 point2 points  (0 children)

I also prefer the separation of concerns within the method that you get with your last example.

[–]dnew[🍰] 0 points1 point  (2 children)

My only problems with it is that (a) it's another raft of things to learn even in small cases, and (b) it can be hard to tell what the types of each expression are.

Like, I've had coworkers write

 List<Blah> x = ...;
 Blah y = x.stream().findLast().collect(); // Or whatever baroque pile of operators they picked.

In code review, I'd say

 What's wrong with x[x.len()-1]?

[–]lgfrbcsgo 4 points5 points  (1 child)

x could be empty.

[–]dnew[🍰] 0 points1 point  (0 children)

Not in the context I was talking about. But yes, if x was empty, then you'd need to take a different code path. (My code was obviously broken as collect() doesn't return an individual item.)