一、替代匿名内部类

package day03;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类--线程操作..");
            }
        });
        thread.start();

        //使用Lambda表示代替匿名内部类
        Thread thread1 = new Thread(() -> System.out.println("lambda表达式-线程操作"));
        thread1.start();
    }
}

二、函数式接口

函数式接口有且只有一个抽象方法,只要接口中出现多个抽象方法那么就不能称之为函数式接口。Java8提供了一个新的注解@FunctionalInterface,如果接口被这个注解标注,就说明这个接口是函数式接口,如果有多于一个的抽象方法,在编译的时候就会报错。但是这个注解不是必需的,只要接口符合函数式接口的定义,那么这个接口就是函数式接口。

简单的说一个接口有且只有一个抽象方法,这个接口就是函数式接口。

Java基础知识回顾15-lambda学习_lambda

原则上讲,函数式接口中有且只能有一个抽象方法,但是也是可以定义默认方法和静态方法的,这两种方法的定义不会影响函数式接口的定义。

package day05;

/**
 * @author qx
 * @date 2023/11/3
 * @des
 */
@FunctionalInterface
public interface MyInterface {
    void method1();

    static void show() {
        System.out.println("静态方法");
    }

    default void test() {
        System.out.println("默认方法");
    }
}

测试:

package day05;

/**
 * @author qx
 * @date 2023/11/3
 * @des
 */
public class Test {
    public static void main(String[] args) {
        MyInterface myInterface = new MyInterface() {
            @Override
            public void method1() {
                System.out.println("抽象方法");
            }
        };
        //抽象方法
        myInterface.method1();
        // 默认方法
        myInterface.test();
        // 静态方法
        MyInterface.show();
    }
}

输出:

抽象方法
默认方法
静态方法

三、四大内置函数式接口

Java内置了四个函数式接口方便我们使用Lambda表达式。

1.Consumer消费型接口

void accept(T t);

接收一个参数,并且没有返回值。

package day03;

import java.util.function.Consumer;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        Consumer<String> consumer = s -> System.out.println("我是" + s);
        consumer.accept("admin");
    }
}

输出:

我是admin

2.Supplier供给型接口

T get();

没有参数,但是有返回值

package day03;

import java.util.UUID;
import java.util.function.Supplier;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        // 没有参数 有返回值
        Supplier<String> supplier = () -> UUID.randomUUID().toString();
        System.out.println(supplier.get());
    }
}

输出:

81fb7499-fdf2-49f2-ba7f-51bd4d8ea635

3.Function函数式接口

R apply(T t);

接收一个参数,并返回一个结果的接口方法

package day03;

import java.util.UUID;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        // 有参数 有返回值
        Function<String, String> function = s -> s.toUpperCase();
        System.out.println(function.apply("hello"));
    }
}

输出:

HELLO

4.Predicate断言式接口

boolean test(T t);

有一个参数,返回值是boolean类型的接口方法

package day03;

import java.util.function.Predicate;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        Predicate<String> predicate = s -> s.length() > 2;
        System.out.println(predicate.test("hello"));
    }
}

输出:

true

四、方法引用和构造器引用

实现抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!

方法引用:使用操作符“::”将类与方法分隔开来。

有下面几种调用方式:

对象::实例方法名
类::静态方法名
类::实例方法名
package day03;


import java.util.Comparator;

/**
 * @author qx
 * @date 2023/10/27
 * @des Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        // 比较两个数据的大小
        Comparator<Integer> comparator = (o1, o2) -> o1.compareTo(o2);
        // 返回1
        System.out.println(comparator.compare(4, 3));
    }
}

如果实现抽象方法的参数列表和返回值类型和方法引用的参数和返回值类型相同。我们可以使用方法引用,上面的操作也可以使用方法引用来实现。

Java基础知识回顾15-lambda学习_lambda_02

package day06;

import java.util.Comparator;

/**
 * @author qx
 * @date 2023/10/29
 * @desc
 */
public class LambdaTest {
    public static void main(String[] args) {
        Comparator<Integer> comparator = Integer::compareTo;
        System.out.println(comparator.compare(4, 3));
    }
}

五、Lambda表达式的一些常见用法

1.使用lambda表达式对集合进行迭代

package day06;

import java.util.Arrays;
import java.util.List;

/**
 * @author qx
 * @date 2023/10/29
 * @desc Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa", "bb", "cc");
        // before java8
        for (String s : list) {
            System.out.println(s);
        }
        // lambda
        list.forEach(s -> System.out.println("lambda:" + s));
    }
}

2.用lambda表达式实现map

map方法的作用是将一个对象变换为另一个对象。

package day06;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author qx
 * @date 2023/10/29
 * @desc Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa", "bb", "cc");
        // 将字母转换为大写返回
        list.stream().map(s -> s.toUpperCase()).forEach(s -> System.out.println(s));
    }
}

输出:

AA
BB
CC

3.用lambda表达式实现reduce

reduce方法的作用是将所有值合并为一个值。

package day06;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author qx
 * @date 2023/10/29
 * @desc Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Integer result = list.stream().reduce((sum, x) -> sum + x).get();
        // 输出 6
        System.out.println(result);
    }
}

4.filter操作

filter方法的作用是过滤的操作

package day06;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author qx
 * @date 2023/10/29
 * @desc Lambda测试
 */
public class LambdaTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        // 过滤返回大于2的数据
        List<Integer> integerList = list.stream().filter(s -> s > 2).collect(Collectors.toList());
        // 输出[3]
        System.out.println(integerList);
    }
}