Lambda表达式,Stream流

Lambda

前言

    当我们想要使用一个线程,我们其实并不想真的创建一个匿名内部类对象。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将 run 方法体内的代码传递给 Thread 类。

传统的使用一个线程

public class Test {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行!");
            }
        }).start();
    }
}

对于 Runnable 的匿名内部类用法,可以分析出几点内容:

  • Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心;
  • 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类;
  • 为了省去定义一个 RunnableImpl 实现类的麻烦,不得不使用匿名内部类;
  • 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;
  • 而实际上,似乎只有方法体才是关键所在

使用Lambda表达式写法

public class Test {
    public static void main(String[] args) {
        new Thread(()->System.out.println("多线程任务执行!")).start();
    }
}

这段代码和上面的传统写法功能一样,但却是肉眼可见的简单!!

使用Lambda表达式的前提

那程序在满足什么条件的时候才可以使用Lambda表达式呢??

  1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。 无论是JDK内置的 Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
  2. 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

备注:有且仅有一个抽象方法的接口,称为“函数式接口”。

Lambda表达式格式

    一个参数 一个箭头 一段代码

(参数类型 参数名)->{代码语句}//如果只有一条语句{}大括号也可以省略

格式说明:

  • 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔
  • 中间的一个箭头代表将前面的参数传递给后面的代码;
  • 大括号内的语法与传统方法体要求基本一致。

Lambda表达式的省略规则

在Lambda标准格式的基础上,使用省略写法的规则为:

  1. 小括号内参数的类型可以省略;
  2. 如果小括号内有且仅有一个参,则小括号可以省略;
  3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
    通过这些省略规则,可以尝试简化 -----使用Collections的sort方法对集合字符串排序

Stream

前言

试想一下,如果希望对集合中的元素进行筛选过滤:

筛选出集合中所有姓张的人,在到所有姓张的人中筛选名字长度是3个字的!

传统的方法你可能会这样

import java.util.ArrayList;
import java.util.List;

public class Demo02NormalFilter {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        List<String> zhangList = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("张")) {
                zhangList.add(name);
            }
        } 
        List<String> shortList = new ArrayList<>();
        for (String name : zhangList) {
            if (name.length() == 3) {
                shortList.add(name);
            }
        } for (String name : shortList) {
            System.out.println(name);
        }
    }
}

代码分析:
这段代码中含有三个循环,每一个作用不同:

  1. 首先筛选所有姓张的人;
  2. 然后筛选名字有三个字的人;
  3. 最后进行对结果进行打印输出。

每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环是做事情的方式,而不是目的。另一方面,使用线性循环就意味着只能遍历一次。如果希望再次遍历,只能再使用另一个循环从头开始。

当我们使用Stream后的代码

import java.util.ArrayList;
import java.util.List;
public class Demo03StreamFilter {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(System.out::println);
    }
}

我丢!怎么可以这么简单 ┗( ▔, ▔ )┛
直接阅读代码的字面意思就可以完美展示这段代码的功能:获取流、过滤姓张、过滤长度为3、逐一打印。

获取流方式

获取的方法比较简单

  • 所有的 Collection 集合都可以通过 stream 默认方法获取流;
  • Stream 接口的静态方法 of 可以获取数组对应的流

java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。
List集合举例

List<String> list = new ArrayList<>();

Stream<String> stream1 = list.stream();

of 方法的参数其实是一个可变参数,所以支持数组。
举例

String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
Stream<String> stream = Stream.of(array);

常用方法

终结方法:
    返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式
调用。终结方法包括 count 和 forEach 方法

非终结方法:
    返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其
余方法均为非终结方法。)

方法名 方法作用 方法种类 是否支持链式调用
count 统计个数 终结
forEach 逐一处理 终结
filter 过滤 函数拼接
limit 取用前几个 函数拼接
skip 跳过前几个 函数拼接
concat 组合 函数拼接

来个综合案例使用一下这些方法

/**
 * 现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,依次进行以下若干操作步骤:
 * 1. 第一个队伍只要名字为3个字的成员姓名;
 * 2. 第一个队伍筛选之后只要前3个人;
 * 3. 第二个队伍只要姓张的成员姓名;
 * 4. 第二个队伍筛选之后不要前2个人;
 * 5. 将两个队伍合并为一个队伍;
 * 7. 打印整个队伍的信息。
 */
class Test{
    public static void main(String[] args) {
        //第一个大部队
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张三","李四","王老五","赵四儿");

        //第二个大部队
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"胡歌","李易峰","彭于晏","蔡徐坤");

        //第一个队伍只要名字为3个字的成员姓名;  第一个队伍筛选之后只要前3个人;
        Stream<String> stream1 = list1.stream();
        Stream<String> streamOne = stream1.filter(s -> s.length() == 3).limit(3);



        //第二个队伍只要姓张的成员姓名;第二个队伍筛选之后不要前2个人;
        Stream<String> stream2 = list2.stream();
        Stream<String> streamTwo = stream2.filter(s -> s.startsWith("张")).skip(2);

        //将两个队伍合并为一个队伍;  打印整个队伍的信息。
        Stream.concat(streamOne,streamTwo).forEach(s -> System.out.println(s));

    }
}
发布了30 篇原创文章 · 获赞 39 · 访问量 2054

猜你喜欢

转载自blog.csdn.net/weixin_44564242/article/details/105090341