1.什么叫做Lambda表达式

我们可以把它看成是一种闭包,它允许把函数当做参数来使用,是面向函数式编程的思想,一定程度上可以使代码看起来更加简洁;当lambda表达式与流操作一起结合使用,会使代码看起来逼格十分高

 (parameters参数) -> {expression表达式或方法体;}
    展开如:
    (Type1 param1, Type2 param2, Type2 param2, ...) -> {
        statement1;
        statement2;
        statement3;
        ...
        return statementX;
    }

当参数只有一个,小括号可以省略;当执行的方法体只有一条时,花括号可以省略,return这个关键字可以省略,末尾的分号取消

2.lambda表达式应用场景

需要显示创建函数式接口对象的地方,都可以使用实际上函数式接口的转换是Lambda表达式唯一能做的事情,即lambda必须和函数式接口(接口使用@Functional Interface标注,或者只有一个方法的接口)配套使用;主要用于替换以前广泛使用的内部匿名类,各种回调,比如事件响应器、传入Thread类的Runnable等

new Thread(()-> System.out.println("启动子线程")).start();

通过以上例子启动一个子线程,通过一行代码即可,代码是否简洁

3.基本使用方法

public class LambdaTest {

    public static void main(String[] args) {
        String[] str=new String[]{"a","ba","cc","dd"};
        //传统匿名内部类
        Arrays.sort(str, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return Integer.compare(o1.length(),o2.length());
            }
        });
        String[] str1=new String[]{"a","ba","cc","dd"};
        //使用lambda表达式
        Arrays.sort(str1,(o1,o2)-> Integer.compare(o1.length(),o1.length()));
    }
}

从上述代码可以看出,若使用传统的匿名内部类,代码需要编写很长一段,会使代码量变大,当使用lambda表达式时,可以将代码量缩减至一行

4.java8定义的函数式接口

jdk1.8开始为了方便用户开发专门提供了一个新的包:java.util.function在这个包里面针对于用户有可能做的函数式接口做了一个公共定义,最为核心的有四个接口:
1)功能性接口:Function<T, R>
一.有输入参数,有返回值
二.是对接收一个T类型参数,返回R类型的结果的方法的抽象
三.通过调用apply方法执行内容



package java.util.function;

import java.util.Objects;

/**
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /** 接口泛型 T为apply 的入参 ,R为返回参数
     * Applies this function to the given argument
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
    /*
	省略其他方法,
	*/
}

测试Function函数接口

    public static void main(String[] args) {
        testFunction("你好",st1-> st1.length());
    }
    //测试函数式接口,function.apply(str)就相当于直接调用st1.length(),并且将值返回回来
    public static void testFunction(String str, Function<String ,Integer> function){
        Integer length = function.apply(str);
        System.out.println("返回值、、、、、"+length);
    }

步骤:
1.调用testFunction方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法

2)消费型接口:Consumer< T>
一:有输入参数,没返回值
二:对应的方法类型为接收一个参数,没有返回值
三:一般来说使用Consumer接口往往伴随着一些期望状态的改变或者事件的发生,典型的forEach就是使用的Consumer接口,虽然没有任何的返回值,但是向控制台输出结果
四:Consumer 使用accept对参数执行行为



package java.util.function;

import java.util.Objects;

/**
 * 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.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @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.
     *
     * @param t the input argument
     */
    void accept(T t);
	//省略其他方法
}

测试

public class Fun {
    public static void main(String[] args) {
        testConsumer("hello",(str)-> System.out.println(str));
    }
    /**
     *
     * @param str 传入参数
     * @param con
     */
    public static void testConsumer(String str, Consumer<String> con) {
        // 执行
        con.accept(str);
    }
}

步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法

3).供给型接口:Supplier
一:无传入参数,有返回值
二:该接口对应的方法类型不接受参数,但是提供一个返回值
三:使用get()方法获得这个返回值


@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

测试

public class Fun {
    public static void main(String[] args) {
        testSupplier(()->"hello");
    }
    /**
     * @param sup
     * @return
     */
    public static String testSupplier(Supplier<String> sup) {
        // 执行
        String s = sup.get();
        return s;
    }
}

步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法

4)断言型接口:Predicate
一:有传入参数,有返回值Boolean
二:该接口对应的方法为接收一个参数,返回一个Boolean类型值
三:多用于判断与过滤,使用test()方法执行这段行为


@FunctionalInterface
public interface Supplier<T> {
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
  public static void main(String[] args) {
        testPredicate("hello",(str)->str instanceof String);
    }
    /**
     * @param str
     * @param pre
     * @return
     */
    public static boolean testPredicate(String str, Predicate<String> pre) {
        // 执行
        boolean flag = pre.test(str);
        return flag;
    }

步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法

5.Lambda的优点

a.极大的减少代码冗余,同时可读性也好过冗长的匿名内部类
b.与集合类批处理操作结合,实现内部迭代,并充分利用现代多核CPU进行并行计算。之前集合类的迭代都是外部的,即客户代码。而内部迭代意味着由Java类库来进行迭代,而不是客户代码

6.和匿名内部类的区别

a.在lambda中,this不是指向lambda表达式产生的那个对象,而是它的外部对象
b.Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法,但每一个匿名内部类编译器会为其创建一个类文件

09-09 08:48