Java8 新特性一篇文章给你讲透
目录
Java8简介
什么是Java8
Java8是Java语言的一个重要版本,于2014年3月发布。它引入了许多革命性的新特性,特别是函数式编程的支持,使得Java语言更加现代化和强大。
主要特性概览
核心特性:
- Lambda表达式: 支持函数式编程
- Stream API: 强大的集合处理能力
- 新的日期时间API: 替代旧的Date和Calendar
- 接口默认方法: 接口可以包含实现方法
- Optional类: 优雅处理空值
- 方法引用: 简化Lambda表达式
- 新的Nashorn JavaScript引擎
- 重复注解支持
与老版本的区别
1. 编程范式变化
Java7及以前:
- 面向对象编程为主
- 命令式编程风格
- 代码相对冗长
- 集合操作需要循环
Java8:
- 支持函数式编程
- 声明式编程风格
- 代码更简洁优雅
- Stream API简化集合操作
2. 语法差异对比
// Java7: 传统循环
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperNames = new ArrayList<>();
for (String name : names) {
if (name.length() > 3) {
upperNames.add(name.toUpperCase());
}
}
// Java8: Stream API
List<String> upperNames = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
3. 性能提升
性能改进:
- 并行流支持多核处理
- 新的垃圾收集器G1
- 字符串去重优化
- 更好的JIT编译器
Lambda表达式
基本语法
// 基本语法: (parameters) -> expression
// 或 (parameters) -> { statements; }
// 示例1: 无参数
Runnable runnable = () -> System.out.println("Hello Lambda");
// 示例2: 单参数
Consumer<String> consumer = (str) -> System.out.println(str);
// 简化写法
Consumer<String> consumer2 = str -> System.out.println(str);
// 示例3: 多参数
BinaryOperator<Integer> add = (a, b) -> a + b;
// 示例4: 多行语句
BinaryOperator<Integer> max = (a, b) -> {
if (a > b) return a;
else return b;
};
常见用法
// 集合遍历
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println("Hello " + name));
// 线程创建
new Thread(() -> {
System.out.println("Running in thread");
}).start();
// 事件处理
button.addActionListener(e -> System.out.println("Button clicked"));
// 比较器
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30)
);
people.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
函数式接口
内置函数式接口
// 1. Predicate<T> - 断言接口
Predicate<String> isLongerThan5 = str -> str.length() > 5;
boolean result = isLongerThan5.test("Hello World"); // true
// 2. Function<T, R> - 函数接口
Function<String, Integer> getLength = String::length;
Integer length = getLength.apply("Hello"); // 5
// 3. Consumer<T> - 消费者接口
Consumer<String> printer = System.out::println;
printer.accept("Hello Consumer");
// 4. Supplier<T> - 供应者接口
Supplier<Double> randomSupplier = Math::random;
Double random = randomSupplier.get();
// 5. BiFunction<T, U, R> - 双参数函数接口
BiFunction<String, String, String> concat = String::concat;
String result = concat.apply("Hello ", "World"); // "Hello World"
自定义函数式接口
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
// 可以有默认方法
default int multiply(int a, int b) {
return a * b;
}
}
// 使用自定义函数式接口
MathOperation add = (a, b) -> a + b;
MathOperation subtract = (a, b) -> a - b;
System.out.println(add.operate(10, 5)); // 15
System.out.println(subtract.operate(10, 5)); // 5
System.out.println(add.multiply(10, 5)); // 50
方法引用
方法引用类型
// 1. 静态方法引用
Function<String, Integer> parseInt = Integer::parseInt;
Integer number = parseInt.apply("123");
// 2. 实例方法引用
Function<String, String> toUpperCase = String::toUpperCase;
String upper = toUpperCase.apply("hello");
// 3. 对象方法引用
String prefix = "Hello ";
Function<String, String> addPrefix = prefix::concat;
String result = addPrefix.apply("World"); // "Hello World"
// 4. 构造方法引用
Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();
// 5. 数组构造方法引用
Function<Integer, String[]> arraySupplier = String[]::new;
String[] array = arraySupplier.apply(5);
实际应用示例
// 排序
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.sort(String::compareToIgnoreCase);
// 映射
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// 过滤
List<String> longNames = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList());
Stream流
Stream基础概念
Stream特点:
- 不存储数据,只是数据的视图
- 不会修改源数据
- 惰性求值,只有终端操作才会执行
- 可以并行处理
- 只能遍历一次
创建Stream
// 1. 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 2. 从数组创建
String[] array = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);
// 3. 从值创建
Stream<String> stream3 = Stream.of("a", "b", "c");
// 4. 从函数创建
Stream<Integer> stream4 = Stream.iterate(0, n -> n + 2).limit(10);
// 5. 从生成器创建
Stream<Double> stream5 = Stream.generate(Math::random).limit(5);
// 6. 并行流
Stream<String> parallelStream = list.parallelStream();
中间操作
List<Person> people = Arrays.asList(
new Person("Alice", 25, "Engineer"),
new Person("Bob", 30, "Manager"),
new Person("Charlie", 35, "Engineer"),
new Person("David", 28, "Developer")
);
// 1. filter - 过滤
List<Person> engineers = people.stream()
.filter(p -> "Engineer".equals(p.getJob()))
.collect(Collectors.toList());
// 2. map - 映射
List<String> names = people.stream()
.map(Person::getName)
.collect(Collectors.toList());
// 3. flatMap - 扁平化映射
List<String> allSkills = people.stream()
.flatMap(p -> p.getSkills().stream())
.collect(Collectors.toList());
// 4. distinct - 去重
List<String> uniqueJobs = people.stream()
.map(Person::getJob)
.distinct()
.collect(Collectors.toList());
// 5. sorted - 排序
List<Person> sortedByAge = people.stream()
.sorted(Comparator.comparing(Person::getAge))
.collect(Collectors.toList());
// 6. limit - 限制数量
List<Person> firstTwo = people.stream()
.limit(2)
.collect(Collectors.toList());
// 7. skip - 跳过元素
List<Person> skipFirst = people.stream()
.skip(1)
.collect(Collectors.toList());
// 8. peek - 查看元素(调试用)
List<Person> debugged = people.stream()
.peek(p -> System.out.println("Processing: " + p.getName()))
.collect(Collectors.toList());
终端操作
// 1. collect - 收集到集合
List<String> names = people.stream()
.map(Person::getName)
.collect(Collectors.toList());
// 2. forEach - 遍历
people.stream().forEach(p -> System.out.println(p.getName()));
// 3. count - 计数
long count = people.stream().count();
// 4. anyMatch - 是否存在匹配
boolean hasEngineer = people.stream()
.anyMatch(p -> "Engineer".equals(p.getJob()));
// 5. allMatch - 是否全部匹配
boolean allAdults = people.stream()
.allMatch(p -> p.getAge() >= 18);
// 6. noneMatch - 是否没有匹配
boolean noMinors = people.stream()
.noneMatch(p -> p.getAge() < 18);
// 7. findFirst - 找到第一个
Optional<Person> first = people.stream()
.filter(p -> p.getAge() > 25)
.findFirst();
// 8. findAny - 找到任意一个(并行流中很有用)
Optional<Person> any = people.stream()
.filter(p -> p.getAge() > 25)
.findAny();
// 9. reduce - 归约
Optional<Integer> totalAge = people.stream()
.map(Person::getAge)
.reduce(Integer::sum);
// 10. min/max - 最小/最大值
Optional<Person> youngest = people.stream()
.min(Comparator.comparing(Person::getAge));
Optional<Person> oldest = people.stream()
.max(Comparator.comparing(Person::getAge));
收集器Collectors
// 1. 收集到List
List<String> names = people.stream()
.map(Person::getName)
.collect(Collectors.toList());
// 2. 收集到Set
Set<String> uniqueNames = people.stream()
.map(Person::getName)
.collect(Collectors.toSet());
// 3. 收集到Map
Map<String, Person> nameToPerson = people.stream()
.collect(Collectors.toMap(
Person::getName,
Function.identity()
));
// 4. 收集到特定集合
LinkedList<String> linkedList = people.stream()
.map(Person::getName)
.collect(Collectors.toCollection(LinkedList::new));
// 5. 连接字符串
String allNames = people.stream()
.map(Person::getName)
.collect(Collectors.joining(", "));
// 6. 分组
Map<String, List<Person>> groupedByJob = people.stream()
.collect(Collectors.groupingBy(Person::getJob));
// 7. 分区
Map<Boolean, List<Person>> partitionedByAge = people.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() > 30));
// 8. 统计信息
IntSummaryStatistics ageStats = people.stream()
.mapToInt(Person::getAge)
.summaryStatistics();
// 9. 自定义收集器
List<String> customCollected = people.stream()
.map(Person::getName)
.collect(Collectors.collectingAndThen(
Collectors.toList(),
list -> {
Collections.reverse(list);
return list;
}
));
并行流处理
// 并行流示例
List<Person> people = Arrays.asList(/* 大量数据 */);
// 并行处理
List<String> names = people.parallelStream()
.filter(p -> p.getAge() > 25)
.map(Person::getName)
.collect(Collectors.toList());
// 并行流注意事项
// 1. 确保操作是无状态的
// 2. 避免修改共享状态
// 3. 某些操作在并行流中可能更慢(如findFirst)
// 性能测试
long start = System.currentTimeMillis();
List<String> sequential = people.stream()
.map(Person::getName)
.collect(Collectors.toList());
long sequentialTime = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
List<String> parallel = people.parallelStream()
.map(Person::getName)
.collect(Collectors.toList());
long parallelTime = System.currentTimeMillis() - start;
System.out.println("Sequential: " + sequentialTime + "ms");
System.out.println("Parallel: " + parallelTime + "ms");
Optional类
基本用法
// 1. 创建Optional
Optional<String> optional1 = Optional.of("Hello");
Optional<String> optional2 = Optional.ofNullable(null);
Optional<String> optional3 = Optional.empty();
// 2. 判断是否存在
if (optional1.isPresent()) {
System.out.println(optional1.get());
}
// 3. 安全获取值
String value = optional1.orElse("Default");
String value2 = optional1.orElseGet(() -> "Generated Default");
String value3 = optional1.orElseThrow(() -> new RuntimeException("Value not found"));
// 4. 链式操作
Optional<String> result = optional1
.filter(s -> s.length() > 3)
.map(String::toUpperCase);
// 5. 实际应用
public String getUserName(User user) {
return Optional.ofNullable(user)
.map(User::getName)
.orElse("Unknown");
}
实际应用示例
// 传统写法
public String getStreetName(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
return address.getStreet();
}
}
return "Unknown Street";
}
// 使用Optional
public String getStreetName(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getStreet)
.orElse("Unknown Street");
}
// 集合操作
List<User> users = Arrays.asList(/* 用户列表 */);
List<String> streetNames = users.stream()
.map(User::getAddress)
.filter(Objects::nonNull)
.map(Address::getStreet)
.filter(Objects::nonNull)
.collect(Collectors.toList());
// 使用Optional优化
List<String> streetNames2 = users.stream()
.map(user -> Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getStreet)
.orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
新的日期时间API
核心类
// 1. LocalDate - 日期
LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2024, 1, 1);
LocalDate parsedDate = LocalDate.parse("2024-01-01");
// 2. LocalTime - 时间
LocalTime now = LocalTime.now();
LocalTime specificTime = LocalTime.of(14, 30, 0);
LocalTime parsedTime = LocalTime.parse("14:30:00");
// 3. LocalDateTime - 日期时间
LocalDateTime now = LocalDateTime.now();
LocalDateTime specificDateTime = LocalDateTime.of(2024, 1, 1, 14, 30, 0);
// 4. ZonedDateTime - 带时区的日期时间
ZonedDateTime zonedNow = ZonedDateTime.now();
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime tokyoTime = ZonedDateTime.now(tokyoZone);
// 5. Duration - 时间段
Duration duration = Duration.between(startTime, endTime);
long hours = duration.toHours();
// 6. Period - 日期间隔
Period period = Period.between(startDate, endDate);
int years = period.getYears();
实际应用
// 日期计算
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate nextYear = today.plusYears(1);
// 日期比较
boolean isAfter = today.isAfter(LocalDate.of(2023, 12, 31));
boolean isBefore = today.isBefore(LocalDate.of(2025, 1, 1));
// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = LocalDateTime.now().format(formatter);
// 解析
LocalDateTime parsed = LocalDateTime.parse("2024-01-01 12:00:00", formatter);
// 时区转换
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
ZonedDateTime local = utc.withZoneSameInstant(ZoneId.systemDefault());
接口默认方法
基本概念
interface Vehicle {
// 默认方法
default void start() {
System.out.println("Vehicle starting...");
}
// 抽象方法
void stop();
// 静态方法
static void info() {
System.out.println("This is a vehicle interface");
}
}
class Car implements Vehicle {
@Override
public void stop() {
System.out.println("Car stopping...");
}
// 可以选择重写默认方法
@Override
public void start() {
System.out.println("Car starting...");
}
}
实际应用
// 集合接口的默认方法
List<String> list = Arrays.asList("a", "b", "c");
// forEach是默认方法
list.forEach(System.out::println);
// sort是默认方法
list.sort(String::compareTo);
// 自定义接口
interface DataProcessor<T> {
T process(T data);
default List<T> processBatch(List<T> dataList) {
return dataList.stream()
.map(this::process)
.collect(Collectors.toList());
}
default void validate(T data) {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null");
}
}
}
实际应用场景
1. 数据处理
// 用户数据处理
List<User> users = getUserList();
// 过滤、转换、收集
List<String> activeUserEmails = users.stream()
.filter(User::isActive)
.map(User::getEmail)
.filter(email -> email != null && email.contains("@"))
.collect(Collectors.toList());
// 分组统计
Map<String, Long> usersByRole = users.stream()
.collect(Collectors.groupingBy(
User::getRole,
Collectors.counting()
));
// 年龄统计
IntSummaryStatistics ageStats = users.stream()
.mapToInt(User::getAge)
.summaryStatistics();
2. 文件处理
// 读取文件并处理
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
List<String> longLines = lines
.filter(line -> line.length() > 100)
.map(String::toUpperCase)
.collect(Collectors.toList());
}
// 目录遍历
try (Stream<Path> paths = Files.walk(Paths.get("."))) {
List<Path> javaFiles = paths
.filter(path -> path.toString().endsWith(".java"))
.collect(Collectors.toList());
}
3. 数据库查询结果处理
// 假设从数据库查询到用户列表
List<User> users = userRepository.findAll();
// 复杂查询逻辑
Map<String, List<User>> usersByDepartment = users.stream()
.filter(user -> user.getStatus().equals("ACTIVE"))
.collect(Collectors.groupingBy(User::getDepartment));
// 统计信息
Map<String, DoubleSummaryStatistics> salaryStats = users.stream()
.collect(Collectors.groupingBy(
User::getDepartment,
Collectors.summarizingDouble(User::getSalary)
));
4. 配置处理
// 配置文件处理
Properties props = new Properties();
// ... 加载配置
// 使用Stream处理配置
Map<String, String> config = props.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().toString(),
entry -> entry.getValue().toString()
));
// 过滤特定配置
List<String> databaseConfigs = config.entrySet().stream()
.filter(entry -> entry.getKey().startsWith("db."))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
5. 异步处理
// 并行处理大量数据
List<String> urls = Arrays.asList(/* URL列表 */);
List<String> results = urls.parallelStream()
.map(url -> {
try {
return fetchUrl(url);
} catch (Exception e) {
return "Error: " + e.getMessage();
}
})
.collect(Collectors.toList());
总结
主要优势
Java8优势:
- 代码更简洁优雅
- 支持函数式编程
- 性能提升(并行流)
- 更好的空值处理
- 现代化的日期时间API
- 接口的默认方法
使用建议
最佳实践:
- 优先使用Stream API处理集合
- 合理使用Lambda表达式简化代码
- 注意并行流的适用场景
- 使用Optional处理空值
- 充分利用新的日期时间API
- 合理使用接口默认方法
学习路径
学习顺序:
1. Lambda表达式基础
2. 函数式接口
3. Stream API基础操作
4. 收集器和高级操作
5. Optional类使用
6. 新的日期时间API
7. 接口默认方法
8. 实际项目应用
Java8的新特性让Java语言更加现代化和强大,掌握这些特性可以显著提升代码质量和开发效率。建议在实际项目中逐步应用这些特性,积累经验。
2595

被折叠的 条评论
为什么被折叠?



