lambda 两个list获取交集_Java8新特性:Lambda表达式详解

本文深入探讨了Java8的重要特性——Lambda表达式,阐述其在函数式编程中的作用,通过实例展示了如何使用Lambda简化代码,包括无参、有参、有返回值的Lambda形式,并介绍了Stream API的filter、sorted、limit等方法在数据处理中的应用,帮助读者高效获取两个list的交集。
摘要由CSDN通过智能技术生成
ab05c2fe805d71e27a072efb5103f6a5.png   Java大联盟

  致力于最高效的Java学习

关注

194ea216893e970a8747840a8aab33a6.gif

在 Java 版本的历次更新迭代中,Java8 是一个特殊的存在,与以往的版本升级不同。我们对 Java8 似乎抱有更大的期待,因为它是 Java5 之后最重要的一次升级,提供了十多个新特性,其中 Lambda 表达式是 Java8 新特性中最重要的一个。

Lambda 表达式允许开发者将函数作为参数传给某个方法,即支持函数式编程,这并不是一种新技术,很多基于 JVM 的语言如 Groovy 和 Scala 都支持函数式编程,Java 官方直到 Java8 才引入函数式编程机制。在 Java8 诞生之前,开发者更多的关注点在于对象的属性,这也是面向对象编程思想的核心,即对数据进行抽象,而函数式编程则是对行为进行抽象,是面向函数进行编程。

Java8 通过引入 Lambda 表达式来支持函数式编程,Lambda 表达式允许我们将一个函数作为参数进行传递,一个函数定义了一个行为,语法如下所示。

(参数) -> (方法体)

我们首先通过一个例子来直观理解什么是 Lambda 表达式:启动一个线程,不使用 Lambda 表达式的代码如下所示。

new Thread(new Runnable() {
  @Override
  public void run() {
    System.out.println("do it..."");
  }
}).start();

使用 Lambda 表达式的代码如下所示。

new Thread(()-> System.out.println("do it...")).start();

new Thread() 中传递的就是一个函数,它定义了线程的具体任务,即行为。通过对比可以得出结论,使用 Lambda 表达式可以替代传统的匿名类开发方式,不需要创建匿名类即可完成业务逻辑的代码编写,开发效率更高。

Lambda 表达式由 3 部分组成:1、参数。2、->。3、函数主体。

d97b557fe86165b272e579555a363e44.png

这里需要注意,能够使用 Lambda 表达式的必须是一个函数接口,函数接口是指该接口中只包含一个方法,如 Runnable 接口。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 


     * The general contract of the method run is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */


    public abstract void run();
}

如果一个接口中包含超过两个方法,则不能使用 Lambda 表达式,接下来我们介绍几种常用的函数接口类型。

1、没有参数、没有返回值的函数接口

public interface MyInterface {
    public void test();
}

具体使用如下所示,定义一个 test 方法,将函数接口作为参数传入。

public class Test {
    public static void main(String[] args) {

        Test test = new Test();
        //不使用Lambda表达式
        test.test(new MyInterface() {
            @Overridepublic void test() {
                System.out.println("123");
            }
        });
        //使用Lambda表达式
        test.test(()-> System.out.println("333"));
    }

    public void test(MyInterface myInterface){
        myInterface.test();
    }
}

运行结果如下图所示。

a3ea9c24ff9b7b040d3efc8a7ef3efb1.png

2、带参数的函数接口

public interface MyInterface {
    public void test(int x);
}

具体使用如下所示。

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.test((int x)-> System.out.println("传入的参数是:"+x));
    }

    public void test(MyInterface myInterface){
        int x = 10;
        myInterface.test(x);
    }
}

运行结果如下图所示。

189ab4c7736f37a8c9b35b576864f3ed.png

参数的数据类型也可以不声明,根据上下文自动获取,如下所示。

test.test((int x)-> System.out.println("传入的参数是:"+x));
等于
test.test((x)-> System.out.println("传入的参数是:"+x));

3、有返回值的函数接口

public interface MyInterface {
    public boolean test();
}

具体使用如下所示。

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.test(()-> true);
    }

    public void test(MyInterface myInterface){
        System.out.println(myInterface.test());
    }
}

