Fundamentals 29 min read

Master Java 8: Lambda, Stream, and LocalDateTime Explained with Real Code

This article introduces Java 8’s new language features—Lambda expressions, the Stream API, and the modern date‑time classes—explaining their syntax, core concepts, and practical usage through clear examples and code snippets that illustrate how they simplify collection processing and date handling.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Master Java 8: Lambda, Stream, and LocalDateTime Explained with Real Code

Lambda

Lambda Introduction

Lambda expressions are anonymous functions derived from the mathematical λ‑calculus, providing a concise way to represent functional interfaces.

Structure of Lambda Expressions

A lambda can have zero or more parameters.

Parameter types may be explicitly declared or inferred.

All parameters must be enclosed in parentheses and separated by commas.

Empty parentheses denote no parameters, e.g., () -> 42.

If there is a single inferred‑type parameter, the parentheses may be omitted, e.g., a -> a * a.

The body may contain zero or more statements.

If the body consists of a single statement, braces can be omitted; the return type matches the expression.

Multiple statements require braces; the return type matches the block’s return type.

Using Lambda Expressions

Simple map traversal with a traditional loop:

Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
System.out.println("map普通方式遍历:");
for (String key : map.keySet()) {
    System.out.println("k=" + key + ",v=" + map.get(key));
}

Using a lambda to traverse the same map:

System.out.println("map拉姆达表达式遍历:");
map.forEach((k, v) -> {
    System.out.println("k=" + k + ",v=" + v);
});

List traversal with lambda and method reference:

List<String> list = new ArrayList<>();
list.add("a");
list.add("bb");
list.add("ccc");
list.add("dddd");
System.out.println("list拉姆达表达式遍历:");
list.forEach(v -> {
    System.out.println(v);
});
System.out.println("list双冒号运算符遍历:");
list.forEach(System.out::println);
map普通方式遍历:
 k=a,v=a
 k=b,v=b
 k=c,v=c
 k=d,v=d
map拉姆达表达式遍历:
 k=a,v=a
 k=b,v=b
 k=c,v=c
 k=d,v=d
list拉姆达表达式遍历:
 a
 bb
 ccc
 dddd
list双冒号运算符遍历:
 a
 bb
 ccc
 dddd

Lambda can also replace anonymous inner classes, e.g., thread creation:

// Traditional way
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("普通方式创建!");
    }
};
// Lambda way
Runnable r2 = () -> System.out.println("拉姆达方式创建!");

Note: In a lambda, this refers to the enclosing class, whereas in an anonymous class it refers to the anonymous instance.

Lambda Usage Tips

While lambdas reduce boilerplate, they may also decrease readability if overused.

Stream

Stream Introduction

The Stream API provides a high‑level, declarative way to process collections, similar to writing SQL queries, enabling operations such as filtering, sorting, and aggregation without modifying the underlying data structures.

Stream features:

Not a data structure; it does not store elements.

No indexed access, though you can generate arrays or lists.

Lazy evaluation: intermediate operations are deferred until a terminal operation triggers execution.

Built‑in parallelism: a parallel stream runs operations concurrently without explicit threading code.

Can represent infinite streams; short‑circuiting operations like limit or findFirst allow early termination.

All stream operations require a lambda expression as a parameter.

Stream Operation Types

Intermediate operations return a new stream and are lazy (e.g., filter, map, sorted).

Terminal operations produce a result or side effect and trigger processing (e.g., forEach, collect, reduce).

Using Stream

Filtering a list with the traditional loop:

List<String> list = Arrays.asList("张三", "李四", "王五", "xuwujing");
System.out.println("过滤之前:" + list);
List<String> result = new ArrayList<>();
for (String str : list) {
    if (!"李四".equals(str)) {
        result.add(str);
    }
}
System.out.println("过滤之后:" + result);

Same filtering using Stream:

List<String> result2 = list.stream()
    .filter(str -> !"李四".equals(str))
    .collect(Collectors.toList());
System.out.println("stream 过滤之后:" + result2);
过滤之前:[张三, 李四, 王五, xuwujing]
过滤之后:[张三, 王五, xuwujing]
stream 过滤之后:[张三, 王五, xuwujing]

Other common Stream usages (code snippets only):

// Construct a stream
Stream<String> stream = Stream.of("a", "b", "c");
String[] arr = {"a", "b", "c"};
stream = Stream.of(arr);
stream = Arrays.stream(arr);
List<String> list = Arrays.asList(arr);
stream = list.stream();
// Convert a stream (single‑use!)
Stream<String> s = Stream.of("a", "b", "c");
String[] toArray = s.toArray(String[]::new);
List<String> toList = s.collect(Collectors.toList());
Set<String> toSet = s.collect(Collectors.toSet());
String joined = s.collect(Collectors.joining());
// map – transform each element
List<String> upper = list3.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
List<Integer> ints = list31.stream()
    .map(Integer::valueOf)
    .collect(Collectors.toList());
