Java8新特性

代码星辉·七月创作之星挑战赛 10w+人浏览 247人参与

1.Lambda表达式

Lambda表达式是JDK8引入的一种函数式编程特性,允许以简洁的语法实现函数式接口(只有一个抽象方法的接口)。

(parameters) -> expression
或
(parameters) -> { statements; }
 
  • 参数列表:可省略参数类型(编译器自动推断),空参数时保留括号。
  • 箭头符号 ->:分隔参数和实现逻辑。
  • 表达式或代码块:单行表达式可省略大括号和return;多行语句需用大括号包裹。
package com.whm.unit13;

public class LambdaTest {
  public static void main(String[] args) {
    //使用匿名内部类的方式
    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println(Thread.currentThread().getName() + "线程执行");
      }
    }).start();
    /*匿名内部类缺点
    * 1.代码结构复杂
    * 2.new生产class文件占用内存高
    * 3.需要显示接口抽象方法代码冗余
    * */

    //使用lambda表达式  格式:(参数) -> {表达式或代码块}
    new Thread(() -> System.out.println("正在执行的线程" +
            Thread.currentThread().getName())).start();
    /*lambda表达式优点
    * 1.占用内存低
    * 2.语法简洁
    * 3.自动类型推断
    * */
  }
}
package com.whm.unit13;

public class LambdaCase {
  public static void main(String[] args) {
    //1.无参无返回值
    Test1 test1 = () -> System.out.println("Name=Jack");
    test1.method();
    //2.有参无返回值
    Test2 test2 = name -> System.out.println("Name=" + name);
    test2.method("Mary");
    //3.无参有一个返回值
    Test3 test3 = () -> "Name=Anny";
    System.out.println(test3.method());
    //4.有参有一个返回值
    Test4 test4 = name -> name;
    System.out.println("Name=" + test4.method("Tom"));
    //5.有参有多个返回值
    Test5 test5 = (n, m) -> n * m;
    System.out.println("Result=" + test5.method(10, 20));
  }
}

interface Test1 {
  void method();
}

interface Test2 {
  void method(String name);
}

interface Test3 {
  String method();
}

interface Test4 {
  String method(String name);
}

interface Test5 {
  int method(int n, int m);
}

 

1. 替代匿名内部类
// 传统写法
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

// Lambda写法
Runnable r2 = () -> System.out.println("Hello");
 
2. 集合操作
List<String> list = Arrays.asList("a", "b", "c");
list.forEach(item -> System.out.println(item));
 
3. 函数式接口
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));
 

2.方法引用

进一步简化Lambda,通过::符号引用已有方法:

  • 静态方法引用:ClassName::staticMethod
  • 实例方法引用:instance::method
  • 构造方法引用:ClassName::new
package com.whm.unit12;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class MethodTest {
  public static void main(String[] args) {
    Student student=new Student("Jack");
    //1.实例方法引用
    Supplier<String> supplier=student::getName;
    //2.静态方法引用
    Function<Double,Long> function=Math::round;
    //3.特殊方法引用
    Comparator<Integer> comparator=Integer::compareTo;
    Function<Student,String> function1=Student::getName;
    //4.构造方法引用
    Function<String,Student> function2=Student::new;
    //5.数组引用
    Function<Integer,int[]> function3=int[]::new;
    System.out.println(Arrays.toString(function3.apply(10)));
  }
}
class Student{
  private String name;

  public String getName() {
    return name;
  }

  public Student(String name) {
    this.name = name;
  }
}

3.常见函数式接口

JDK8在java.util.function包中提供了内置函数式接口:

  • Predicate<T>:断言型,boolean test(T t)
  • Consumer<T>:消费型,void accept(T t)
  • Function<T,R>:函数型,R apply(T t)
  • Supplier<T>:供给型,T get()

Predicate<T>:断言型

过滤集合中的元素

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Predicate<Integer> isEven = num -> num % 2 == 0;
List<Integer> evens = numbers.stream().filter(isEven).collect(Collectors.toList());
// 输出:[2, 4]
 

说明:通过 test 方法判断元素是否满足条件,常用于数据筛选。

Consumer<T>:消费型

遍历并处理集合元素

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
names.forEach(printUpperCase);
// 输出:ALICE\nBOB\nCHARLIE
 

说明:通过 accept 方法对输入参数执行操作,无返回值,适用于日志打印或数据修改。

Function<T, R>:函数型

字符串转整数并计算平方

Function<String, Integer> parseAndSquare = s -> (int) Math.pow(Integer.parseInt(s), 2);
int result = parseAndSquare.apply("3");
// 输出:9
 

说明:通过 apply 方法将输入类型 T 转换为输出类型 R,适合数据转换或链式处理。

Supplier<T>:供给型

场景示例:生成随机数

Supplier<Double> randomSupplier = () -> Math.random();
double randomValue = randomSupplier.get();
// 输出:0.0 <= randomValue < 1.0
 

4.Stream API

