精华内容
下载资源
问答
  • ​ JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。 二、对接口的要求 ​ 虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda ...

    lambda表达式

    一、Lambda简介

           Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更简洁的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
           JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

    二、对接口的要求

           虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,但不是说接口中只能有一个方法。

    三、lambda的基础语法

           语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 。
           如果只有一个参数时()可以省略,方法体只有返回值或只有一行代码时{}可以省略,例如消费型与供给型接口所示。

    四、四大函数型接口lambda表达式示例

    • 查看非lambda代码的四大函数型接口点击此处
    • 以下为lambda代码简化后的函数式接口示例
    public static void main(String[] args) {
            //消费型
            //consumertest(10000,(i) -> {System.out.println("消费了:"+i+"元");});
            consumertest(10000,i -> System.out.println("消费了:"+i+"元"));
    
            //供给型
            //System.out.println(getValue(() -> {
            //    return (int) (Math.random() * 10) + 1;
            //}));
            System.out.println(getValue(()->(int)(Math.random()*10)+1));
    
            //方法型
            System.out.println(functiontest("    哈哈    ", (str) -> str.trim()));
    
            //断言型
            List<Integer> list = new ArrayList<>();
            list.add(300);
            list.add(3);
            list.add(30);
            list.add(3333);
            list.add(30033);
            List<Integer> list1 = predicatetest(list,(li)->li>100);
            System.out.println(list1);
    
        }
    
        //消费型接口
        public static void consumertest(Integer i, Consumer<Integer> com){
            com.accept(i);
        }
    
        //供给型
        public static Integer getValue(Supplier<Integer> s){
            return s.get();
        }
    
        //方法型
        public static String functiontest(String str,Function<String,String> fun){
            return fun.apply(str);
        }
    
        //断言型
        public static List<Integer> predicatetest(List<Integer> list, Predicate<Integer> pre){
            List<Integer> newlist = new ArrayList<>();
            for (Integer i : list) {
                if (pre.test(i)){
                    newlist.add(i);
                }
            }
            return newlist;
        }
    

    五、lambda表达式的简化

    语法:
           方法引用: 简化Lambda–>Lambda表达式特殊的一种表现形式当lambda体中的实现是通过调用另外一个方法实现的时候,这个方法的参数列表返回值类型与抽象方法的参数列表与返回值一致的时候,就可以使用方法引用进行代替。
           方法引用分为:
                  引用::成员方法名
                  类名::静态方法名
                  类名::成员方法名

    public static void main(String[] args) {
            List<String> list = new ArrayList();
            list.add("123");
            list.add("12");
            list.add("1");
            //引用::成员方法名
            //遍历容器,打印里面的每一个数据
            list.forEach((i)->{
                System.out.println(i);
            });
            //Lambda体实现的功能就是打印参数-->可以通过方法引用来代替
            //通过PrintStream这个类型的对象调用println实现的,
        	//Lambda的抽象方法的参数作为println方法的参数,两者都没有返回值
            PrintStream ps = System.out;
            list.forEach(ps::println);
    
            list.forEach(System.out::println);
    
            //类名::静态方法名
            //比较2个double参数,返回最大的一个
            //2个参数 1个返回值  BiFunction
            //求最大值r
        	//lambda表达式
            //BiFunction<Double,Double,Double> fun = (d1, d2)->Math.max(d1,d2);
            //lambda的简化
        	BiFunction<Double,Double,Double> fun = Math::max;
            
        	System.out.println(fun.apply(100.0, 200.0));
    
            //比较两个int类型的参数
            Comparator<Integer> com = (i1, i2)->Integer.compare(i1,i2);
            //lambda简化
        	com = Integer::compare;
            System.out.println(com.compare(12, 13));
    
            //比较两个字符串是否相等
            BiPredicate<String,String> pre = (s1,s2)-> s1.equals(s2);
            //1)lambda是否是通过引用另外一个方法实现的->是  
        	//2)返回值匹配  
        	//3)抽象方法第一个参数s1作为内部引用另一个方法的对象存在,
        	//	如果抽象方法存在多个参数,第二个参数开始匹配内部引用的方法的参数列表-->方法引用
            pre = String::equals;
            System.out.println(pre.test("zhangsan", "zhangsan"));
    
        	//类名::成员方法名
            //获取bean中的属性
            Employee e = new Employee("ggh",12);
            Supplier<String> sup = ()->e.getName();
            sup = e::getName;   //对象固定
            System.out.println("名字为:"+sup.get());
    
            Function<Employee,String> func = (em)-> em.getName();
            func = Employee::getName;   //对象可变
            System.out.println(func.apply(e));
        }
    
    展开全文
  • 1. lambda表达式简介2. lambda表达式的三种编写方式(1) expression 单条语句执行(不用加{ })(2) statement 语句块(使用{ }包裹函数)(3) refernce 方法...函数式接口使用 简单示例 复杂示例 当参数只有一个的时候,.

    1. lambda表达式简介

    lambda表达式是java8开始的新特性,可以看作匿名函数

    功能则是将一个函数作为另一个函数的参数

    2. lambda表达式的三种编写方式

    (1) expression 单条语句执行(不用加{ })

    函数式接口使用

    简单示例
    在这里插入图片描述
    复杂示例
    在这里插入图片描述
    当参数只有一个的时候,可以省略空格
    在这里插入图片描述

    使用单语句时可以省略return

    在这里插入图片描述

    (2) statement 语句块(使用{ }包裹函数)

    使用示例

    在这里插入图片描述
    示例2
    在这里插入图片描述

    (3) refernce 方法引用

    简单示例
    在这里插入图片描述
    示例2
    在这里插入图片描述

    3. 函数式接口

    @FunctionalInterface注解

    @FunctionalInterface注解的功能就是约束一个接口只能有一个方法,参数没有限制,返回值可有可无

    当一个接口使用该注解,就代表该接口是一个函数式接口,也就可以使用lambda表达式简化使用

    四大函数式接口

    jdk1.8拥有的新功能

    • ① Function<T, R> : 函数型接口
    •   R apply(T t);
      
    • ② Consumer : 消费型接口
    •   void accept(T t);
      
    • ③ Supplier : 供给型接口
    •   T get();
      
    • ④ Predicate : 判断型接口
    •  boolean test(T t);
      

    (1) Function(函数型接口)

    有参数、有返回值
    在这里插入图片描述
    使用示例

    public static void main(String[] args) {
            //1. 普通方式
            Function<String,String> function1 = new Function<String, String>() {
                @Override
                public String apply(String s) {
                    return "hello,"+s;
                }
            };
    
            //2.lambda表达式方式
            Function<String,String> function2 = (str) -> {return "hello,"+str;};
    
            //3. 再简化
            Function<String,String> function3 = str -> "hello,"+str;
    
            //使用
            System.out.println(function1.apply("小明"));
            System.out.println(function2.apply("小红"));
            System.out.println(function3.apply("单身汪"));
        }
    

    在这里插入图片描述

    (2) Predicate (判断型接口)

    有参数,返回一个boolean值
    在这里插入图片描述
    使用示例

     public static void main(String[] args) {
            //1.普通方式
            Predicate<String> predicate1 = new Predicate<String>() {
                @Override
                public boolean test(String s) {
                    return s.equals("小明");
                }
            };
    
            //2.lambda方式
            Predicate<String> predicate2 = (s) -> {return s.equals("小明");};
    
            //3.再简化
            Predicate<String> predicate3 = s -> s.equals("小明");
    
            System.out.println(predicate1.test("小明")); //true
            System.out.println(predicate2.test("小红")); //false
            System.out.println(predicate3.test("小丑")); //false
        }
    

    (3) Consumer (消费型接口)

    有参数,无返回值
    在这里插入图片描述
    使用示例

    public static void main(String[] args) {
    
            //1.普通方式
            Consumer consumer1 = new Consumer() {
                @Override
                public void accept(Object name) {
                    System.out.println((String)name+"正在消费");
                }
            };
    
            //2.lambda表达式方式
            Consumer consumer2 = (name)->{
                System.out.println((String)name+"正在消费");
            };
    
            //3.简化
            Consumer consumer3 = name->  System.out.println((String)name+"正在消费");
    
            //4.再简化 右侧相当于是将一个方法作为函数式接口的实现
            Consumer<String> consumer4 = System.out::println;
    
            consumer1.accept("小明");
            consumer2.accept("小红");
            consumer3.accept("小丑");
            consumer4.accept("打工人正在消费");
        }
    

    在这里插入图片描述

    (4) Supplier (供给者接口)

    无参数,有返回值
    在这里插入图片描述
    使用示例

    public class TestSupplier {
        public static void main(String[] args) {
            //1.普通方式
            Supplier supplier1 = new Supplier() {
                @Override
                public Object get() {
                    return new Hambuger("小明");
                }
            };
    
            //2.lambda表达式方式
            Supplier supplier2 = ()->{return new Hambuger("小红");};
    
            //3.简化
            Supplier supplier3 = ()-> new Hambuger("小丑");
    
            Object hambuger1 = supplier1.get();
            Object hambuger2 = supplier2.get();
            Object hambuger3 = supplier3.get();
    
            System.out.println(hambuger1);
            System.out.println(hambuger2);
            System.out.println(hambuger3);
        }
    }
    //汉堡类
    class Hambuger{
        String name;
        Hambuger(String name){
           this.name = name+"做的汉堡";
        }
        @Override
        public String toString() {
            return name;
        }
    }
    

    在这里插入图片描述

    展开全文
  • Java8函数式接口Lambda表达式

    千次阅读 多人点赞 2019-04-07 17:14:10
    何为函数式接口?...函数式接口lambda表达式的联系:lambda是实现函数式接口一个快捷方式,可以作为函数式接口一个实例。常用Java8内置的函数式接口 Function、Predicate、Consumer 和 Supplier 介绍。

    摘要

    • 何为函数式接口?
    • 什么是lambda表达式,lambda表达式的本质;
    • 函数式接口与lambda表达式的联系:lambda是实现函数式接口的一个快捷方式,可以作为函数式接口的一个实例;
    • 常用Java8内置的函数式接口 Function、Predicate、Consumer 和 Supplier 介绍;

    一、函数式接口

    何为函数式接口?

    函数式接口也是 java interface 的一种,但还需要满足:

    1. 一个函数式接口只有一个抽象方法(SAM,single abstract method);
    2. Object 类中的 public abstract method 不会被视为单一的抽象方法;
    3. 函数式接口可以有默认方法和静态方法;
    4. 函数式接口可以用@FunctionalInterface 注解进行修饰。

    满足这些条件的 interface,就可以被视为函数式接口。例如,java8中的Comparator接口:

    @FunctionalInterface
    public interface Comparator<T> {
        /**
         * single abstract method
         * @since 1.8
         */
        int compare(T o1, T o2);
    
        /**
         * Object 类中的 public abstract method 
         * @since 1.8
         */
        boolean equals(Object obj);
    
        /**
         * 默认方法
         * @since 1.8
         */
        default Comparator<T> reversed() {
            return Collections.reverseOrder(this);
        }
    
    	......
        
    	/**
         * 静态方法
         * @since 1.8
         */
        public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
            return Collections.reverseOrder();
        }
    
    	......
    	
    

    函数式接口有什么用?

    一句话,函数式接口带给我们最大的好处就是:可以使用极简的lambda表达式实例化接口。为什么这么说呢?我们或多或少使用过一些只有一个抽象方法的接口,比如 Runnable, ActionListener, Comparator …。比如,我们要用Comparator实现排序算法,我们的处理方式通常无外乎两种:

    1. 规规矩矩的写一个实现Comparator接口的java类去封装排序逻辑。若业务需要多种排序方式,那就得写多个类提供多种实现,而这些实现往往只需使用一次。。。。
    2. 另外一种聪明些的做法无外乎就是在需要的地方搞个匿名内部类去扛了。比如:
    class Test { 
        public static void main(String args[]) { 
            List<Person> persons = new ArrayList<Person>();
            Collections.sort(persons, new Comparator<Person>(){
                @Override
                public int compare(Person o1, Person o2) {
                    return Integer.compare(o1.getAge(), o2.getAge());
                }
            });
        } 
    } 
    

    匿名内部类实现的代码量没有多到哪里去,结构也还算清晰。不过如今脚本语言横行无阻,无不以其简洁的语法为杀手锏,俘获程序员的欢心。jdk开发者们应该是意识到了这一点,我们从上面Comparator的实现就可以得到验证。该接口在jdk8的实现增加了FunctionalInterface注解,代表Comparator是一个函数式接口,使用者可放心的通过lambda表达式来实例化。那我们来看看使用lambda实例化所需编写的代码:

    Comparator<Person> comparator = (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge());
    

    就这么简单,->前面的()是Comparator接口中compare方法的参数列表,->后面则是run方法的方法体。

    @FunctionalInterface 使用场景

    我们知道,一个接口只要满足只有一个抽象方法的条件,即可以当成函数式接口使用,有没有@FunctionalInterface都无所谓。但是jdk定义了这个注解肯定是有原因的,对于开发者,该注解的使用一定要三思而后续行。

    如果使用了此注解,再往接口中新增抽象方法,编译器就会报错,编译不通过。换句话说,@FunctionalInterface就是一个承诺,承诺该接口世世代代都只会存在这一个抽象方法。因此,凡是使用了这个注解的接口,开发者可放心大胆的使用lambda来实例化。当然误用@FunctionalInterface带来的后果也是极其惨重的:如果哪天你把这个注解去掉,再加一个抽象方法,则所有使用lambda实例化该接口的客户端代码将全部编译错误。。。

    特别地,当某接口只有一个抽象方法,但没有增加@FunctionalInterface,则代表人家没有承诺该接口未来不增加抽象方法,所以建议不要用lambda来实例化,还是老老实实的用以前的方式比较稳妥。


    二、lambda表达式

    什么是lambda?

    lambda表达式是实现函数式接口的一个快捷方式。下面这段代码是最直观的体现:

    Runnable task = () -> System.out.println("i am coming...");
    

    =号的前面是变量的声明,后面是一个lambda表达式。我们直接将lambda表达式赋值为Runnable类型的task变量,就意味着:lambda表达式是实现函数式接口的一个快捷方式。理解这一点是至关重要的。

    lambda表达式语法

    lambda表达式语法可抽象表示为:

    (Type1 param1, Type2 param2, ..., TypeN paramN) -> {
         statment1;
         statment2;
         ...
         return statmentN;
    }
    

    以Predicate判断是否为成年人为例:

    Predicate<Person> predicate = (Person person) -> {
        Integer age = person.getAge();
        return age >= 18;
    };
    

    上面的lambda表达式语法抽象表示是比较官方的,和我们平时所写的lambda表达式比起来要繁琐一些。别着急,下面会一点一点地演示lambda表达式的简化过程。

    1. 参数类型省略

    绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样,lambda表达式就变成了:

    (param1, param2, ..., paramN) -> {
        statment1;
        statment2;
        ...
        return statmentN;
    }
    

    上面的例子也可简化为:

    Predicate<Person> predicate = (person) -> {
        Integer age = person.getAge();
        return age >= 18;
    };
    
    1. 当lambda表达式的参数个数只有一个,可以省略小括号。

    lambda表达式简写为:

    param -> {
        statment1;
        statment2;
        ...
        return statmentN;
    }
    

    对应的例子简化为:

    Predicate<Person> predicate = person -> {
        Integer age = person.getAge();
        return age >= 18;
    };
    
    1. 当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。

    其他省就省了,为啥return关键字也可以被省略呢?原因是,编译器会认为:既然只有一个语句,那么这个语句执行的结果就应该是返回值,所以return也就不需要了。因此,lambda表达式简化为:

    param -> statment;
    

    所以例子又可简化成:

    Predicate<Person> predicate = person -> person.getAge() >= 18
    

    现在这个样子,才是我们熟悉的模样。。。

    Lambda表达式眼中的外部世界

    我们前面所有的介绍,感觉上lambda表达式像一个闭关锁国的家伙:可以访问给它传递的参数,也能自己内部定义变量,但是却从来没看到其访问它外部的变量。是不是lambda表达式不能访问其外部变量?我们可以这样想:lambda表达式其实是快速创建函数式接口实例的语法糖,匿名内部类所实现的实例都可以访问接口外部变量,那么lambda表达式肯定也是可以。事实上,不但可以,在java8中还做了一个小小的升级。看下面例子:

    String[] array = {"a", "b", "c"};
    for (Integer i : Lists.newArrayList(1, 2, 3)) {
        System.out.println(i);
        Stream.of(array).map(item -> Strings.padEnd(item, i, '*')).forEach(s -> System.out.println(s));
    }/*** output
    	a
    	b
    	c
    	a*
    	b*
    	c*
    	a**
    	b**
    	c**
    	*/
    

    上面的这个例子中,map中的lambda表达式访问外部变量Integer i,并且外部变量 i 还可以不用显式声明为final。事实上,lambda表达式同匿名内部类一样,访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。看下面的例子:

    String[] array = {"a", "b", "c"};
    for (int i = 1; i < 4; i++) {
    	System.out.println(i);
    	Stream.of(array).map(item -> Strings.padEnd(item, i, '*')).forEach(System.out::println);
    }/*** output
    	Error:(124, 63) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
    	*/
    

    上面的代码会报编译错误,因为变量i被lambda表达式引用,所以编译器会把其当成final来处理,但如代码所示,变量i是会自增变化的(ps:大家可以想象问什么上一个例子不报错,而这个报错)。细心的读者肯定会发现:以前java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。Bingo,java8对这个限制做了优化,外部变量可以不用显式使用final修饰,但编译器会自动把它当成final来处理。

    lambda表达式与匿名类

    lambda表达式与匿名类的异同集中体现在三点上:

    1. lambda就是为了优化匿名内部类而生,lambda要比匿名类简洁的多得多;
    2. lambda仅适用于函数式接口,匿名类不受限;
    3. 在匿名类内部,this关键字指向该抽象类实例,而lambda内部this指向闭包实例。如果需要在内部通过this关键字访问实例,必须使用匿名类;

    Java8 预定义函数式接口

    Java8 引入了函数式接口,并在java.util.function 包内预定义了常用函数式接口,下表罗列了一些常用的函数式接口:
    在这里插入图片描述

    Function

    Function接口接受一个输入参数T,返回一个结果R,即: R = F u n c t i o n ( T ) R = Function(T) R=Function(T)。接口定义为:

    /**
     * Represents a function that accepts one argument and produces a result.
     * @param <T> the type of the input to the function
     * @param <R> the type of the result of the function
     * @since 1.8
     */
    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         */
        R apply(T t);
    
        /**
         * Returns a composed function that first applies the {@code before}
         * function to its input, and then applies this function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         */
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
        /**
         * Returns a composed function that first applies this function to
         * its input, and then applies the {@code after} function to the result.
         * If evaluation of either function throws an exception, it is relayed to
         * the caller of the composed function.
         */
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    
        /**
         * Returns a function that always returns its input argument.
         */
        static <T> Function<T, T> identity() {
            return t -> t;
        }
    }
    

    Function接口默认实现了3个default方法,分别是compose、andThen和identity,对应的函数表达为:

    • compose方法的含义是 V = F u n c t i o n ( P a r a m F u n c t i o n ( T ) ) V=Function(ParamFunction(T)) V=Function(ParamFunction(T));
    • andThen方法的含义是 V = P a r a m F u n c t i o n ( F u n c t i o n ( T ) ) V=ParamFunction(Function(T)) V=ParamFunction(Function(T));
    • identity方法的含义是 T = F u n c t i o n ( T ) T=Function(T) T=Function(T);

    看个例子:

    public static void main(String[] args) {
    	Function<Integer, Integer> func1 = x -> {
    		return x + 1;
    	};
    	Function<Integer, Integer> func2 = y -> {
    		return y * 7;
    	};
    
    	int x = 3, y = 5;
    	System.out.println(func1.apply(x));
    	System.out.println(func2.apply(y));
    
    	System.out.println(func1.compose(func2).apply(x));
    	System.out.println(func1.andThen(func2).apply(x));
    }/*** output
    	4
    	35
    	22
    	28
    */
    

    Function接口相关的接口包括:

    • BiFunction :R apply(T t, U u);接受两个参数,返回一个值,代表一个二元函数;
    • DoubleFunction :R apply(double value);只处理double类型的一元函数;
    • IntFunction :R apply(int value);只处理int参数的一元函数;
    • LongFunction :R apply(long value);只处理long参数的一元函数;
    • ToDoubleFunction:double applyAsDouble(T value);返回double的一元函数;
    • ToDoubleBiFunction:double applyAsDouble(T t, U u);返回double的二元函数;
    • ToIntFunction:int applyAsInt(T value);返回int的一元函数;
    • ToIntBiFunction:int applyAsInt(T t, U u);返回int的二元函数;
    • ToLongFunction:long applyAsLong(T value);返回long的一元函数;
    • ToLongBiFunction:long applyAsLong(T t, U u);返回long的二元函数;
    • DoubleToIntFunction:int applyAsInt(double value);接受double返回int的一元函数;
    • DoubleToLongFunction:long applyAsLong(double value);接受double返回long的一元函数;
    • IntToDoubleFunction:double applyAsDouble(int value);接受int返回double的一元函数;
    • IntToLongFunction:long applyAsLong(int value);接受int返回long的一元函数;
    • LongToDoubleFunction:double applyAsDouble(long value);接受long返回double的一元函数;
    • LongToIntFunction:int applyAsInt(long value);接受long返回int的一元函数;

    Predicate

    Predicate接口接受一个输入参数,返回一个布尔值结果。其定义为:

    /**
     * Represents a predicate (boolean-valued function) of one argument.
     * @param <T> the type of the input to the predicate
     * @since 1.8
     */
    @FunctionalInterface
    public interface Predicate<T> {
    
        /**
         * Evaluates this predicate on the given argument.
         */
        boolean test(T t);
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * AND of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code false}, then the {@code other}
         * predicate is not evaluated.
         */
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }
    
        /**
         * Returns a predicate that represents the logical negation of this
         * predicate.
         */
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
        /**
         * Returns a composed predicate that represents a short-circuiting logical
         * OR of this predicate and another.  When evaluating the composed
         * predicate, if this predicate is {@code true}, then the {@code other}
         * predicate is not evaluated.
         */
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
        /**
         * Returns a predicate that tests if two arguments are equal according
         * to {@link Objects#equals(Object, Object)}.
         */
        static <T> Predicate<T> isEqual(Object targetRef) {
            return (null == targetRef)
                    ? Objects::isNull
                    : object -> targetRef.equals(object);
        }
    }
    

    其默认方法也封装了and、or和negate逻辑,看个例子:

    public static void main(String[] args) {
    	Predicate<Person> predicate1 = (Person person) -> {
                Integer age = person.getAge();
                return age >= 18;
        };
    
    	Predicate<Person> predicate2 = (Person person) -> {
    		String name = person.getName();
    		return name.startsWith("R");
    	};
    
    	Person rico = new Person();
    	rico.setName("Rico");
    	rico.setAge(16);
    
    	System.out.println("Rico名字以R开头且年满18岁 : " + predicate1.and(predicate2).test(rico));
    	System.out.println("Rico名字以R开头或年满18岁 : " +  predicate1.or(predicate2).test(rico));
    	System.out.println("Rico名字不是以R开头 : " +  predicate1.negate().test(rico));
    }/*** output
    	Rico名字以R开头且年满18岁 : false
    	Rico名字以R开头或年满18岁 : true
    	Rico名字不是以R开头 : true
    */
    

    其他Predicate接口:

    • BiPredicate:boolean test(T t, U u);接受两个参数的二元谓词;
    • DoublePredicate:boolean test(double value);入参为double的谓词函数;
    • IntPredicate:boolean test(int value);入参为int的谓词函数;
    • LongPredicate:boolean test(long value);入参为long的谓词函数;

    Consumer

    Consumer接口接受一个输入参数,没有返回值。其定义为:

    /**
     * Represents an operation that accepts a single input argument and returns no
     * result. Unlike most other functional interfaces, {@code Consumer} is expected
     * to operate via side-effects.
     *  * @param <T> the type of the input to the operation
     *  * @since 1.8
     */
    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * Performs this operation on the given argument.
         */
        void accept(T t);
    
        /**
         * Returns a composed {@code Consumer} that performs, in sequence, this
         * operation followed by the {@code after} operation. If performing either
         * operation throws an exception, it is relayed to the caller of the
         * composed operation.  If performing this operation throws an exception,
         * the {@code after} operation will not be performed.
         */
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }
    

    看个例子:

    public static void main(String[] args) {
    	Person rico = new Person();
    	rico.setName("Rico");
    	rico.setAge(16);
    
    	Consumer<Person> consumer = person -> System.out.println(person);
        consumer.accept(rico);
    }/*** output
    	{"age":16,"name":"Rico"}
    */
    

    其他Consumer接口:

    • BiConsumer:void accept(T t, U u);接受两个参数
    • DoubleConsumer:void accept(double value);接受一个double参数
    • IntConsumer:void accept(int value);接受一个int参数
    • LongConsumer:void accept(long value);接受一个long参数
    • ObjDoubleConsumer:void accept(T t, double value);接受一个泛型参数一个double参数
    • ObjIntConsumer:void accept(T t, int value);接受一个泛型参数一个int参数
    • ObjLongConsumer:void accept(T t, long value);接受一个泛型参数一个long参数

    Supplier

    Supplier接口不需要任何参数,返回一个值。其定义为:

    /**
     * Represents a supplier of results.
     *
     * @param <T> the type of results supplied by this supplier
     *
     * @since 1.8
     */
    @FunctionalInterface
    public interface Supplier<T> {
    
        /**
         * Gets a result.
         */
        T get();
    }
    

    看个例子:

    public static void main(String[] args) {
    	Person rico = new Person();
    	rico.setName("Rico");
    	rico.setAge(16);
    
    	Supplier<Person> supplier = () -> rico;
    	System.out.println("supplier : " + supplier.get());
    }/*** output
    	supplier : {"age":16,"name":"Rico"}
    */
    

    其他Supplier接口:

    • BooleanSupplier:boolean getAsBoolean(); 返回boolean
    • DoubleSupplier:double getAsDouble();返回double
    • IntSupplier:int getAsInt();返回int
    • LongSupplier:long getAsLong();返回long
    展开全文
  • 主要介绍了Java Lambda表达式函数式接口,结合实例形式分析了Java8 Lambda表达式函数式接口相关原理、用法及操作注意事项,需要的朋友可以参考下
  • Lambda表达式函数式接口基础学习 ...函数式接口是指只有一个抽象方法的接口; Lambda表达式需要函数式接口的支持; 自定义的函数式接口可以加上注解 @FunctionalInterface ,用于编译器检查是否是函数式接口。 ...

    Lambda表达式与函数式接口基础学习

    1. 概念一:Lambda表达式的操作符和基本结构

    操作符: ->
    基本结构:参数列表 -> Lambda体(需要执行的功能)

    2. 概念二:函数式接口

    函数式接口是指只有一个抽象方法的接口;
    Lambda表达式需要函数式接口的支持;
    自定义的函数式接口可以加上注解 @FunctionalInterface ,用于编译器检查是否是函数式接口。

    Lambda表达式的参数列表对应一个函数式接口的抽象方法的参数列表,Lambda体对应了该抽象方法的实现。

    3. Lambda表达式的语法格式

    第一种:无参数,无返回值
    例如:() -> System.out.println("hello");
    无参数,无返回值的Lambda表达式在使用中也可以结合一个有无参数,无返回值的抽象方法的函数式接口使用,如Runnable接口的run()Runnable是一个函数式接口),示例代码如下:

    	@Test
        public void test01(){
            // 原来使用匿名内部类方式
            Runnable r1 = new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello");
                }
            };
            // Lambda表达式方式
            Runnable r2 = () -> System.out.println("hello");
        }
    

    可以看到,在Java8以前,要实现一个Runnable接口,在仅仅只有一条需要执行的语句的情况下也需要通过匿名内部类的方式多写好几行与执行功能无关的代码。而Java8之后的Lambda表达式则只关注具体的执行功能,简化了开发。由于run()是没有参数也没有返回值的抽象方法,所以Lambda表达式的参数列表为空,但是()不能省略,而Lambda体中由于只有一条语句,所以可以直接写,但是如果超过了一条语句,则需要加上{}

    第二种:有一个参数,无返回值
    例如:

    (x) -> System.out.println(x);
    x -> System.out.println(x); // 只有一个参数时可以不写括号,但是建议写上
    

    Lambda表达式的参数可以自己定义,不需要加类型修饰符,因为编译器会通过代码的上下文推断出该参数的类型。示例代码如下:

    	@Test
        public void test02(){
            Consumer<String> c = (x) -> System.out.println(x + ",out");
            c.accept("hhhh");
        }
    

    Consumer接口也是一个函数式接口,它只有accept()这一个抽象方法,该方法有一个参数并且没有返回值。

    第三种:有多个参数,有返回值
    Comparator<T>接口是一个比较器,也是一个函数式接口,它的抽象方法int compare(T o1, T o2);有两个参数并且提供返回值,示例代码如下:

    	@Test
        public void test03(){
            // 匿名内部类方式
            Comparator<Integer> com1 = new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    System.out.println("函数式接口");
                    return Integer.compare(o1, o2);
                }
            };
            // Lambda表达式方式
            Comparator<Integer> com2 = (x, y) -> {
                System.out.println("函数式接口");
                return Integer.compare(x, y);
            };
        }
    

    第四种:当Lambda体中只有一条语句时,return和{}都可以省略
    还是用上一个例子:

    	@Test
        public void test04(){
            Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
        }
    

    由于该接口的抽象方法是有返回值的,而Lambda体又只有一条语句:return Integer.compare(x, y);所以可以省略return

    4. Java内置的四大核心函数式接口

    因为Lambda表达式需要函数式接口的支持,所以当我们使用Lambda表达式时也需要对应的函数式接口,但是每次都自己定义接口会比较麻烦,所以Java为我们提供了一些内置的函数式接口,这些函数式接口基本能够满足我们大部分的需求,其中最主要的有四个:

    第一个:Consumer<T>: 消费型接口
    抽象方法:void accept(T t);
    使用示例:

        @Test
        public void test01(){
            enjoy(125.5, (x) -> System.out.println("用餐消费:" + x));
            enjoy(255.0, (x) -> System.out.println("住宿消费:" + x));
            enjoy(505.5, (x) -> System.out.println("车票消费:" + x));
        }
    
        private void enjoy(double money, Consumer<Double> consumer){
            consumer.accept(money);
        }
    

    消费型接口的含义是类似于消费者一样,只接收一个参数,内部进行处理,没有返回值。这里的enjoy方法接收两个参数,一个是金额,一个是函数式接口Consumer,这样做的目的是为了防止代码冗余,试想如果每个不同的项目的消费情况都需要一个独立的方法来完成那么在这个例子中就得为用餐消费、住宿消费、车票消费分别写三个差不多的方法。而有了Lambda表达式和函数式接口就可以简化代码了,当我们需要输出不同的项目消费情况时只需在调用enjoy方法时传递不同的Lambda表达式即可。

    第二个:Supplier<T>: 供给型接口
    抽象方法:T get();
    使用示例:

    	@Test
        public void test02(){
            System.out.println(generateString(() -> UUID.randomUUID().toString()));
        }
    
        private String generateString(Supplier<String> supplier){
            return supplier.get();
        }
    

    供给型接口的含义是有返回值,没有参数。示例中的generateString方法用于得到一个随机的字符串,它接收一个函数式接口Supplier,Lambda表达式中的UUID.randomUUID().toString()用于生成随机的字符串,由于只有一条语句,所以return可以省略。

    第三个:Function<T, R>: 函数型接口
    抽象方法:R apply(T t);
    使用示例:

    	@Test
        public void test03(){
            String str = "sdfasdgbas";
            System.out.println(stringHandler(str, (s) -> str.toUpperCase()));
            System.out.println(stringHandler(str, (s) -> str.substring(0, str.length() - 1)));
        }
    
        private String stringHandler(String str, Function<String, String> function){
            return function.apply(str);
        }
    

    函数型接口的含义是提供一个参数,经过处理后返回一个值。stringHandler方法是一个字符串处理方法,它并没有在方法体中给出具体处理的代码,而是通过接收一个函数式接口Function,来调用其apply方法进行处理并返回值。这种思想和第一个示例一样,如果每种不同的处理方式(如:将字符串变成大写或小写,截取字符串等)都需要一个不同的方法来实现就会很麻烦。通过传递Lambda表达式的方式就会更简单。

    第四个:predicate<T>: 断言型接口
    抽象方法:boolean test(T t);
    使用示例:

    	/**
         * predicate<T>: 断言型接口测试
         * 将满足条件的字符串放入集合中
         */
    	@Test
        public void test04(){
            List<String> strings = new ArrayList<>(Arrays.asList(
                    "hhhh",
                    "ooo",
                    "egasgaasg",
                    "asodiang",
                    "waogaweogaweog"
            ));
            System.out.println(filterStrings(strings, (s) -> s.length() > 5));
        }
    
        private List<String> filterStrings(List<String> strings, Predicate<String> predicate){
            List<String> result = new ArrayList<>(strings.size());
            for (String str: strings) {
                if(predicate.test(str)){
                    result.add(str);
                }
            }
            return result;
        }
    

    断言型接口的含义是接收一个参数,判断其是否符合某个条件,返回一个boolean值。在本示例中,filterStrings是一个过滤List集合中的字符串的方法,要求筛选出符合条件的字符串并返回。同样的,筛选条件并没有直接的写在方法体中,而是通过接收一个断言型接口Predicate调用其test方法来进行判断,在调用filterStrings方法时就可以通过Lambda表达式写出需要的筛选条件。

    其他函数式接口
    当我们实际使用的时候会发现,有时候我需要传递两个参数或者三个参数该怎么办?这四大函数式接口不能满足这个需求,需要自己定义吗?不需要,因为这四个是最核心的函数式接口,其实Java还提供了从这四个扩展来的更多的函数式接口以满足需求,具体可以去查阅文档。

    函数式接口和Lambda表达式的基本用法就到这里了,后面还有一篇关于Java8的方法引用的文章,也是Lambda表达式相关的内容。

    展开全文
  • Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码。JDK1.8提供了函数式接口支持Lambda语法开发
  • 对于Java8其实相比之前的的版本增加的内容是相当多的,其中有相当大块的内容是关于Lambda表达式与Stream API,而这两部分是紧密结合而不能将其拆开来对待的,但是是可以单独使用的,所以从学习的顺序来说首先得要...
  • Lambda 表达式是Java8以后的新特性,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑,相应的带来了新的学习成本。 Lambda语法特征主要有以下四点...
  • 当然还有函数式接口这样的东西。说实话。刚开始内心是拒绝学习的。因为这么写很多时候你dubug的时候感觉很很无助。当然慢慢习惯的就好。但是到现在我对这两概念还是模糊的。谁是谁的问题。我现在还没搞清楚。只能...
  • 前言: 目前接触的项目中大量使用Java8的语法、看起来代码十分的简洁、优雅、可能开始 阅读起来 有些不习惯、但是看的多了...个人理解: lambda表达式的出现可以替换之前没有函数式接口以及lambda表达式之前的 要实
  • 一点睛 ...如果采用匿名内部类语法来创建函数式接口的实例,只要实现一个抽象方法即可,在这种情况下即可采用Lambda表达式来创建对象,该表达式创建出来的对象的目标类型就是这个函数式接口。 Java ...
  • Java 8 在语言层面引入Lambda表达式,用以支持函数式编程风格。Lambda表达式使用五行代码转换为单个语句来解决匿名内部类的庞大性。 这简单的水平解决方案解决了内部类提出的“垂直问题”。本文对lambda的介绍分为...
  • 死磕Lambda表达式(四):常用的函数式接口

    万次阅读 多人点赞 2020-03-05 08:26:53
    在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几其中的接口及其使用示例。
  •   ▊ lambda表达式的引入   ▌为什么需要lambda表示?...透过现象看本质:它们真正需要的,是一个"函数",是一个告诉它们,根据什么去排序、被触发后执行什么、线程去执行什么任务的"函数"(comp
  • 本文是跟着宋红康老师讲解的视频做的笔记,视频地址:[尚硅谷]Java8新特性(Lambda表达式+Stream API+Optional类)_...4. Lambda表达式如果只有一个参数,那么参数的小括号可以省略 5. Lambda有多个参数,有返回值 ..
  • lambda表达式是JAVA8中提供的一种新的特性,它支持JAVA也能进行简单的“函数式编程”。 它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,...
  • 文章目录1 Lambda 表达式1.1 lambda一个匿名函数1.2 lambda应用1.3 lambda 语法1.4 Lambda 表达式需要“函数式接口”的支持2 函数式接口 1 Lambda 表达式 1.1 lambda一个匿名函数 原先的匿名内部类 //例如 比较...
  • 主要介绍了Java8简单了解Lambda表达式函数式接口,具有一定参考价值,需要的朋友可以了解下。
  • lambda表达式调用函数式接口有如下几种方法: 一、匿名内部类 二、-> 方式 没有参数时候可以使用 () -> {},当参数只有一个时候()可以省略,当处理了只有一行时候{}可以省略 三、:: 方式 ①类名::...
  • Lambda表达式只支持函数式接口 也就是只有一个抽象方法的接口 可以使用@FunctionalInterface标注函数式接口,在编译时提前发现错误。 例子: package test; @FunctionalInterface public interface IParmas1 { void ...
  • Lambda表达式实现函数式接口与传统实现方式: (函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。) public class LambdaDemo { public static void main( String[] args ) { ...
  • Lambda表达式一个匿名函数, 我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递) 。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使得Java语言表达能力得到了提升。、 ...
  • 函数式编程Lambda简介函数式编程实例Lambda省略格式Lambda使用前提常用的函数式接口 Lambda简介 在创建匿名内部类的过程中,你是否觉得代码冗余繁长?为了运行类内的方法,而不得不创建一个匿名内部类来调用方法,这...
  • 有且只有一个抽象方法(可以包含default或static方法,但Object类除外)的接口是函数式接口。@FunctionlInterface就是用来指定某个接口必须是函数式接口。@FunctionalInterface不是必须的,只是告诉编译器检查这个...
  • 函数式接口lambda表达式

    千次阅读 2017-06-20 21:54:40
    函数式接口和lambda表达式函数式接口(Functional Interface) :​ 任何接口,如果只包含唯一 一个抽象方法,那么它就是一个FI。(之前它们被称为 SAM类型,即 单抽象方法类型(Single Abstract Method))。接口中的...
  • Java8新特性之Lambda表达式函数式接口一. 函数式接口简介1. 概念2. 格式3. @FunctionalInterface注解二. Lambda表达式1. 概念2. 格式3. 示例三. 函数式编程1. Lambda的延迟执行2. 使用Lambda作为参数和返回值四. ...
  • 函数式接口Lambda表达式的优点

    千次阅读 2018-12-18 22:47:34
    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。 一:优化性能 先看一段常见的程序 public class MyLambda { ...
  • java8 lambda表达式语法的两种格式: (parameters) -> expression (parameters) -> {statements;} 语法解读: (parameters),lambda表达式的参数列表,其定义方法为JAVA普通的方法相同,例如(Object a, ...
  • 在学习Lambda表达式函数式接口的时候,发现学习的时候不系统,用的时候总是忘记怎么去使用。所以总结一些实例,便于理解其使用。 实例理解Java8新特性中Lambda表达式函数式接口的使用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,890
精华内容 16,756
关键字:

lambda的表达式是一个函数式接口