首页技术栈归档照片墙音乐日记随想收藏夹友链留言关于

Java 8 新特性

写作时间:2026-07-07

Lambda 表达式

匿名内部类

@Test
public void test01(){
    //匿名内部类
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1,o2);
        }

        @Override
        public boolean equals(Object obj) {
            return false;
        }
    };
    //调用
    TreeSet<Integer> set = new TreeSet<>(comparator);
}

Lambda表达式

@Test
public void test02(){
    // Lambda 表达式
    Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);

    TreeSet<Integer> set = new TreeSet<>(comparator);
}

基础语法

  • 操作符:->
  • 左侧:参数列表
  • 右侧:执行代码块 / Lambda 体

语法格式:

  • 无参数,无返回值:() -> sout
public class Test02 {
	int num = 10; //jdk 1.7以前 必须final修饰

    @Test
    public void test01(){
        //匿名内部类
        new Runnable() {
            @Override
            public void run() {
                //在局部类中引用同级局部变量
                //只读
                System.out.println("Hello World" + num);
            }
        };
    }

    @Test
    public void test02(){
        //语法
     	Runnable runnable = () -> {
         	System.out.println("Hello Lambda");
     	};
    }
}

  • 有一个参数,无返回值
@Test
public void test03(){
    Consumer<String> consumer = (a) -> System.out.println(a);
    consumer.accept("我觉得还行!");
}
  • 有一个参数,无返回值 (小括号可以省略不写)
@Test
public void test03(){
    Consumer<String> consumer = a -> System.out.println(a);
    consumer.accept("我觉得还行!");
}

  • 有两个及以上的参数,有返回值,并且 Lambda 体中有多条语句
@Test
public void test04(){
    Comparator<Integer> comparator = (a, b) -> {
        System.out.println("比较接口");
        return Integer.compare(a, b);
    };
}

  • 有两个及以上的参数,有返回值,并且 Lambda 体中只有1条语句 (大括号 与 return 都可以省略不写)
@Test
public void test04(){
    Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
}

函数式接口

调用 Collections.sort() 方法,通过定制排序 比较两个 Employee (先按照年龄比,年龄相同按照姓名比),使用 Lambda 表达式作为参数传递

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    private Integer id;
    private String name;
    private Integer age;
    private Double salary;
}

  • 定义 List 传入数据
List<Employee> emps = Arrays.asList(
    new Employee(101, "Z3", 19, 9999.99),
    new Employee(102, "L4", 20, 7777.77),
    new Employee(103, "W5", 35, 6666.66),
    new Employee(104, "Tom", 44, 1111.11),
    new Employee(105, "Jerry", 60, 4444.44)
);

测试类

@Test
public void test01(){
    Collections.sort(emps, (e1, e2) -> {
        if (e1.getAge() == e2.getAge()){
            return e1.getName().compareTo(e2.getName());
        } else {
            return Integer.compare(e1.getAge(), e2.getAge());
        }
    });

    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

消费型接口

@Test
public void test01(){
    //Consumer
    Consumer<Integer> consumer = (x) -> System.out.println("消费型接口" + x);
    //test
    consumer.accept(100);
}

提供型接口

@Test
public void test02(){
    List<Integer> list = new ArrayList<>();
    List<Integer> integers = Arrays.asList(1,2,3); 
    list.addAll(integers);
    //Supplier<T>
    Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
    list.add(supplier.get());
    System.out.println(supplier);
    for (Integer integer : list) {
        System.out.println(integer);
    }
}

函数式接口

@Test
public void test03(){
    //Function<T, R>
    String oldStr = "abc123456xyz";
    Function<String, String> function = (s) -> s.substring(1, s.length()-1);
    //test
    System.out.println(function.apply(oldStr));
}

断言型接口

@Test
public void test04(){
    //Predicate<T>
    Integer age = 35;
    Predicate<Integer> predicate = (i) -> i >= 35;
    if (predicate.test(age)){
        System.out.println("你该退休了");
    } else {
        System.out.println("我觉得还OK啦");
    }
}

方法引入

对象::实例方法

//简单的输出
@Test
public void test01(){
    PrintStream ps = System.out;
    Consumer<String> con1 = (s) -> ps.println(s);
    con1.accept("aaa");

    Consumer<String> con2 = ps::println;
    con2.accept("bbb");
}

**注意:**Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致

类::静态方法

//com1.compare(1, 2) 就相当于第一个参数减去第二个 是否是正数或者负数
@Test
public void test02(){
    Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
    System.out.println(com1.compare(1, 2));

    Comparator<Integer> com2 = Integer::compare;
    System.out.println(com2.compare(2, 1));
}

类::实例方法

//判断两个值是否相等    
@Test
    public void test03(){
        BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
        System.out.println(bp1.test("a","b"));

        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp2.test("c","c"));
    }

**条件:**Lambda 参数列表中的第一个参数是方法的调用者,第二个参数是方法的参数时,才能使用 ClassName :: Method