常用操作分类

中间操作(返回新 Stream)
  • 过滤:filter(Predicate<T>)
    示例:筛选偶数
    stream.filter(x -> x % 2 == 0)

  • 映射:map(Function<T,R>)
    示例:转为字符串
    stream.map(Object::toString)

  • 去重:distinct()
    示例:去除重复元素
    stream.distinct()

终端操作(触发计算)
  • 收集结果:collect(Collectors.toList())
    示例:转为 List
    stream.collect(Collectors.toList())

  • 遍历:forEach(Consumer<T>)
    示例:打印元素
    stream.forEach(System.out::println)

  • 聚合:reduce(BinaryOperator<T>)
    示例:求和
    stream.reduce(0, Integer::sum)

package com.whm.unit13;

import javax.net.ssl.SSLContext;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class StreamAPITest {
  public static void main(String[] args) {
    List<Student> list = Arrays.asList(
            new Student("Jack", 19, '男'),
            new Student("Jack", 21, '女'),
            new Student("Anny", 20, '男'),
            new Student("Mary", 18, '女'),
            new Student("Tom", 22, '男'));
    //1.打印所有男生
    list.stream().filter(student -> student.getGender() == '男').forEach(System.out::println);
    //2.使用 Stream API 打印所有女生的信息。
    list.stream().filter(student -> student.getGender() == '女').forEach(System.out::println);
    System.out.println("===================");
    //3.将学生列表按年龄从低到高排序,并打印结果。
    list.stream().sorted((s1, s2) -> s1.getAge() - s2.getAge()).forEach(System.out::println);
    //4.使用 map() 提取所有学生的姓名,并将结果收集为一个 List<String>。
    System.out.println("===================");
    List<String> list1 = list.stream().map(Student -> Student.getName()).toList();
    System.out.println(list1);
    System.out.println("===================");
    //5.使用 Stream 统计男生的数量并输出。
    System.out.println("男生数量--->" + list.stream().filter(Student -> Student.getGender() == '男').count());
    System.out.println("===================");
    //6.使用 Stream 找出年龄最大的学生,并打印其信息。
    Optional<Student> optional = list.stream().max((s1, s2) -> s1.getAge() - s2.getAge());
    System.out.println(optional.get());
    System.out.println("===================");
    //7.使用 Collectors.groupingBy() 按性别对学生进行分组,输出一个 Map<Character, List<Student>>。
    Map<Character, List<Student>> groupedByGender = list.stream()
            .collect(Collectors.groupingBy(Student::getGender));
    // 打印结果
    System.out.println("按性别分组结果:");
    groupedByGender.forEach((gender, students) -> {
      System.out.println("性别:" + gender);
      students.forEach(System.out::println);
    });
    System.out.println("===================");
    //8.使用 anyMatch() 判断是否存在年龄大于 20 的学生,输出 true 或 false。
    System.out.println(list.stream().anyMatch(student -> student.getAge() > 20));
    //9.使用 filter() 筛选出姓名为 "Jack" 的学生,并打印结果。
    System.out.println("===================");
    list.stream().filter(student -> student.getName().equals("Jack")).forEach(System.out::println);
    //10.使用 map() 将所有学生的姓名转为大写格式并打印。
    System.out.println("===================");
    list.stream().map(student -> student.getName().toUpperCase()).forEach(System.out::println);
    //11.先按姓名升序排序,如果姓名相同则按年龄升序排序,并打印结果。
    System.out.println("===================");
    list.stream().sorted(Comparator.comparing(Student::getName)
                    .thenComparing(Student::getAge))
            .forEach(System.out::println);
  }
}

class Student {
  private String name;
  private int age;
  private char gender;

  public Student() {
  }

  public Student(String name, int age, char gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }

  /**
   * 获取
   *
   * @return name
   */
  public String getName() {
    return name;
  }

  /**
   * 设置
   *
   * @param name
   */
  public void setName(String name) {
    this.name = name;
  }

  /**
   * 获取
   *
   * @return age
   */
  public int getAge() {
    return age;
  }

  /**
   * 设置
   *
   * @param age
   */
  public void setAge(int age) {
    this.age = age;
  }

  /**
   * 获取
   *
   * @return gender
   */
  public char getGender() {
    return gender;
  }

  /**
   * 设置
   *
   * @param gender
   */
  public void setGender(char gender) {
    this.gender = gender;
  }

  public String toString() {
    return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
  }
}

5.Optional 

Optional 是 Java 8 引入的一个容器类,用于表示一个值可能存在或可能不存在。它可以避免空指针异常(NullPointerException),使代码更加健壮和清晰。Optional 可以包含非空值,也可以为空。

创建 Optional 对象

使用 Optional.of() 方法创建一个包含非空值的 Optional 对象。如果传入的值为 null,会抛出 NullPointerException

Optional<String> optional = Optional.of("Hello");

使用 Optional.ofNullable() 方法创建一个可能为空的 Optional 对象。如果传入的值为 null,返回一个空的 Optional。

