JavaSE-函数式接口、lambda表达式

函数式接口

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 lambda 表达式。

Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。

    // 定义一个函数型接口,特点传入参数,调用一个方法
    @FunctionalInterface
    interface MathOperation {
        int operation(int a, int b);
    }

    @FunctionalInterface
    interface StrOperation {
        void operation(String str);
    }

四大函数型接口

  • Function

  • Supplier

  • Consumer

  • Predicate

Runnable(线程相关)

Function

(类型转换型函数接口)特点:有一个参数输入,有一个输出

import java.util.function.Function;

public class TestFunction {
    public static void main(String[] args) {
        // 传入T 类型数据,返回R 类型数据
        /**
         * 1. 使用匿名内部类方法实现函数型接口
         * 2. 使用lambda 表达式实现函数型接口
         */
        // 匿名内部类
        Function<Integer, String> function = new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) {
                return integer.toString();
            }
        };
        // lambda
        Function<Integer, String> function2 = (Integer integer) -> {
            return integer.toString();
        };
        System.out.println(function2.apply(1));
    }
}

Predicate

(断定型函数接口)特点:输入一个类型的参数,返回一个boolean值

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class TestPredicate {
    public static void main(String[] args) {
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if (integer > 10)
                    return true;
                else
                    return false;
            }
        };
        Predicate<Integer> predicate2 = (i) -> i > 10;
        System.out.println(predicate2.test(20));

        List<Integer> integers = Arrays.asList(1, 5, 8, 9, 2, 10, 8);
        // 断定型接口实现类
        Predicate<Integer> p1 = (i) -> true;  // 所有
        Predicate<Integer> p2 = (i) -> i % 2 == 0;  // 偶数
        Predicate<Integer> p3 = (i) -> i % 2 == 1;  // 奇数
        Predicate<Integer> p4 = (i) -> i > 7;  // 大于7
        System.out.println("输出结果:");
        for (Integer integer : integers) {
            if (p4.test(integer)) {
                System.out.print(integer + " ");
            }
        }
    }
}

Consumer

(消费型函数接口)特点:传入一个参数没有返回值

import java.util.function.Consumer;

public class TestConsumer {
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        Consumer<String> consumer2 = (str)->{
            System.out.println(str);
        };
        consumer2.accept("ok");
    }
}

Supplier

(供给型函数接口)特点:没输入参数有返回值

import java.util.function.Supplier;

public class TestSupplier {
    public static void main(String[] args) {
        Supplier<String> supplier = new Supplier<String>() {
            @Override
            public String get() {
                return "null";
            }
        };
        Supplier<String> supplier2 = () -> {
            return "null";
        };
        System.out.println(supplier2.get());
    }
}

lambda 表达式

实现接口

public class Lambda {
    public static void main(String[] args) {
        Lambda lambda = new Lambda();
        /**
         * 定义函数接口的实现类:
         * 1. 传统:定义一个实现类,重写接口类中的方法,new 实现类调用方法。
         * 2. 使用lambda 表达式 (parameters) ->expression 或 (parameters) ->{ statements; } 来表示实现类
         */
        MathOperation plus = (int a, int b) -> {
            return a + b;
        };  // 此处实际上就是重写了MathOperation接口类中的operation方法
        System.out.println(lambda.operate(10, 5, plus));

        StrOperation str_plus = (String str) -> {
            System.out.println("hello +" + str);
        };  // 此处实际上就是重写了StrOperation接口类中的operation方法
        str_plus.operation("world");
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }

    // 定义一个函数型接口,特点调用函数返回数据
    interface MathOperation {
        int operation(int a, int b);
    }

    interface StrOperation {
        void operation(String str);
    }
}

作用域问题、使用说明

  1. lambda 表达式只能引用标记了 final 的外层局部变量(默认使用final修饰),也就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

  2. Lambda 表达式当中被引用的变量的值不可以被更改。

  3. 在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

  4. 和局部变量不同的是,Lambda内部对于成员变量以及静态变量是即可读又可写。

  5. Lambda 表达式中使用 this 会引用创建该 Lambda 表达式的方法的 this 参数。

