美文网首页
Java8 函数式接口 学习笔记

Java8 函数式接口 学习笔记

作者: R7_Perfect | 来源:发表于2020-11-26 15:22 被阅读0次

    一, 函数式编程

    java中的函数式编程体现就是Lambda和方法引用:

    Lambda

    // 1.1使用匿名内部类  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            System.out.println("Hello world !");  
        }  
    }).start();  
      
    // 1.2使用 lambda 获得Runnable接口对象  
    new Thread(() -> System.out.println("Hello world !")).start();
    

    Lambda除了简洁之外,还具有延迟执行特点

    延迟执行

    有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。

    public class Demo01Logger {
        private static void log(int level, String msg) {
            if (level == 1) {
                System.out.println(msg);
            }
         }
        public static void main(String[] args) {
            String msgA = "Hello";
            String msgB = "World";
            String msgC = "Java";
            log(2, msgA + msgB + msgC);//级别1 不一定能够满足 但是 字符串连接操作还是执行了 那么字符串的拼接操作就白做了,存在性能浪费
        }
    }
    

    Lambda的更优写法:

    @FunctionalInterface
    public interface MessageBuilder {
        String buildMessage();
    }
    public class Demo02LoggerLambda {
        private static void log(int level, MessageBuilder builder) {
            if (level == 1) {
                System.out.println(builder.buildMessage());// 实际上利用内部类 延迟的原理,代码不相关 无需进入到启动代理执行
            }
        }
        public static void main(String[] args) {
            String msgA = "Hello";
            String msgB = "World";
            String msgC = "Java";
           log(2,()->{
                    System.out.println("lambda 是否执行了");
                    return msgA + msgB + msgC;
            });
        }
    }
    

    方法引用

    方法引用,不是方法调用!
    方法引用是 lambda 表达式的语法糖,任何用方法引用的地方都可由lambda表达式替换

    list.forEach(value -> System.out.println(value));
    

    可替换为

    list.forEach(System.out::println);
    
    类别 使用形式
    静态方法引用 类名 :: 静态方法名
    实例方法引用 对象名(引用名) :: 实例方法名
    类方法引用 类名 :: 实例方法名
    构造方法引用 类名 :: new

    二, 函数式接口

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

    • 你可以通过 Lambda 表达式或方法引用来创建该接口的对象。
    • 可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检测它是否是一个函数式接口

    @FunctionalInterface

    在JDK 8中引入了FunctionalInterface接口,其源代码定义如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface FunctionalInterface {}
    

    加上@FunctionalInterface标注,则会触发JavaCompiler的检查。对于符合函数接口的接口,加不加都无关紧要,但是加上则会提供一层编译检查的保障。如果不符合,则会报错。

    需要注意的是:接口中只能存在一个抽象方法
    格式:

    修饰符 interface 接口名称{
        public abstract 返回值 方法名称(参数列表)
        // 其他方式 
    }
    // public abstract 可以不写 编译器自动加上
    修饰符 interface 接口名称{
           返回值 方法名称(参数列表)
        // 其他方式 
    }
    

    调用举例:

    @FunctionalInterface // 标明为函数式接口
    public abstract MyFunctionInterface{
        void method(); //抽象方法
    }
    
    public class TestFunctional {
        // 定义一个含有函数式接口的方法
        public static void doSomething(MyFunctionInterface functionalInterface) {
            functionalInterface.method();//调用自定义函数式接口的方法
        }
        public static void main(String[] args) {
            //调用函数式接口的方法
            MyFunctionInterface functionalInterface = () -> System.out.println("hello!")
            doSomething(functionalInterface );
        }
    }
    

    常用函数式接口

    接口 参数 返回值 说明
    Supplier<T> T 供给型;无参,返回一个指定泛型的对象
    Consumer<T> T 消费型;传入一个指定泛型的参数,无返回值
    Predicate<T> T Boolean 断言型;判断函数,返回判断结果true/false
    Function<T,R> T R 方法型;输入一个参数,得到一个结果

    Supplier

    无参有返回值

    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
    

    使用:

    public class TestSupplier {
        public static void main(String[] args) {
             // 产生的数据作为 sout 作为输出
            Supplier<String> supply = ()->"产生数据"
            System.out.println(supply.get());//输出“产生数据”
        }
    }
    

    Consumer

    有参无返回值

    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
        ...
    }
    

    使用:

    public class TestComsumer {
        public static void main(String[] args) {
            Consumer<String> consumer = s->System.out.println(s)
            consumer.accept("hello");//输出“hello”
        }
    }
    

    Predicate

    对入参数据进行判断,并返回boolean

    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T t);
        ...
    }
    

    使用:

    public class UsePredicate {
        public static void main(String[] args) {
            Predicate<Integer> predicate = (x)-> x==10;
            System.out.println(predicate.test(10));//输出true
        }
    }
    

    Function

    将入参T转为返回值R

    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    }
    

    使用:

    // 将数字转换为String类型
    private static void numberToString() {
        String apply = function.apply(12);
        System.out.println("转换结果:"+apply);
    }
    public static void main(String[] args) {
            Function<Number, String> function = (s)->String.valueOf(s)
        System.out.println("转换结果:"+function.apply(12));//输出“12”
    }
    

    三, Functional Java

    Functional Java是一个第三方库,是一个在Java语言中实现函数型编程范式的类库。

    标准的Java 8 也引入了很多函数型编程范式的元素,比如Stream,lambda以及函数型接口。但在功能上Java 8 远不如Functional Java丰富,使用上也受到一定的限制。

    Functional 项目地址:https://github.com/functionaljava/functionaljava

    引入

    //主包
    compile "org.functionaljava:functionaljava:4.8"
    //可以不引入
    compile "org.functionaljava:functionaljava-java8:4.8"
    compile "org.functionaljava:functionaljava-quickcheck:4.8"
    compile "org.functionaljava:functionaljava-java-core:4.8"
    

    F0, F, F2, …, F8

    对应Fuction<T,R>类, F<A, B>输入类型为A,返回值类型为B
    F0没有入参,F有1个入参,…,F8有8个入参
    返回值类型都只有一个,最后那个类型参数代表返回值类型。

    F<Integer, Integer> twice = n -> n * 2;
    F2<Integer, Integer, Integer> f = (a, b) -> a + b;
    F3<Integer, Integer, Integer, Integer> g = (a, b, c) -> a + b + c;
    

    Effect0, Effect1, Effect2, …, Effect8

    没有返回值的函数接口类型, 对应Consumer
    Effect0没有入参,Effect1有1个入参,…,Effect8有8个入参

    Effect1<Integer> abc = n -> System.out.println(n);
    
    FJ 接口 FJ 方法 Java 8 接口 Java 8 方法
    Effect2<T, U> f BiConsumer<T, U> accept
    F2<T, U, R> f BiFunction<T, U, R> apply
    F2<T, T, T> f BinaryOperator<T> apply
    F2<T, U, Boolean> f BiPredicate<T, U> test
    F0<Boolean> f BooleanSupplier getAsBoolean

    其他特性不多做介绍了。。。

    相关文章

      网友评论

          本文标题:Java8 函数式接口 学习笔记

          本文链接:https://www.haomeiwen.com/subject/vuwgiktx.html