Master Java Stream API: Real‑World Examples Covering 90% of Business Scenarios

This article introduces Java 8 functional programming concepts such as lambda expressions and method references, explains the Stream API, and provides dozens of practical code snippets for querying, grouping, aggregating, sorting, partitioning, and parallel processing of collections, helping developers handle most everyday business logic efficiently.

Lin is Dream
Lin is Dream
Lin is Dream
Master Java Stream API: Real‑World Examples Covering 90% of Business Scenarios

Java 8 introduced functional programming features, including lambda expressions and method references, allowing functions to be passed as parameters and simplifying code abstraction (y = f(x), where x is input and y is output).

The core of functional programming in Java is the java.util.stream.Stream interface, which enables fluent operations on collections.

Stream API Examples

The following code snippets summarize more than 90% of typical business scenarios and are recommended for Java beginners.

1. Use in Instead of for Loop Query

List<String> userIds = users.stream()
    .map(TestUser::getUserId)
    .collect(Collectors.toList());
LambdaQueryWrapper<TestOrder> wrapper = Wrappers.lambdaQuery(TestOrder.class)
    .in(TestOrder::getUserId, userIds)
    .orderByDesc(TestOrder::getOrderId);
List<Order> orders = orderService.list(wrapper);
Map<String, List<TestOrder>> userOrderMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getUserId));

2. List to Map Transformations

2.0 Group by Single Field

Map<String, List<TestUser>> userOrderMap = users.stream()
    .collect(Collectors.groupingBy(user -> {
        if (user.getRemainAmount().compareTo(new BigDecimal(10000)) >= 0) {
            return "HighValue";
        } else if (user.getRemainAmount().compareTo(new BigDecimal(1000)) >= 0) {
            return "MidValue";
        } else {
            return "LowValue";
        }
    }));

2.1 Group by Multiple Fields (Composite Key)

Map<String, List<TestUser>> userOrderMap = users.stream()
    .collect(Collectors.groupingBy(user -> user.getRemainAmount() + "_" + user.getName()));

2.2 Aggregations on List Fields

// Sum
Map<Integer, Integer> sumMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus, Collectors.summingInt(TestOrder::getNum)));
// Count
Map<Integer, Long> countMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus, Collectors.counting()));
// Average
Map<Integer, Double> avgMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus, Collectors.averagingInt(TestOrder::getNum)));
// Sum BigDecimal
Map<String, BigDecimal> priceMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getProductId,
        Collectors.mapping(TestOrder::getRewardAmt, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

2.3 Find Min/Max in Groups

// Minimum price per status
Map<Integer, TestOrder> minMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus,
        Collectors.collectingAndThen(Collectors.minBy(Comparator.comparing(TestOrder::getPrice)),
            opt -> opt.orElse(null))));
// Maximum price per status
Map<Integer, TestOrder> maxMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus,
        Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(TestOrder::getPrice)),
            opt -> opt.orElse(null))));

2.4 Preserve Insertion Order

Map<Integer, List<TestOrder>> orderedMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getStatus, LinkedHashMap::new, Collectors.toList()));

2.5 Sort List by Field

// Sort by price descending and then group by order name
Map<String, List<TestOrder>> sortedGroup = orders.stream()
    .sorted(Comparator.comparing(TestOrder::getPrice).reversed())
    .collect(Collectors.groupingBy(TestOrder::getOrderName));

2.6 Convert List to Other Objects

List<TestUserDto> dtoList = users.stream()
    .map(user -> BeanUtil.copyProperties(user, TestUserDto.class))
    .collect(Collectors.toList());

2.7 Join String Fields

Map<String, String> joinedMap = orders.stream()
    .collect(Collectors.groupingBy(TestOrder::getUserId,
        Collectors.collectingAndThen(
            Collectors.mapping(TestOrder::getOrderName, Collectors.joining(",")),
            name -> "Product Names: " + name)));
String phones = list.stream()
    .map(Object::getPhone)
    .collect(Collectors.joining(","));

2.8 Partition by Condition

Map<Integer, Map<Boolean, List<TestUser>>> partitioned = users.stream()
    .collect(Collectors.groupingBy(TestUser::getStatus,
        Collectors.partitioningBy(user -> user.getAge() > 20)));
Map<Integer, Map<Boolean, Long>> partitionCount = users.stream()
    .collect(Collectors.groupingBy(TestUser::getStatus,
        Collectors.partitioningBy(user -> user.getAge() > 20, Collectors.counting())));

2.9 Custom Mapping and Filtering

Map<String, List<String>> result = list.stream()
    .collect(Collectors.groupingBy(coupon -> String.valueOf(coupon.getId()),
        Collectors.mapping(coupon -> {
            if (coupon.getActivityId().equals(this.actId)) {
                return JSONObject.toJSONString(coupon);
            } else {
                return coupon.getStockCount().toString();
            }
        }, Collectors.toList())));

3. Sum Over a Field

int totalAge = users.stream()
    .mapToInt(TestUser::getAge)
    .sum();
BigDecimal totalAmount = users.stream()
    .map(TestUser::getRemainAmount)
    .reduce(BigDecimal.ZERO, BigDecimal::add);

4. Sort and Collect

// Collect sorted amounts
List<BigDecimal> sortedAmounts = users.stream()
    .map(TestUser::getRemainAmount)
    .sorted()
    .collect(Collectors.toList());
// Sort by amount then collect objects
List<TestUser> sortedUsers = users.stream()
    .sorted(Comparator.comparing(TestUser::getRemainAmount))
    .collect(Collectors.toList());

5. Filter, Max, Min

// Filter non‑null phone and sum ages
int filteredSum = users.stream()
    .filter(u -> u.getPhone() != null)
    .mapToInt(TestUser::getAge)
    .sum();
// Max by remaining amount
TestUser maxUser = users.stream()
    .max(Comparator.comparing(TestUser::getRemainAmount))
    .orElse(null);
// Min by remaining amount
TestUser minUser = users.stream()
    .min(Comparator.comparing(TestUser::getRemainAmount))
    .orElse(null);

6. Peek for Debugging

List<BigDecimal> amounts = users.stream()
    .map(TestUser::getRemainAmount)
    .peek(System.out::println)
    .collect(Collectors.toList());

7. Skip and Limit

List<TestUser> afterSkip = users.stream()
    .skip(5)
    .collect(Collectors.toList());
List<TestUser> firstFive = users.stream()
    .limit(5)
    .collect(Collectors.toList());

8. Flatten Multiple Lists

List<TestOrder> allOrders = userDtos.stream()
    .flatMap(dto -> dto.getOrders().stream())
    .collect(Collectors.toList());

9. Find First Element

TestUserDto firstDto = userDtos.stream()
    .findFirst()
    .orElse(null);

10. Parallel Stream for Large Data

TestUserDto parallelFirst = userDtos.stream()
    .parallel()
    .findFirst()
    .orElse(null);

11. MyBatis‑Plus Grouping with Count and Having

LambdaQueryWrapper<TestOrder> wrapper = new QueryWrapper<TestOrder>()
    .select("*, count(*) as count")
    .lambda()
    .groupBy(TestOrder::getUserId)
    .orderByDesc(TestOrder::getOrderId)
    .having("count(*) > {0}", 10);

The article concludes with a reminder to experiment with these patterns, adapt them to your own domain models, and share feedback for continuous improvement.

JavaLambdaFunctional ProgrammingCollectionsStream APIParallel StreamsMybatisPlus
Lin is Dream
Written by

Lin is Dream

Sharing Java developer knowledge, practical articles, and continuous insights into computer engineering.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.