一、Lambda表达式

Lambda 表达式,也可称为闭包,它是Java 8 发布的最重要新特性

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中) 

lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)

(一)语法

(parameters) -> expression
或
(parameters) ->{ statements; }

Lambda表达式由三部分组成

1、paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明,也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号

2、->:可理解为“被用于”的意思

3、方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不返回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回

// 1、不需要参数,返回值为 2
() -> 2

// 2、接收一个参数(数字类型),返回其2倍的值
x -> 2 * x

// 3、接受2个参数(数字),并返回他们的和
(x, y) -> x + y

// 4、接收2个int型整数,返回他们的和
(int x, int y) -> x + y

// 5、接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

Lambda语法特点

  • 类型声明可省略:参数的类型可省略,编译器可自动识别
  • 参数圆括号可省略:一个参数可以省略圆括号,无参或多个参数需要圆括号
  • 大括号可省略:如果主体部分只是一个语句,可以省略大括号
  • 返回关键字可省略:如果主体只有一个表达式返回值,则可以省略返回关键字编译器会自动返回,如果多条语句则不能省略

(二)Lambda表达式使用

Lambda表达式中我们只需要关心:参数列表 方法体

Lambda从普通接口实现类至Lambda表达式生成过程

public class LambdaTest {
    public static void main(String[] args) {
        Like like = new LikeImpl();
        like.like();

        like = new LikeImpl2();
        like.like();

        //4、局部内部类
        class LikeImpl3 implements Like{
            @Override
            public void like() {
                System.out.println("I like3");
            }
        }
        like = new LikeImpl3();
        like.like();

        //5、匿名内部类
        like = new Like(){
            @Override
            public void like() {
                System.out.println("I like4");
            }
        };
        like.like();

        //6、Lambda表达式
        like = () -> {
            System.out.println("I like5");
        };
        like.like();
    }

    //3、静态内部类
    static class LikeImpl2 implements Like{
        @Override
        public void like() {
            System.out.println("I like2");
        }
    }
}

//1、定义一个接口(有且只有一个抽象方法;接口中抽象方法的public abstract可以省略)
interface Like{
    // 有且只有一个抽象方法(接口中抽象方法的public abstract可以省略)
    void like();
}

//2、接口实现类
class LikeImpl implements Like{
    @Override
    public void like() {
        System.out.println("I like");
    }
}

Lambda简化过程 

/**
 * Lambda表达式只能有一行代码情况下才能简化为一行
 * 多个参数也可去掉参数类型,但是要去都去,要加都加
 */
public class LambdaTest2 {
    public static void main(String[] args) {
        Love like = null;

        // Lambda表达式
        like = (int a) -> {
            System.out.println("I like " + a);
        };
        like.like(520);

        //1、去掉参数类型
        like = (a) -> {
            System.out.println("I like " + a);
        };
        like.like(521);

        //2、去掉参数类型括号
        like = a ->{
            System.out.println("I like " + a);
        };
        like.like(522);

        //3、去掉方法体花括号
        like = a -> System.out.println("I like " + a);
        like.like(522);
    }
}

// 定义一个接口(有且只有一个抽象方法;接口中抽象方法的public abstract可以省略)
interface Love{
    // 有且只有一个抽象方法(接口中抽象方法的public abstract可以省略)
    void like(int a);
}

Lambda表达式的语法还可以精简

1、参数类型可以省略,如果需要省略,每个参数的类型都要省略

2、参数的小括号里面只有一个参数,那么小括号可以省略

3、如果方法体当中只有一句代码,那么大括号可以省略

4、如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字

1、List和foreach、sort

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        //List的foreach
        list.add("hello");
        list.add("lambda");
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("----------");
        //Lambda方法
        list.forEach(a-> System.out.println(a));

        //List的sort 方法
        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println(list);
        System.out.println("----------");
        //Lambda方法
        list.sort((o1,o2)->o2.compareTo(o1));
        System.out.println(list);
    }

源码如下:

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
    
    ......
}


@Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

2、HashMap和forEach

public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();

        map.put(1, "hello");
        map.put(2, "lambda");
        map.forEach(new BiConsumer<Integer, String>(){
            @Override
            public void accept(Integer k, String v){
                System.out.println(k + "=" + v);
            }
        });

        //Lambda方法
        map.forEach((k,v)-> System.out.println("key = "+k+" ,value = "+v));
    }

源码如下:

@FunctionalInterface
public interface BiConsumer<T, U> {

    /**
     * Performs this operation on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);
    
    ......
}


@Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e.key, e.value);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

二、函数式接口

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

使用 @FunctionalInterface 注解

函数式接口可以被隐式转换为 lambda 表达式,如创建线程 实现的 Runnable 接口

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口

如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。因此,只要保证接口中只有一个抽象方法,可以不加这个注解。加上就会自动进行检测

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 新增加的函数接口:

  • java.util.function

Java中主要有4个常用函数式接口,都在 java.util.function包下

Function,Predicate,Consumer,Supplier

1、Function

传入参数T,返回类型R

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
/**
 * Function 函数型接口, 有一个输入参数 T ,有一个输出 R
 * 只要是 函数型接口 可以 用 lambda表达式简化
 */
public class FunctionTest {
    public static void main(String[] args) {
        Function<String ,String> function = new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s;
            }
        };

        System.out.println(function.apply("abc"));
    }
}

2、Predicate

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
/**
 * 断定型接口:有一个输入参数,返回值只能是 布尔值!
 */
public class PredicateTest {
    public static void main(String[] args) {
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                System.out.println(s);
                return true;
            }
        };

        System.out.println(predicate.test("abc"));
    }
}

3、Consumer

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
/**
 * Consumer 消费型接口: 只有输入,没有返回值
 */
public class ConsumerTest {
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("abc");
    }
}

4、Supplier

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
/**
 * Supplier 供给型接口 没有参数,只有返回值
 */
public class SupplierTest {
    public static void main(String[] args) {
        Supplier<String> supplier = new Supplier<String>() {
            @Override
            public String get() {
                return "abc";
            }
        };

        System.out.println(supplier.get());
    }
}