Optional<String> optional = Optional.ofNullable(null);

使用 Optional.empty() 方法创建一个空的 Optional 对象。

Optional<String> optional = Optional.empty();

检查 Optional 是否有值

使用 isPresent() 方法检查 Optional 是否包含非空值。

if (optional.isPresent()) {
    System.out.println("Value is present: " + optional.get());
}

使用 ifPresent() 方法在值存在时执行操作。

optional.ifPresent(value -> System.out.println("Value is present: " + value));

获取 Optional 的值

使用 get() 方法获取 Optional 中的值。如果 Optional 为空,会抛出 NoSuchElementException

String value = optional.get();

使用 orElse() 方法获取 Optional 中的值,如果 Optional 为空,返回默认值。

String value = optional.orElse("Default Value");

使用 orElseGet() 方法获取 Optional 中的值,如果 Optional 为空,通过 Supplier 提供默认值。

String value = optional.orElseGet(() -> "Default Value");

使用 orElseThrow() 方法获取 Optional 中的值,如果 Optional 为空,抛出指定的异常。

String value = optional.orElseThrow(() -> new RuntimeException("Value not present"));

链式操作

使用 map() 方法对 Optional 中的值进行转换。

Optional<String> upperCase = optional.map(String::toUpperCase);

使用 flatMap() 方法对 Optional 中的值进行转换,返回另一个 Optional。

Optional<String> flatMapped = optional.flatMap(value -> Optional.of(value.toUpperCase()));

使用 filter() 方法对 Optional 中的值进行过滤。

Optional<String> filtered = optional.filter(value -> value.length() > 5);

注意事项

Optional 主要用于方法的返回类型,避免返回 null。不推荐用于类的字段或方法的参数。

Optional 的设计目的是为了明确表示可能为空的值,而不是替代所有的 null 检查。滥用 Optional 可能会导致代码复杂化。

7.新增日期时间API

package com.whm.unit13;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class DateAndTimeAPITest {
  public static void main(String[] args) {
    // 1. 获取当前日期(不带时间)
    LocalDate localDate = LocalDate.now();
    System.out.println("当前日期:" + localDate);

    // 2. 获取当前时间(不带日期)
    LocalTime localTime = LocalTime.now();
    System.out.println("当前时间:" + localTime);

    // 3. 获取当前日期和时间(不带时区)
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println("当前日期时间:" + localDateTime);

    // 4. 使用 DateTimeFormatter 格式化日期时间
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String format = localDateTime.format(dateTimeFormatter);
    System.out.println("格式化日期时间:" + format);

    // 5. 解析字符串为日期时间
    String str = "2025-07-20 07:47:26";
    LocalDateTime parse = LocalDateTime.parse(str, dateTimeFormatter);
    System.out.println("解析后的日期时间:" + parse);
    // 6. 计算日期加减
    LocalDateTime localDateTime1 = localDateTime.plusDays(1);
    System.out.println("明天日期:" + localDateTime1.format(dateTimeFormatter));
    LocalDateTime localDateTime2 = localDateTime.plusMonths(1);
    System.out.println("下个月是:" + localDateTime2.format(dateTimeFormatter));

    // 7. 计算两个日期之间的天数差
    LocalDate date1 = LocalDate.of(2025, 1, 1);
    LocalDate date2 = LocalDate.of(2026, 1, 1);
    long daysBetween = ChronoUnit.DAYS.between(date1, date2);
    System.out.println("两个日期之间的天数差: " + daysBetween);

    // 8. 获取当前时间戳(Instant)
    Instant now = Instant.now();
    System.out.println("当前时间戳:" + now);

    // 9. 带时区的时间
    ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
    System.out.println("带时区的时间: " + zonedDateTime);
  }
}

8.接口优化

默认方法(Default Methods)

默认方法允许在接口中提供方法的默认实现,子类可以直接使用或重写。语法格式为:

public interface MyInterface {
    default void defaultMethod() {
        System.out.println("默认方法实现");
    }
}
 

关键点:

  • 使用 default 关键字修饰。
  • 子类可直接调用或通过 @Override 重写。
  • 解决接口升级时兼容性问题:新增默认方法不会强制现有实现类修改代码。

多继承冲突:若一个类实现多个接口且存在同名默认方法,需显式指定或重写。例如:

@Override
public void defaultMethod() {
    InterfaceA.super.defaultMethod(); // 显式选择接口A的实现
}
 

静态方法(Static Methods)

接口中可定义静态方法,直接通过接口名调用,不属于实现类。语法格式为:

public interface MyInterface {
    static void staticMethod() {
        System.out.println("静态方法调用");
    }
}
 

关键点:

  • 使用 static 关键字修饰。
  • 仅能通过接口名调用(如 MyInterface.staticMethod()),无法通过实现类实例调用。
  • 提供工具方法:例如 Collections.sort() 在 JDK 8 后可通过接口静态方法实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值