

注意: 函数式接口:接口中只有一个抽象方法。
(参数1,参数2): 抽象方法的参数
->: 分隔符
{}:表示抽象方法的实现
- public class Test01 {
- public static void main(String[] args) {
-
- //该构造方法需要传递一个线程任务对象。Runnable类型
- My task=new My();
- Thread t1=new Thread(task);
- t1.start();
-
-
- //匿名内部类
- Runnable task02=new Runnable() {
- @Override
- public void run() {
- System.out.println("这时匿名内部类方式的任务对象");
- }
- };
- Thread t2=new Thread(task02);
- t2.start();
- }
- }
- class My implements Runnable{
-
- @Override
- public void run() {
- System.out.println("自定义任务接口类");
- }
- }
分析:
Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心
为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错
而实际上,似乎只有方法体才是关键所在。
可以使用lambda表示完成上面的要求
- //lambda表达式
- Runnable task03 = ()-> {
- System.out.println("这是使用Lambda表达式完成的");
- };
-
- Thread t3=new Thread(task03);
- t3.start();
前提:必须是函数式接口。
简化匿名内部类的使用,语法更加简单。
- public class Test {
- public static void main(String[] args) {
-
- //匿名内部对象
- People people1 = new People() {
- @Override
- public void eat() {
- System.out.println("匿名内部对象");
- }
- };
- fun(people1);
-
- //lambda表达式
- People people2 = () -> {
- System.out.println("lambda表达式");
- };
- fun(people2);
- }
-
- public static void fun(People p){
- p.eat();
- }
- }
-
- //函数式接口
- interface People{
- public void eat();
- }
举例演示 java.util.Comparator 接口的使用场景代码,其中的抽象方法定义为:
public abstract int compare(T o1, T o2);
当需要对一个对象集合进行排序时, Collections.sort 方法需要一个 Comparator 接口实例来指定排序的规则。
- public class Test {
- public static void main(String[] args) {
- List
list = new ArrayList<>(); - list.add(new People("张三",18,178));
- list.add(new People("李四",19,177));
- list.add(new People("王五",20,176));
- list.add(new People("赵六",21,175));
-
- //对集合中的元素进行排序 按照年龄从大到小。
- Comparator
comparator = (People o1, People o2) -> { - return o2.getAge()- o1.getAge();
- };
- Collections.sort(list,comparator);
- for (People p: list) {
- System.out.println(p);
- }
- }
- }
-
- class People{
- private String name;
- private int age;
- private double height;
-
- @Override
- public String toString() {
- return "People{" +
- "name='" + name + '\'' +
- ", age=" + age +
- ", height=" + height +
- '}';
- }
-
- public People(String name, int age, double height) {
- this.name = name;
- this.age = age;
- this.height = height;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public double getHeight() {
- return height;
- }
-
- public void setHeight(double height) {
- this.height = height;
- }
- }


内置函数接口的由来
- public class Test {
- public static void main(String[] args) {
- People p = arr -> {
- int sum = 0;
- for (int n: arr) {
- sum += n;
- }
- System.out.println("数组的和为:"+sum);
- };
- fun(p);
-
- }
-
- public static void fun(People people){
- int[] arr = {1,2,3,4,5,6,7};
- people.getSum(arr);
- }
- }
-
- /**
- * 标识某个接口是函数式接口 只能有一个 public 接口
- */
-
- @FunctionalInterface
- interface People{
- public abstract void getSum(int[] arr);
- }
分析:
我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽 象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。
常见的函数式接口:

有参数,无返回值。
- public class Test01 {
- public static void main(String[] args) {
- Consumer
consumer = t -> { - System.out.println("花了"+t+"元");
- };
-
- fun01(consumer,2000);
- }
-
- public static void fun01(Consumer
consumer,double money) { - consumer.accept(money);
- }
- }
T:表示返回结果的泛型
无参,想有返回结果的函数式接口时 T.get();
- public class Test02 {
- public static void main(String[] args) {
- fun(() -> new Random().nextInt(10));
- }
-
- public static void fun(Supplier
supplier) { - Integer i = supplier.get();
- System.out.println("内容为:"+i);
- }
- }
T: 参数类型的泛型
R: 函数返回结果的泛型
有参,有返回 值时。
- public class Test03 {
- public static void main(String[] args) {
-
- //将字符串小写转大写
- fun((t) -> {
- return t.toUpperCase();
- },"hello world");
-
- //求字符串的长度;
- length((l) -> {
- return l.length();
- },"hello world");
-
- }
-
- public static void fun(Function
function,String msg) { - String f = function.apply(msg);
- System.out.println("结果为:"+f);
- }
-
- public static void length(Function
function,String msg) { - Integer i = function.apply(msg);
- System.out.println("长度为:"+i);
- }
- }
T: 参数的泛型
当传入一个参数时,需要对该参数进行判断时,则需要这种函数。
- public class Test04 {
- //判断名字的长度是否大于 3
- public static void main(String[] args) {
- fun((t) ->{
- return t.length()>3?true:false;
- },"sssss");
- }
-
- public static void fun(Predicate
predicate,String name) { - boolean b = predicate.test(name);
- System.out.println("结果为:"+b);
- }
- }
lambda表达式有时会导致冗余
如果在Lambda表达式中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用。

方法引用的分类

静态方法引用类无需实例化,直接用类名去调用。
- public class Test01 {
- public static void main(String[] args) {
- Consumer
c = Test01::sum; - fun(c);
-
- }
-
- public static void fun(Consumer
consumer) { - Integer[] arr={1,2,3,4,5};
- consumer.accept(arr);
- }
-
- public static void sum(Integer[] arr){
- int sum=0;
- for (int a:arr){
- sum+=a;
- }
- System.out.println("数组的和为:"+sum);
- }
- }
实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。
- public class Test {
- public static void main(String[] args) {
- People people = new People("张三",18);
- Supplier
supplier = () -> { - return people.getName();
- };
-
- fun(supplier);
- }
-
- public static void fun(Supplier
supplier) { - String s = supplier.get();
- System.out.println("结果为:"+s);
- }
- }
-
- class People{
- private String name;
- private Integer age;
-
- @Override
- public String toString() {
- return "People{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
-
- public People(String name, Integer age) {
- this.name = name;
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Integer getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
- }