jdk8新特性-Lambda表达式-方法引用

Lambda表达式

只要会匿名内部类, 一定会Lambda表达式(简化匿名内部类)

Runnable使用Lambda

public class LamadaTest {

    public static void main(String[] args) {

        // 强调: 怎么做-------------------------------------
        // 面向对象不好的地方:
        // 1. 不得不创建一个类, 实现Runnable接口
        // 2. 如果不想创建类, 不得不使用匿名内部类
        // 3. 使用匿名内部类, 不得不重写run方法
        // 4. 重写run方法, 不得不写出跟父类一样的, 返回值类型, 方法名,参数列表
        // 5. 最后才要写出run方法里面的代码
        new Thread(new Runnable() {

            @Override
            public void run() {

                System.out.println("使用匿名内部类创建一个线程1");
            }
        }).start();
        
        // 开启一条新线程  ->  开启线程, 让run方法中的代码执行起来

        // 目标: 线程  run里面的代码跑起来

        // 我们要做的就剩  指定run方法里面的代码
        
        // 函数式编程: 强调: 做什么
        new Thread(() -> System.out.println("开启了一条新线程2")).start();
        new Thread(() -> System.out.println("开启了一条新线程3")).start();
        new Thread(() -> System.out.println("开启了一条新线程4")).start();
        new Thread(() -> System.out.println("开启了一条新线程5")).start();
        new Thread(() -> System.out.println("开启了一条新线程6")).start();
        new Thread(() -> System.out.println("开启了一条新线程7")).start();

    }
}

Lambda表达式的格式和前提

格式

() -> {}
() : 参数列表(一些参数)
-> : 一个箭头 将小括号中的参数, 给大括号中使用
{} : 一段代码
    
    
Lambda表达式其实是对匿名内部类的改写
() : 匿名内部类中重写方法的参数列表
{} : 匿名内部类中重写方法的方法体

前提

  1. 使用的接口, 一定是一个函数式接口(有且只有一个抽象方法的接口)@FunctionalInterface
  2. 函数式接口要作为方法的参数(主要使用场景)或者返回

1. 无参无返回的Lambda

package com.free._03lambda.demo02;

@FunctionalInterface
public interface MyInter2 {
    void fun();
}
package com.free._03lambda.demo02;

/*

    无参无返回的Lambda

        模拟: 函数式接口
             函数式接口作为参数的方法

        关注: 方法的调用
 */
public class Demo02 {
    public static void main(String[] args) {
        // 方法的调用
        print(new MyInter2() {
            @Override
            public void fun() {
                System.out.println("无参无返回的匿名内部类");
            }
        });


        // Lambda
        print(() -> System.out.println("无参无返回的Lambda"));

    }

    // 函数式接口作为参数的方法
    public static void print(MyInter2 lambda) { // 传入的一定是实现类对象
        lambda.fun();
    }

}

2. 无参有返回的Lambda

package com.free._03lambda.demo03;

public interface MyInter3 {
    String fun();
}
package com.free._03lambda.demo03;
/*
    无参有返回
 */
public class Demo03 {
    public static void main(String[] args) {
        // 方法的调用
        print(new MyInter3() {
            @Override
            public String fun() {
                return "匿名内部类";
            }
        });

        // lambda
        print(() -> "Lambda");
    }


    public static void print(MyInter3 lambda) {
        String s = lambda.fun();
        System.out.println(s);
    }
}

3. 有参无返回的Lambda

package com.free._03lambda.demo04;

public interface MyInter4 {
    void fun(int i);
}
package com.free._03lambda.demo04;
/*
    有参无返回
 */
public class Demo04 {
    public static void main(String[] args) {

        print(new MyInter4() {
            @Override
            public void fun(int i) {
                System.out.println("匿名内部类不" + i);
            }
        });

        // lambda
        print(i -> System.out.println("Lambda" + i));

    }

    public static void print(MyInter4 lambda) {
        lambda.fun(666);
    }
}

4. 有参有返回的Lambda

package com.free._03lambda.demo05;

public interface MyInter5 {
    int stringToInt(String s);
}
package com.free._03lambda.demo05;
/*
    有参有返回
 */
public class Demo05 {
    public static void main(String[] args) {
        // 匿名内部类
        print(new MyInter5() {
            @Override
            public int stringToInt(String s) {
                // Integer.parseInt(字符串) -> 将数字格式的字符串转换成int类型的数字
                return Integer.parseInt(s);
            }
        });

        // lambda
        print(s -> Integer.parseInt(s));

        // Method Reference
        // print(Integer::parseInt);

    }

    public static void print(MyInter5 lambda) {
        int i = lambda.stringToInt("100");
        System.out.println(i);
    }
}

Comparator使用Lambda

package com.free._03lambda.demo06;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Demo06 {
    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<>();
        // 添加元素
        Collections.addAll(list, 5, 4, 2, 6, 8, 7, 9, 3, 1);

        // 降叙排序
        /*Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });*/

        // lambda
        Collections.sort(list, (o1, o2) -> o2 - o1);

        System.out.println(list);


        // 只有引用数据类型的数组, 才能使用比较器排序
        Integer[] arr = {2, 4, 3, 5, 1};
        /*Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });*/

        Arrays.sort(arr, (o1, o2) -> o2 - o1 );



        System.out.println(Arrays.toString(arr));

    }
}

Lambda的简化格式

原则: 可推导, 可省略.

  1. 小括号中, 数据类型可以省略
  2. 小括号中, 如果只有一个参数, 小括号可以省略
  3. 大括号中, 如果只有一条语句, 可以省略大括号和分号
  4. 大括号中, 如果只有一条语句且是返回语句,可省略return

alt+enter 自动转换成lamada表达式设置
在这里插入图片描述