public class Lambda {
    final static String string = "java";
    public static void main(String[] args) {
        final String STR = "javascript";
        Lambda lambda = new Lambda();
        /**
         * 定义函数接口的实现类:
         * 1. 传统:定义一个实现类,重写接口类中的方法,new 实现类调用方法。
         * 2. 使用lambda 表达式 (parameters) ->expression 或 (parameters) ->{ statements; } 来表示实现类
         */
        MathOperation plus = (int a, int b) -> {
            return a + b;
        };  // 此处实际上就是重写了MathOperation接口类中的operation方法
        System.out.println(lambda.operate(10, 5, plus));

        StrOperation str_plus = (String str) -> {
            System.out.println("hello +" + str);
        };  // 此处实际上就是重写了StrOperation接口类中的operation方法
        str_plus.operation("world");
        str_plus.operation(string);
        str_plus.operation(STR);
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }

    // 定义一个函数型接口,特点调用函数返回数据
    interface MathOperation {
        int operation(int a, int b);
    }

    interface StrOperation {
        void operation(String str);
    }
}

玩法

有参数无返回值函数式接口8种写法

@FunctionalInterface
public interface Fn{
	void print(String str, String str1);
} 
  1. 普通写法
Fn fn = new Fn(){
	@Override
	public void print(String str, String str1){
		System.out.println(str+str1)
	}
}
  1. lambda 表达式
Fn fn = (String str, String str1)->{
	System.out.println(str+str1)
}
  1. lambda 表达式,参数类型可以省略
Fn fn = (str, str1)->{
	System.out.println(str+str1)
}
  1. lambda 表达式,执行内容为一行时可以省略{}
Fn fn = (str, str1)->System.out.println(str+str1)
  1. lambda 表达式引用静态方法
public class Demo{
	static Fn fn = (str, str1)->Demo2.print(str, str1);
	public static void main(String[] args){}
	public static class Demo2{
		public static void print(String str, String str1){
			System.out.println(str+str1)
		}
	}
}
  1. lambda 表达式使用::引用静态方法,隐藏参数;如果静态方法参数和函数式接口的方法参数一致,可以使用下面代码优化。
public class Demo{
	static Fn fn = (str, str1)->Demo2.print(str, str1);
	public static void main(String[] args){}
	public static class Demo2{
		public static void print(String str, String str1){
			System.out.println(str+str1)
		}
	}
}

lambda 表达式优化

Fn fn = Demo2::print;
  1. lambda 表达式引用实例方法
public class Demo{
	static Fn fn = (str, str1)->new Demo2().print(str, str1);
	public static void main(String[] args){}
	public static class Demo2{
		public void print(String str, String str1){
			System.out.println(str+str1)
		}
	}
}
  1. lambda 表达式使用::引用实例方法,隐藏参数;如果实例方法参数和函数式接口的方法参数一致,可以使用下面代码优化。
public class Demo{
	static Fn fn = (str, str1)->new Demo2().print(str, str1);
	public static void main(String[] args){}
	public static class Demo2{
		public void print(String str, String str1){
			System.out.println(str+str1)
		}
	}
}

lambda 表达式优化

Fn fn = new Demo2()::print;

无参数有返回值函数式接口8种写法

class User {
    private String name;
    private int age;
    private String sex;

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

    public User() {
    }

    public static class StaticMethod {
        public static User user() {
            return new User("chen", 20, "男");
        }
    }

    public static class InstanceMethod {
        public User user() {
            return new User("li", 21, "男");
        }
    }
}

@FunctionalInterface
interface Fn {
    User create_user();
}

