zoukankan      html  css  js  c++  java
  • Java8新特性系列二:Lambda和函数式接口

    1. 函数式接口

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

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

     3. 函数式接口通常@FunctionalInterface注解标识

    /**
     * 这是一个自定义的函数式接口
     * @FunctionalInterface 用于检测一个接口是否为函数式接口
     */
    @FunctionalInterface
    public interface MyInterface {
        boolean method();
    }

    2. Lambda表达式

     Lambda可以作为参数和返回值,此外匿名内部类没有class文件的概念,内存中即少加载一个文件
    public class Lamda {
    
        public static void main(String[] args) {
            List<Apple> inventory = Arrays.asList(new Apple(100, "red"), new Apple(150, "green"));
            List<Apple> result = filter(inventory, apple -> apple.weight > 100);
            result.forEach(System.out::println);
        }
    
        public static List<Apple> filter(List<Apple> inventory, MyInterface iface) {
            List<Apple> result = new ArrayList<>();
            for (Apple apple : inventory) {
                if (iface.method(apple)) {
                    result.add(apple);
                }
            }
            return result;
        }
    
        /**
         * 这是一个自定义的函数式接口
         *
         * @FunctionalInterface 用于检测一个接口是否为函数式接口
         */
        @FunctionalInterface
        public interface MyInterface {
            boolean method(Apple apple);
        }
    }

    2.1 Lambda延迟加载

     提升性能:有些代码在执行后,结果不一定被使用,从而造成性能浪费;例如:日志案例

    public class LoggerLambda {
    
        public static void main(String[] args) {
            String msgA = "Hello ";
            String msgB = "world ";
            String msgC = "Java ";
            //只有level==1时,才会执行buildMessage(),返回拼接的字符串,不浪费性能
            log(1, () -> msgA + msgB + msgC);
        }
    
        private static void log(int level, MessageBuilder builder) {
            if (level == 1) {
                System.out.println(builder.buildMessage());
            }
        }
    
        @FunctionalInterface
        public interface MessageBuilder {
            String buildMessage(); //空参数,返回值为String
        }
    }
    

    2.2 Lambda作用域

    在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量

    3. 常用的API函数式接口

     JDK 1.8 之前

    • java.lang.Runnable
    • java.util.concurrent.Callable
    • java.security.PrivilegedAction
    • java.util.Comparator
    • java.io.FileFilter
    • java.nio.file.PathMatcher
    • java.lang.reflect.InvocationHandler
    • java.beans.PropertyChangeListener
    • java.awt.event.ActionListener
    • javax.swing.event.ChangeListener

     JDK 1.8 之后 

    3.1 Predicate

     java.util.function.Predicate<T>接口是判断型接口,主要用于判断是否满足某个谓词,API包含5个方法:

     1. boolean test(T t)

     2. default Predicate<T> and(Predicate<? super T> other)

     3. dafault Predicate<T> or(Predicate<? super T> other)

     4. default Predicate<T> negate()

     5. static <T> Predicate<T> isEqual(Object targetRef)

    public class ApplePredicate {
    
        public static void main(String[] args) {
            List<Apple> inventory = Arrays.asList(
                    new Apple(100, "red", 1, "CN"),
                    new Apple(150, "green", 2, "UK"),
                    new Apple(200, "red", 3, "USA"));
    
            filter(inventory, apple -> apple.getNumber() > 2);
    
            filter2(inventory, apple -> apple.getNumber() > 1, apple -> apple.getWeight() > 100);
    
            Predicate<Apple> predicate = apple -> apple.getWeight() > 200;
    
            //谓词取反,negate代表苹果重量小于等于200的谓词
            Predicate<Apple> negate = predicate.negate();
            filter(inventory, negate);
    
            Apple apple = new Apple(100, "red", 1, "CN");
    
            //筛选出和apple相同苹果的谓词
            Predicate<Apple> predicate1 = Predicate.isEqual(apple);
            filter(inventory, predicate1).forEach(apple1 -> System.out.println(apple));
        }
    
        /**
         * Predicate test() method demo
         * 筛选出满足谓词的苹果
         *
         * @param inventory
         * @param predicate
         * @return
         */
        public static List<Apple> filter(List<Apple> inventory, Predicate<Apple> predicate) {
            List<Apple> result = new ArrayList<>();
            for (Apple apple : inventory) {
                if (predicate.test(apple)) {
                    result.add(apple);
                }
            }
    
            return result;
        }
    
        /**
         * Predicate and() method demo
         * 筛选出同时满足两个谓词条件的苹果
         *
         * @param inventory
         * @param predicate1
         * @param predicate2
         * @return
         */
        public static List<Apple> filter2(List<Apple> inventory, Predicate<Apple> predicate1, Predicate<Apple> predicate2) {
            List<Apple> result = new ArrayList<>();
            for (Apple apple : inventory) {
                Predicate<Apple> and = predicate1.and(predicate2);
                if (and.test(apple)) {
                    result.add(apple);
                }
            }
            return result;
        }
    
        /**
         * Predicate or() method demo
         * 筛选出满足两个谓词条件中任意一个条件的苹果
         *
         * @param inventory
         * @param predicate1
         * @param predicate2
         * @return
         */
        public static List<Apple> filter3(List<Apple> inventory, Predicate<Apple> predicate1, Predicate<Apple> predicate2) {
            List<Apple> result = new ArrayList<>();
            for (Apple apple : inventory) {
                Predicate<Apple> or = predicate1.or(predicate2);
                if (or.test(apple)) {
                    result.add(apple);
                }
            }
            return result;
        }
    
        @Data
        @AllArgsConstructor
        @EqualsAndHashCode
        public static class Apple {
            private int weight; //苹果重量
            private String color;//苹果颜色
            private int number;//苹果编号
            private String city;//苹果产地
    
        }
    }

    3.2 Consumer接口

     java.util.function.Consumer<T>接口是消费型接口,与Suppier接口相反;包含两个方法:

     1. void accept(T t)

     2. default Consumer<T> andThen(Consumer<? super T> after)

    public class ConsumerDemo {
    
        public static void main(String[] args) {
            List<Apple> inventory = Arrays.asList(
                    new Apple(100, "red", 1, "CN"),
                    new Apple(150, "green", 2, "UK"),
                    new Apple(200, "red", 3, "USA"));
    
            //定义一个消费List<Apple>的接口,打印苹果的编号
            Consumer<List<Apple>> consumer = apples -> {
                for (Apple apple : apples) {
                    System.out.print(apple.getNumber());
                }
            };
    
            //定义一个消费List<Apple>的接口,打印苹果的产地
            Consumer<List<Apple>> consumer2 = apples -> {
                for (Apple apple : apples) {
                    System.out.print(apple.getCity());
                }
            };
            consumer.accept(inventory);
            consumer.andThen(consumer2).accept(inventory);
        }
    
        @Data
        @AllArgsConstructor
        @EqualsAndHashCode
        public static class Apple {
            private int weight; //苹果重量
            private String color;//苹果颜色
            private int number;//苹果编号
            private String city;//苹果产地
    
        }
    }

    3.3 Function接口

     java.util.function.Function<T,R>接口用来转化数据类型T, R表示接口输入、输出的数据类型,相当于y=f(x),包含4个方法:

     1. R apply(T t)

     2. default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)

     3. default <V> Function<V, R> compose(Function<? super V, ? extends T> before)

     4. static <T> Function<T, T> identity()

    public class ConsumerDemo {
    
        public static void main(String[] args) {
            Function<Integer, Integer> function1 = i -> i + 1;
            Function<Integer, Integer> function2 = i -> i * i;
            //6 5+1=6
            System.out.println(function1.apply(5));
            //25 5*5=25
            System.out.println(function2.apply(5));
            //36 (5+1)*(5+1)=36
            System.out.println(function1.andThen(function2).apply(5));
            //26 (5*5)+1=26
            System.out.println(function1.compose(function2).apply(5));
        }
    
    }

    3.4 BiFunction接口

     java.util.function.Function<T,U,R> 接口用来转化数据类型T, U表示接口输入的数据类型、R表示输出的数据类型,相当于z=f(x,y);包含2个方法:

     1. R apply(T t, U u);

     2. default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after)

    3.5 Supplier接口

     java.util.function.Supplier<T>接口是供给型接口,包含一个无参的方法:

     T get()

     这就意味这Lambda表达式需要对外提供一个符合泛型类型的对象数据;个人理解:Supplier类似于工厂,提供了一个规范,用户DIY具体实现;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import java.util.function.Supplier;
    
    public class SuppilerDemo {
    
        public static void main(String[] args) {
    
            int[] arr = {6, 4, 3, 8, 9};
            System.out.println(getMax(() -> {
                int max = arr[0];
                for (int i : arr) {
                    max = max > i ? max : i;
                }
                return max;
            }));
        }
    
        /**
         * 提供返回最大值的功能 
         * @param supplier
         * @return
         */
        public static int getMax(Supplier<Integer> supplier) {
            return supplier.get();
        }
    
        @Data
        @AllArgsConstructor
        @EqualsAndHashCode
        public static class Apple {
            private int weight; //苹果重量
            private String color;//苹果颜色
            private int number;//苹果编号
            private String city;//苹果产地
    
        }
    }
  • 相关阅读:
    python进阶(1)--多进程与多线程概念
    mysql数据库(5)--表的相关操作
    mysql数据库(4)--表删除操作
    备注
    mysql数据库(3)--mysql的执行顺序
    mysql数据库(2)--窗口函数之序号函数
    Spring MVC 返回中文乱码
    郁闷,郁闷啊
    Struts2 下载文件
    js文件加载
  • 原文地址:https://www.cnblogs.com/oxygenG/p/13357943.html
Copyright © 2011-2022 走看看