运行结果如下图所示。

ee9c9de2dd36a598b1cba3698d0b9c7c.png

4、有参数、有返回值的函数接口

public interface MyInterface {
    public int test(int x,int y);
}

具体使用如下所示。

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.test((int x,int y)-> x+y);
    }

    public void test(MyInterface myInterface){
        int x = 10;
        int y = 20;
        System.out.println("10和20之和是:"+myInterface.test(x,y));
    }
}

运行结果如下图所示。

49dd9b9f90530f60f09df8103069f964.png

如果函数接口的方法体只有一条语句,可省略 {},如下所示。

test.test((int x,int y)-> x+y);

如果函数接口的方法体包含多条语句,需要在 {} 中添加相关语句,如下所示。

test.test((int x,int y)-> {
   System.out.println("参数是:"+x+","+y);
    return x+y;
});

搞清楚了 Lambda 表达式的基本使用,接下来我们介绍几种实际开发中常用的 Lambda 表达式案例。

Lambda 表达式实际案例

1、替代匿名类

不使用 Lambda 表达式的代码如下所示。

new Thread(new Runnable() {
  @Overridepublic void run() {
    System.out.println("do it...");
  }
}).start();

使用 Lambda 表达式的代码如下所。

new Thread(()-> System.out.println("do it...")).start();

2、遍历集合

不使用 Lambda 表达式的代码如下所示。

List list = Arrays.asList("Hello","World","Java");for(String str:list){
  System.out.println(str);
}

使用 Lambda 表达式的代码如下所。

List list = Arrays.asList("Hello","World","Java");list.forEach(str-> System.out.println(str));

双冒号 ::  表示方法引用,可以引用其他方法。

List list = Arrays.asList("Hello","World","Java");list.forEach(System.out::println);

运行结果如下图所示。

b8f943ed78c34759748cf0a902eb59db.png

Java8 针对数据处理提供了 Stream API,让开发者能够以声明的方式来处理数据,Stream 对数据的处理类似于 SQL 语句查询数据库,将数据集合抽象成一种流,提供传输流的管道,并且可以在管道的节点上添加处理,如过滤、排序等,常用方法如下所示。

3、filter 过滤

filter() 方法是 Stream 提供的对数据进行过滤的 API,需要结合 Lambda 表达式来处理,比如过滤出目标集合中长度大于等于 5 的字符串,具体操作如下所示。

List list = Arrays.asList("Hello","World","Java");list.stream().filter(str->str.length()>=5).forEach(str-> System.out.println(str));

运行结果如下图所示。

2ceebbb58babf1c8009824cf0550d9af.png

4、Predicate 多条件过滤

如果需要通过多个条件对集合进行过滤,可以使用 Predicate 来处理,Predicate 可以定义具体的过滤条件,调用多次 filter() 方法,通过传入不同的 Predicate 对象来进行过滤,具体操作如下所示。

List list = Arrays.asList("Hello","World","Java");
Predicate predicate1 = str->str.length()>=5;
Predicate predicate2 = str->str.startsWith("H");list.stream()
  .filter(predicate1)
  .filter(predicate2)
  .forEach(str-> System.out.println(str));

运行结果如下图所示。

e4c7a08cca9238d165a42d70cef591ee.png

除了上述方法,也可以调用 Predicate 对象的 and() 方法,对多个 Predicate 对象进行且运算,或者用 or() 进行或运算,如下所示。

List list = Arrays.asList("Hello","World","Java");
Predicate predicate1 = str->str.length()>=5;
Predicate predicate2 = str->str.startsWith("H");list.stream()
  .filter(predicate1.and(predicate2))
  .forEach(str-> System.out.println(str));

运行结果如下图所示。

e4c7a08cca9238d165a42d70cef591ee.png

同时也可将 Predicate 作为参数传递给目标方法,具体操作如下所示。

public class Test {
    public static void main(String[] args) {
        List list = Arrays.asList("Hello","World","Java");//输出以J开头的字符串
        test(list,(str)->str.startsWith("J"));//输出以a结尾的字符串
        test(list,(str)->str.endsWith("a"));//输出长度大于等于5的字符串
        test(list,(str)->str.length()>=5);//输出全部字符串
        test(list,(str)->true);//不输出
        test(list,(str)->false);
    }public static void test(List list, Predicate predicate){for(String str:list){if(predicate.test(str)){
                System.out.println(str);
            }
        }
    }
}