List<Integer> squares = list5.stream()
    .map(n -> n * n)
    .collect(Collectors.toList());
// filter – keep elements that match a predicate
String found = list.stream()
    .filter(str -> "李四".equals(str))
    .findAny()
    .orElse("找不到!");
int sum = lists.stream()
    .filter(u -> "张三".equals(u.getName()))
    .mapToInt(User::getId)
    .sum();
// flatMap – one‑to‑many mapping
String sentence = "The way of the future";
List<String> words = Arrays.asList(sentence)
    .stream()
    .flatMap(str -> Stream.of(str.split(" ")))
    .filter(w -> w.length() > 0)
    .collect(Collectors.toList());
// limit & skip – pagination
Random rd = new Random();
rd.ints().limit(3).forEach(System.out::println);
List<String> page = list9.stream()
    .map(User::getName)
    .limit(3)
    .skip(2)
    .collect(Collectors.toList());
// sorted – ordering
rd.ints().limit(3).sorted().forEach(System.out::println);
// peek – observe elements during processing
Stream.of("one", "two", "three", "four")
    .filter(e -> e.length() > 3)
    .peek(e -> System.out.println("Before: " + e))
    .map(String::toUpperCase)
    .peek(e -> System.out.println("After: " + e))
    .collect(Collectors.toList());
// parallel – concurrent processing
long emptyCount = strings.parallelStream()
    .filter(String::isEmpty)
    .count();
// match – boolean checks
boolean all = lists.stream().allMatch(u -> u.getId() > 3);
boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
// reduce – combine elements
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
int sum = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
int sumWithInit = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum);
// iterate – generate a sequence
Stream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + " "));
// Supplier – custom stream source
Stream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + ", " + u.getName()));
// groupingBy & partitioningBy
Map<Integer, List<User>> byId = Stream.generate(new UserSupplier2())
    .limit(5)
    .collect(Collectors.groupingBy(User::getId));
Map<Boolean, List<User>> byAge = Stream.generate(new UserSupplier3())
    .limit(5)
    .collect(Collectors.partitioningBy(p -> p.getId() < 18));
// summaryStatistics – numeric summary
IntSummaryStatistics stats = numbers.stream()
    .mapToInt(x -> x)
    .summaryStatistics();

LocalDateTime

Introduction

Java 8 introduced a new, immutable, thread‑safe date‑time API (java.time) that replaces the mutable java.util.Date and non‑thread‑safe SimpleDateFormat.

Key Classes

Instant – a point on the timeline.

LocalDate – date without time (yyyy‑MM‑dd).

LocalTime – time without date.

LocalDateTime – date and time without zone.

ZonedDateTime – date‑time with zone information.

Usage

1. Get current date/time

LocalDate nowDate = LocalDate.now();
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("当前时间:" + nowDate);
System.out.println("当前时间:" + nowDateTime);

2. Access components

LocalDateTime ldt = LocalDateTime.now();
System.out.println("当前年:" + ldt.getYear());
System.out.println("当前月份:" + ldt.getMonthValue());
System.out.println("当前时:" + ldt.getHour());
System.out.println("当前分:" + ldt.getMinute());
System.out.println("当前时间:" + ldt.toString());

3. Formatting

System.out.println("格式化时间: " + ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));

4. Adding / subtracting

System.out.println("后5天时间:" + ldt.plusDays(5));
System.out.println("前5天时间并格式化:" + ldt.minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

5. Create specific date

LocalDate ld1 = LocalDate.of(2017, Month.NOVEMBER, 17);
LocalDate ld2 = LocalDate.of(2018, 2, 11);

6. Date difference

LocalDate d1 = LocalDate.parse("2017-11-17");
LocalDate d2 = LocalDate.parse("2018-01-05");
Period p = Period.between(d1, d2);
System.out.println("相差年:" + p.getYears() + " 相差月:" + p.getMonths() + " 相差天:" + p.getDays());
System.out.println("相差月份:" + ChronoUnit.MONTHS.between(d1, d2));
System.out.println("相差天数:" + ChronoUnit.DAYS.between(d1, d2));

7. Instant and Duration

Instant i1 = Instant.now();
Instant i2 = i1.plus(Duration.ofSeconds(10));
System.out.println("相差毫秒:" + Duration.between(i1, i2).toMillis());

8. Comparison

LocalDateTime t1 = LocalDateTime.now();
LocalDateTime t2 = t1.plusMinutes(10);
System.out.println("t1 after t2:" + t1.isAfter(t2));
System.out.println("t1 before t2:" + t1.isBefore(t2));

9. Time zones

Clock utc = Clock.systemUTC();
System.out.println("UTC timestamp:" + utc.millis());
ZoneId ny = ZoneId.of("America/New_York");
ZonedDateTime nyTime = ZonedDateTime.now(ny);
System.out.println("NY time:" + nyTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
JavaLambdaFunctional ProgrammingJDK8LocalDateTimestreamdatetime-api
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.