Stream流

什么是 Stream?

Stream的操作步骤:

创建流的方法

/**
* 创建流
*/
@Test
public void test01(){
    /**
    * 集合流
    *  - Collection.stream() 穿行流
    *  - Collection.parallelStream() 并行流
    */
    List<String> list = new ArrayList<>();
    Stream<String> stream1 = list.stream();

    //数组流
    //Arrays.stream(array)
    String[] strings = new String[10];
    Stream<String> stream2 = Arrays.stream(strings);

    //Stream 静态方法
    //Stream.of(...)
    Stream<Integer> stream3 = Stream.of(1, 2, 3);

    //无限流
    //迭代
    Stream<Integer> stream4 = Stream.iterate(0, (i) -> ++i+i++);
    stream4.forEach(System.out::println);

    //生成
    Stream.generate(() -> Math.random())
        .limit(5)
        .forEach(System.out::println);
}

中间操作

  • filter:接收 Lambda ,从流中排除某些元素
  • limit:截断流,使其元素不超过给定数量
  • skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
  • distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素

实体类

package com.yuan;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    private Integer id;
    private String name;
    private Integer age;
    private Double salary;
}

代码

List<Employee> emps = Arrays.asList(
    new Employee(101, "Z3", 19, 9999.99),
    new Employee(102, "L4", 20, 7777.77),
    new Employee(103, "W5", 35, 6666.66),
    new Employee(104, "Tom", 44, 1111.11),
    new Employee(105, "Jerry", 60, 4444.44)
);

@Test
public void test01(){
    emps.stream()
        .filter((x) -> x.getAge() > 35)//过滤掉大于35的
        .limit(3) //短路?达到满足不再内部迭代
        .distinct()//去除重复数据
        .skip(1)//跳过第一个集合元素
        .forEach(System.out::println);//输出集合数据

}

映射

  • map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流

map:

@Test
public void test02(){
    List<String> list = Arrays.asList("a", "b", "c");
    list.stream()
        .map((str) -> str.toUpperCase())  //str.toUpperCase()将数据转成大写,也有其他方法选择
        .forEach(System.out::println);
}

flatMap:


public class aaa {

    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for (char c : str.toCharArray()) {
            list.add(c);
        }

        return list.stream();
    }

    @Test
    public void test03(){
        List<String> list = Arrays.asList("a", "b", "c");
        list.stream()
                .flatMap(aaa::filterCharacter)
                .forEach(System.out::println);
    }

}

排序

  • sorted():自然排序
  • sorted(Comparator c):定制排序

自然排序

@Test
public void test04(){
    List<Integer> list = Arrays.asList(1,2,3,4,5);
    list.stream()
        .sorted() //升序排列
        .forEach(System.out::println);
}

定制排序

List<Employee> emps = Arrays.asList(
    new Employee(101, "Z3", 19, 9999.99),
    new Employee(102, "L4", 20, 7777.77),
    new Employee(103, "W5", 35, 6666.66),
    new Employee(104, "Tom", 44, 1111.11),
    new Employee(105, "Jerry", 60, 4444.44)
);

@Test
public void test05(){
    emps.stream()
        .sorted((e1, e2) -> { //compara()
            if (e1.getAge().equals(e2.getAge())){
                return e1.getName().compareTo(e2.getName());
            } else {
                return e1.getAge().compareTo(e2.getAge());
            }
        })
        .forEach(System.out::println);
}

多条件排序

class Student {
    String name;
    int score;

    // 构造函数和其他方法省略
}

从高到底排序

List<Student> students = new ArrayList<>();
// 填充学生列表

students.sort(new Comparator<Student>() {
    @Override
    public int compare(Student s1, Student s2) {
        return s2.score - s1.score; // 按分数降序排序
    }
});

使用thenComparing实现多条件排序

students.sort(Comparator.comparing((Student s) -> s.score)
        .reversed()
        .thenComparing(s -> s.name)); //首先按分数降序排序,然后按照姓名升序排序。使用,thenComparing

当使用方法引用的方式方法引用的方式来创建 Comparator 时,可以使用类名 :: 属性名的语法。

students.sort(Comparator.comparing(Student::getScore).reversed()
        .thenComparing(Student::getName));

使用thenComparing排序Map

List<Map<String, String>> compareResults = new ArrayList<>();

compareResults = compareResults.stream()
        .sorted(Comparator.comparing((Map<String, String> i) -> i.get("bgsj"))
                .thenComparing(i -> i.get("bgnr"))
                .thenComparing(i -> i.get("bgzd"))
                .thenComparing(i -> i.get("bgzj")))
        .collect(Collectors.toList());

  • 首先,我们使用Comparator.comparing方法按照"bgsj"字段进行排序。
  • 如果"bgsj"相同,我们使用thenComparing方法按照"bgnr"字段进行排序。
  • 如果"bgnr"也相同,继续使用thenComparing方法按照"bgzd"字段进行排序。
  • 最后,如果"bgzd"也相同,将按照"bgzj"字段进行排序。

