Lambda表达式函数式接口的介绍和使用

1.Lambda表达式介绍

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表达式由三部分组成:

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

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

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

例子:

// 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)

2.什么是函数式接口

函数式接口定义:一个接口有且只有一个抽象方法 。

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

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

 比如说:多线程里面的Thread的run方法就是一个函数式接口

 

 还有sort排序的时候实现Comparator接口重写compar方法,实现sort自定义类的排序,都是函数式接口

public class Demo2 {
    public static void main(String[] args) {
        Student[] students = {new Student(114,"张山"),
                new Student(112,"李四"),new Student(113,"王五")};
        Arrays.sort(students, new MyComparator());
        for (Student tmp : students){
            System.out.println(tmp);
        }
    }
}
class Student implements Comparator<Student> {
    int id;
    String name;

    public Student() {
    }

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }


    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }


    @Override
    public int compare(Student o1, Student o2) {
        return o1.compareTo(o2);
    }
}

输出结果:

comparTo方法解释:

 3.Lambda实现简化

Thread的run方法化简:

comparator接口compar方法的化简:

 在加上小小的练习:

        public class TestDemo {
            public static void main(String[] args) {
                NoParameterNoReturn noParameterNoReturn = ()->{
                    System.out.println("无参数无返回值");
                };
                noParameterNoReturn.test();
                OneParameterNoReturn oneParameterNoReturn = (int a)->{
                    System.out.println("一个参数无返回值:"+ a);
                };
                oneParameterNoReturn.test(10);
                MoreParameterNoReturn moreParameterNoReturn = (int a,int b)->{
                    System.out.println("多个参数无返回值:"+a+" "+b);
                };
                moreParameterNoReturn.test(20,30);
                NoParameterReturn noParameterReturn = ()->{
                    System.out.println("有返回值无参数!");
                    return 40;
                };
                //接收函数的返回值
                int ret = noParameterReturn.test();
                System.out.println(ret);
                OneParameterReturn oneParameterReturn = (int a)->{
                    System.out.println("有返回值有一个参数!");
                    return a;
                };
                ret = oneParameterReturn.test(50);
                System.out.println(ret);
                MoreParameterReturn moreParameterReturn = (int a,int b)->{
                    System.out.println("有返回值多个参数!");
                    return a+b;
                };
                ret = moreParameterReturn.test(60,70);
                System.out.println(ret);
            }
        }

注意:

1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
2. 参数的小括号里面只有一个参数,那么小括号可以省略
3. 如果方法体当中只有一句代码,那么大括号可以省略
4. 如果方法体中只有一条语句,且是 return 语句,那么大括号可以省略,且去掉 return 关键字。

4.变量捕获 

 Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解 Lambda 表达式的作用域 。 Java 当 中的匿名类中,会存在变量捕获。

4.1匿名内部类的变量捕获(重要)

class Test {
    public void func() {
        System.out.println("func()");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        int a = 100;
        new Test() {
            @Override
            public void func() {
                a = 99;
                System.out.println("我是内部类,且重写了func这个方法!");
                System.out.println("我是捕获到变量 a == " + a
                        + " 我是一个常量,或者是一个没有改变过值的变量!");
            }
        };
    }
}

报错:

 

在上述代码当中的变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的 你要保证在使用之前,没有修改。

 

4.2Lambda的变量捕获(重要)

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
public static void main(String[] args) {
    int a = 10;
    NoParameterNoReturn noParameterNoReturn = ()->{
        // a = 99; error
        System.out.println("捕获变量:"+a);
    };
    noParameterNoReturn.test();
}

5.Lambda在集合当中的使用

为了能够让 Lambda Java 的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与 Lambda 表达式对接。

 

对应的接
新增的方法
Collection
removeIf() spliterator() stream() parallelStream() forEach()
List
replaceAll() sort()
Map
computeIfPresent() compute() merge()
getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent()

5.1 Collection接口常用lambda演示

forEach() 方法演示

该方法在接口 Iterable 当中,原型如下:

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

该方法表示:对容器中的每个元素执行action指定的动作 。

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("Hello");
    list.add("bit");
    list.add("hello");
    list.add("lambda");
    list.forEach(new Consumer<String>(){
        @Override
        public void accept(String str){
            //简单遍历集合中的元素。
            System.out.print(str+" ");
        }
    });
}
输出结果: Hello bit hello lambda
我们可以使用lambda修改为如下代码:
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("Hello");
    list.add("bit");
    list.add("hello");
    list.add("lambda");
    //表示调用一个,不带有参数的方法,其执行花括号内的语句,为原来的函数体内容。
    list.forEach(s -> {
        System.out.println(s);
    });
}

sort()方法的演示

sort方法源码:该方法根据c指定的比较规则对容器元素进行排序。

public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

使用案例:

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("Hello");
    list.add("bit");
    list.add("hello");
    list.add("lambda");
    list.sort(new Comparator<String>() {
        @Override
        public int compare(String str1, String str2){
            //注意这里比较长度
            return str1.length()-str2.length();
        }
    });
    System.out.println(list);
}
输出结果: bit, Hello, hello, lambda
修改为 lambda 表达式:
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("Hello");
    list.add("bit");
    list.add("hello");
    list.add("lambda");
    //调用带有2个参数的方法,且返回长度的差值
    list.sort((str1,str2)-> str1.length()-str2.length());
    System.out.println(list);
}

HashMap forEach()方法演示

源代码:

default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}
作用是对 Map 中的每个映射执行 action 指定的操作。
使用案例:
public static void main(String[] args) {
    HashMap<Integer, String> map = new HashMap<>();
    map.put(1, "hello");
    map.put(2, "bit");
    map.put(3, "hello");
    map.put(4, "lambda");
    map.forEach(new BiConsumer<Integer, String>(){
        @Override
        public void accept(Integer k, String v){
            System.out.println(k + "=" + v);
        }
    });
}
使用 lambda 表达式后的代码:
public static void main(String[] args) {
    HashMap<Integer, String> map = new HashMap<>();
    map.put(1, "hello");
    map.put(2, "bit");
    map.put(3, "hello");
    map.put(4, "lambda");
    map.forEach((k,v)-> System.out.println(k + "=" + v));
}
输出结果:
1=hello 2=bit 3=hello 4=lambda

总结

Lambda 表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:
1. 代码简洁,开发迅速
2. 方便函数式编程
3. 非常容易进行并行计算
4. Java 引入 Lambda ,改善了集合操作
缺点:
1. 代码可读性变差
2. 在非并行计算中,很多计算未必有传统的 for 性能要高
3. 不容易进行调试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆浆粉牛奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值