public class Demo {
    // 方式1:原始方法
    Fn fn1 = new Fn() {
        @Override
        public User create_user() {
            return new User("chen", 20, "男");
        }
    };
    // 方式2:lambda 表达式
    Fn fn2 = () -> {
        return new User("chen", 20, "男");
    };
    // 方式3:lambda 表达式单行省略{},同时return 也可以省略
    Fn fn3 = () -> new User("chen", 20, "男");
    // 方式4:调用静态方法
    Fn fn4 = () -> {
        return User.StaticMethod.user();
    };
    // 方式5:调用静态方法,单行省略{},同时return 也可以省略
    Fn fn5 = () -> User.StaticMethod.user();
    // 方式6:使用:: 优化
    Fn fn6 = User.StaticMethod::user;
    // 方式7:调用实例方法
    Fn fn7 = () -> {
        return new User.InstanceMethod().user();
    };
    // 方式8:调用实例方法,单行省略{},同时return 也可以省略
    Fn fn8 = () -> new User.InstanceMethod().user();
    // 方式9:使用:: 优化
    Fn fn9 = new User.InstanceMethod()::user;
    // 方式10:调用空构造器,::优化
    Fn fn10 = User::new;
    /**
     * 实际上是一下代码的优化
     * Fn fn10 = new Fn(){
     *  @Override
     *  public User create_user(){
     *     return new User();
     *  }
     * }
     */
}

有参数有返回值的函数值接口

class User {
    private String name;
    private int age;
    private String sex;

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

    public User() {
    }

    public static class StaticMethod {
        public static User user(String name, int age, String sex) {
            return new User(name, age, sex);
        }
    }

    public static class InstanceMethod {
        public User user(String name, int age, String sex) {
            return new User(name, age, sex);
        }
    }
}

@FunctionalInterface
interface Fn {
    User create_user(String name, int age, String sex);
}

public class Demo {
    // 方式1:原始方法
    Fn fn1 = new Fn() {
        @Override
        public User create_user(String name, int age, String sex) {
            return new User(name, age, sex);
        }
    };
    // 方式2:lambda 表达式
    Fn fn2 = (String name, int age, String sex) -> {
        return new User(name, age, sex);
    };
    // 方式3:lambda 表达式单行省略{},同时return 也可以省略,参数类型省略
    Fn fn3 = (name, age, sex) -> new User(name, age, sex);
    // 方式4:调用静态方法
    Fn fn4 = (String name, int age, String sex) -> {
        return User.StaticMethod.user(name, age, sex);
    };
    // 方式5:调用静态方法,单行省略{},同时return 也可以省略,参数类型省略
    Fn fn5 = (name, age, sex) -> User.StaticMethod.user(name, age, sex);
    // 方式6:使用:: 优化
    Fn fn6 = User.StaticMethod::user;
    // 方式7:调用实例方法
    Fn fn7 = (String name, int age, String sex) -> {
        return new User.InstanceMethod().user(name, age, sex);
    };
    // 方式8:调用实例方法,单行省略{},同时return 也可以省略,参数类型省略
    Fn fn8 = (name, age, sex) -> new User.InstanceMethod().user(name, age, sex);
    // 方式9:使用:: 优化
    Fn fn9 = new User.InstanceMethod()::user;
    // 方式10:调用空构造器,::优化
    Fn fn10 = User::new;
    /**
     * 实际上是一下代码的优化
     * Fn fn10 = new Fn(){
     *  @Override
     *  public User create_user(String name, int age, String sex){
     *     return new User(name, age, sex);
     *  }
     * }
     */
}

特殊事例

public class Demo {
    public static void main(String[] args) {
        List<Integer> arrs = Arrays.asList(1, 5, 6, 9);
        arrs.stream().forEach(System.out::println);
    }
}

原因就是forEach中的参数是一个消费型的函数式接口,详细查看【函数是接口】-【Consumer】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mJSZ1AOU-1653558578190)(imgclip.png "imgclip.png")]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOPIVDUh-1653558578196)(imgclip_1.png "imgclip_1.png")]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值