方法引用

方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。

方法引用的前提

方法引用: 觉得Lambda表达式冗余, 对Lambda继续简化

不是所有的Lambda表达式都可以改成方法引用,

  • Lambda表达式大括号中的内容, 是已经定义好的.

    stream.forEach(s -> System.out.println(s));
    
  • 方法引用的格式

    ::  => 引用运算符
        
    A :: B功能 => 使用A中的B功能
    
  • 方法引用的使用

    stream.forEach(s -> System.out.println(s)); 
    // println() 功能已经定义好了
    // 使用 System.out 中的 println() 功能
    stream.forEach(System.out::println);
    
方法引用基本使用

方法引用使用一对冒号::

下面,我们在 Car 类中定义了 4 个方法作为例子来区分 Java 中 4 种不同方法的引用

public static class Car {
    public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }              

    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }

    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }

    public void repair() {   
        System.out.println( "Repaired " + this.toString() );
    }
}

第一种方法引用的类型是构造器引用,语法是Class::new,或者更一般的形式:Class::new。注意:这个构造器没有参数。

final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );

第二种方法引用的类型是静态方法引用,语法是Class::static_method。注意:这个方法接受一个Car类型的参数。

cars.forEach( Car::collide );

第三种方法引用的类型是某个类的成员方法的引用,语法是Class::method,注意,这个方法没有定义入参:

cars.forEach( Car::repair );

第四种方法引用的类型是某个实例对象的成员方法的引用,语法是instance::method。注意:这个方法接受一个Car类型的参数:

final Car police = Car.create( Car::new );
cars.forEach( police::follow );
基于静态方法引用的代码演示
public static void main(String args[]) {
    List names = new ArrayList();

    names.add("大明");
    names.add("二明");
    names.add("小明");

    names.forEach(System.out::println);
}

上面的代码,我们将 System.out::println 方法作为静态方法来引用。

测试结果为:

大明
二明
小明
  • 案例一(对象引用成员方法)
public interface Printable {
    void print(String s);
}
public class MyRef {

    /**
     * 定义一个方法, 用来将字符串转换成大写, 然后打印
     */
    public void printUpper(String s) {
        System.out.println(s.toUpperCase());
    }
}

public class Demo01 {
    public static void main(String[] args) {
        // 匿名内部类
        /*printString(new Printable() {
            @Override
            public void print(String s) {
                System.out.println(s);
            }
        });*/

        // 前提条件: 功能一定是已经定义好的
        // lambda表达式
        // printString(s -> System.out.println(s));

        // 方法引用
        // printString(System.out::println); // 做打印


        // 将字符串转换成大写并打印(这里有println与toUpperCase两个方法,分别定义,不算定义好的)
        printString(s -> System.out.println(s.toUpperCase()));

        // MyRef 类中 printUpper
        // A :: B =>   MyRef::printUpper
        MyRef ref = new MyRef();
        printString(ref::printUpper);

    }

    public static void printString(Printable p) {
        p.print("HelloWorld");
    }
}
  • 案例二(类名引用静态方法)
public interface CalcAble {
    int getAbs(int a);
}
public class Demo02 {
    public static void main(String[] args) {

        // 匿名内部类
        /*printAbs(new CalcAble() {
            @Override
            public int getAbs(int a) {
                return Math.abs(a);
            }
        });*/

        // lambda
        printAbs(a -> Math.abs(a));

        // MethodReference
        // 使用了 Math类中的 静态方法 abs功能
        // A :: B  => 使用A中的B功能


        // 方法引用 -> lambda -> 匿名内部类 -> 接口的实现类对象
        // fun(Math::abs); // 错误的方式

        printAbs(Math::abs);
    }


    public static void fun(int a) {
        System.out.println(a);
    }


    public static void printAbs(CalcAble c) {
        System.out.println(c.getAbs(-10));
    }
}

  • 案例三(this和super的引用)
public interface GreetAble {
    void greet();
}

public class Fu {
    public void sayHello() {
        System.out.println("大家好, 我是渣渣辉.");
    }
}

public class Zi extends Fu {
    @Override
    public void sayHello() {
        System.out.println("大家好, 我是小小春.");
    }

    public void fun(GreetAble g) {
        g.greet();
    }

    public void method() {

        // 匿名内部类 => 生成 Zi$1.class
        fun(new GreetAble() {
            @Override
            public void greet() {
                Zi.super.sayHello();
            }
        });


        // lambda没有字节码文件生成
        // 打印Fu类的SayHello
        fun(() -> super.sayHello());
        // 打印Zi类的SayHello
        // fun(() -> this.sayHello());

        // A中的B功能  super中的sayHello
        fun(super::sayHello);
        fun(this::sayHello);
    }
}
public class Test {
    public static void main(String[] args) {

        Zi zi = new Zi();
        zi.method();

    }
}
  • 案例四(类中构造方法的引用)
public interface PersonBuilder {
    Person buildPerson(String name, int age);
}

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Demo04 {
    public static void main(String[] args) {

        printPerson((name, age) -> new Person(name, age));

        // 使用了Person中的 new功能
        printPerson(Person::new);


    }

    public static void printPerson(PersonBuilder p) {
        System.out.println(p.buildPerson("高圆圆", 18));
    }
}
  • 案例五(数组创建功能的引用)
public interface ArrayBuilder {
    int[] buildArray(int len);
}
public class Demo05 {
    public static void main(String[] args) {

        printArray(len -> new int[len]);

        // 使用数组的new功能
        printArray(int[]::new);

    }

    public static void printArray(ArrayBuilder a) {
        int[] arr = a.buildArray(3);
        arr[0] = 10;
        arr[1] = 20;
        arr[2] = 30;
        System.out.println(Arrays.toString(arr));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值