运行结果如下图所示。

cd9e47a542c296755ef86f062ed79ab4.png

5、limit 截取

使用 limit() 方法可以对数据集合进行截取,原理与 SQL 语句的 limit 一致,具体操作如下所示。

List list = Arrays.asList("Hello","World","Java");list.stream()
        .limit(2)
        .forEach(str-> System.out.println(str));

运行结果如下图所示。

ffeb43addf70a413ef6820c81a3437a1.png

limit() 也可以结合 filter() 来使用,如下所示。

List list = Arrays.asList("Hello","World","Java");list.stream()
  .filter(str->str.length()>=5)
  .limit(1)
  .forEach(str-> System.out.println(str));

运行结果如下图所示。

e4c7a08cca9238d165a42d70cef591ee.png

6、sorted 排序

使用 sorted() 方法可以对目标集合的数据进行排序,如下所示。

List list = Arrays.asList(1,6,2,3,5,4);list.stream()
  .sorted()
  .forEach(num-> System.out.println(num));

运行结果如下图所示。

08f516644d0988ed728b2d2addf40d20.png

默认是升序排列,可通过添加 Comparator.reverseOrder() 进行降序排列,如下所示。

List list = Arrays.asList(1,6,2,3,5,4);list.stream()
  .sorted(Comparator.reverseOrder())
  .forEach(num-> System.out.println(num));

运行结果如下图所示。

cc4fd0835df8689756824193377269a9.png

7、max 返回集合最大值,min 返回集合最小值

需要注意的是 max() 和 min() 的返回值是 Optional 类型,Optional 也是 Java8 提供的新特性,Optional 类是一个可以为 null 的容器对象,需要调用 get() 方法取出容器内的数据,具体操作如下所示。

List list = Arrays.asList(1,6,2,3,5,4);
System.out.println(list.stream().max(Integer::compareTo).get());

运行结果如下图所示。

d884e89a3ca73415bb0faf9a868c20ba.png

List list = Arrays.asList(1,6,2,3,5,4);
System.out.println(list.stream().min(Integer::compareTo).get());

运行结果如下图所示。

6df6004dc5641919a46c41a84979653c.png

8、map 对集合中元素进行特定操作

如集合中的每个元素 +10 之后输出,具体操作如下所示。

List list = Arrays.asList(1,6,2,3,5,4);list.stream()
  .map(num->num+10)
  .forEach(num-> System.out.println(num));

运行结果如下图所示。

cca7b06eb09e380336650d0ea6c537fe.png

9、reduce 对集合中元素进行特定操作

reduce() 和 map() 一样,都可以对集合中元素进行操作,区别在于 reduce() 是将所有元素按照传入的逻辑进行处理,并将结果合并成一个值返回,如返回集合所有元素之和,操作如下所示。

List list = Arrays.asList(1,6,2,3,5,4);
System.out.println(list.stream().reduce((sum,num)->sum+num).get());

需要注意的是 reduce() 的返回值是 Optional 类型,需要调用 get() 方法取出容器内的数据,运行结果如下图所示。

7c2e7fd7acbcbe6110d3057c650595c6.png

10、collection 基于目标集合的元素生成新集合

从目标集合中取出所有的奇数生成一个新的集合,具体操作如下所示。

List list = Arrays.asList(1,6,2,3,5,4);List list2 = list.stream()
  .filter(num->num%2!=0)
  .collect(Collectors.toList());
list2.forEach(num-> System.out.println(num));

运行结果如下图所示。

6c237388c1cd2f9f1f7e7e8baf3a132e.png

8a40c4876bb1a1923c7e4557a0d13856.png

435400a6e6f2d130eaae95d95c1ba147.png

【框架合集】SpringMVC教程汇总

【框架合集】MyBatis教程汇总

【框架合集】Spring教程汇总

【框架整合】SSM教程

【十套项目源码】

【BAT面试真题】

1a7c5670ee3057530617b20eac1d822f.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值