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.
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
ddddLambda 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")));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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