查找 / 匹配

终止操作:

  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中最大值
  • min:返回流中最小值
public enum Status {
    FREE, BUSY, VOCATION;
}

@Test
public void test01(){
    List<Status> list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);

    boolean flag1 = list.stream()
        .allMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag1);

    boolean flag2 = list.stream()
        .anyMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag2);

    boolean flag3 = list.stream()
        .noneMatch((s) -> s.equals(Status.BUSY));
    System.out.println(flag3);

    // 避免空指针异常
    Optional<Status> op1 = list.stream()
        .findFirst();
    // 如果Optional为空 找一个替代的对象
    Status s1 = op1.orElse(Status.BUSY);
    System.out.println(s1);

    Optional<Status> op2 = list.stream()
        .findAny();
    System.out.println(op2);

    long count = list.stream()
        .count();
    System.out.println(count);
}

归约 / 收集

  • 归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
  • 收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法

reduce:

/**
* Java:
*  - reduce:需提供默认值(初始值)
* Kotlin:
*  - fold:不需要默认值(初始值)
*  - reduce:需提供默认值(初始值)
*/
@Test
public void test01(){
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);   //将集合的数据全部加起来
    Integer integer = list.stream()
        .reduce(0, (x, y) -> x + y);  
    System.out.println(integer);
}


collect:

实体类

package com.yuan;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    private Integer id;
    private String name;
    private Integer age;
    private Double salary;
}

代码

List<Employee> emps = Arrays.asList(
    new Employee(101, "Z3", 19, 9999.99),
    new Employee(102, "L4", 20, 7777.77),
    new Employee(103, "W5", 35, 6666.66),
    new Employee(104, "Tom", 44, 1111.11),
    new Employee(105, "Jerry", 60, 4444.44)
);

@Test
public void test02(){
    //放入List
    List<String> list = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toList()); 
    list.forEach(System.out::println);

	//放入Set
    Set<String> set = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toSet());
    set.forEach(System.out::println);

    //放入LinkedHashSet
    LinkedHashSet<String> linkedHashSet = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(LinkedHashSet::new));
    linkedHashSet.forEach(System.out::println);


   //转Map集合
    emps.stream().collect(Collectors.toMap(Employee::getId,emps->emps)).forEach((id,item)-> System.out.println(id+"->"+item));



}



@Test
public void test03(){
    //总数
    Long count = emps.stream()
        .collect(Collectors.counting());
    System.out.println(count);

    //平均值
    Double avg = emps.stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println(avg);

    //总和
    Double sum = emps.stream()
        .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println(sum);

    //最大值
    Optional<Employee> max = emps.stream()
        .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    System.out.println(max.get());

    //最小值
    Optional<Double> min = emps.stream()
        .map(Employee::getSalary)
        .collect(Collectors.minBy(Double::compare));
    System.out.println(min.get());
}

@Test
public void test04(){
    //分组
    Map<Integer, List<Employee>> map = emps.stream()
        .collect(Collectors.groupingBy(Employee::getId));
    System.out.println(map);

    //多级分组
    Map<Integer, Map<String, List<Employee>>> mapMap = emps.stream()
        .collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
            if (e.getAge() > 35) {
                return "开除";
            } else {
                return "继续加班";
            }
        })));
    System.out.println(mapMap);

    //分区
    Map<Boolean, List<Employee>> listMap = emps.stream()
        .collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321));
    System.out.println(listMap);
}

@Test
public void test05(){
    //总结
    DoubleSummaryStatistics dss = emps.stream()
        .collect(Collectors.summarizingDouble(Employee::getSalary));
    System.out.println(dss.getMax());
    System.out.println(dss.getMin());
    System.out.println(dss.getSum());
    System.out.println(dss.getCount());
    System.out.println(dss.getAverage());

    //连接
    String str = emps.stream()
        .map(Employee::getName)
        .collect(Collectors.joining("-")); //可传入分隔符
    System.out.println(str);
}

使用map 和 reduce 数一数流中有多少个 Employee

List<Employee> emps = Arrays.asList(
    new Employee(101, "Z3", 19, 9999.99),
    new Employee(102, "L4", 20, 7777.77),
    new Employee(103, "W5", 35, 6666.66),
    new Employee(104, "Tom", 44, 1111.11),
    new Employee(105, "Jerry", 60, 4444.44)
);

@Test
public void test02(){
    Optional<Integer> result = emps.stream()
        .map((e) -> 1)
        .reduce(Integer::sum);
    System.out.println(result.get());

avatar

yuanyourdomain

写代码,做研究,记录生活。

RECOMMENDED

MyBatis 动态 SQL

2026-07-08

Nginx 基础入门

2026-07-08

Maven 多模块与私服

2026-07-08