案例需求
按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
把集合中所有以"张"开头的元素存储到一个新的集合
把"张"开头的集合中的长度为3的元素存储到一个新的集合
遍历上一步得到的集合
原始方式示例代码
- public class MyStream1 {
- public static void main(String[] args) {
- //集合的批量添加
- ArrayList
list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); - //list.add()
-
- //遍历list1把以张开头的元素添加到list2中。
- ArrayList
list2 = new ArrayList<>(); - for (String s : list1) {
- if(s.startsWith("张")){
- list2.add(s);
- }
- }
- //遍历list2集合,把其中长度为3的元素,再添加到list3中。
- ArrayList
list3 = new ArrayList<>(); - for (String s : list2) {
- if(s.length() == 3){
- list3.add(s);
- }
- }
- for (String s : list3) {
- System.out.println(s);
- }
- }
- }
使用Stream流示例代码
- public class StreamDemo {
- public static void main(String[] args) {
- //集合的批量添加
- ArrayList
list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); -
- //Stream流
- list1.stream().filter(s->s.startsWith("张"))
- .filter(s->s.length() == 3)
- .forEach(s-> System.out.println(s));
- }
- }
Stream流的好处
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
Stream流把真正的函数式编程风格引入到Java中
代码简洁
Stream流的思想
Stream流的三类方法
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作
一次操作完毕之后,还可以继续进行其他操作
终结方法
一个Stream流只能有一个终结方法
是流水线上的最后一个操作
生成Stream流的方式
Collection体系集合
使用默认方法stream()生成流, default Stream
Map体系集合
把Map转成Set集合,间接的生成流
数组
通过Arrays中的静态方法stream生成流
同种数据类型的多个数据
通过Stream接口的静态方法of(T... values)生成流
代码演示
- public class StreamDemo {
- public static void main(String[] args) {
- //Collection体系的集合可以使用默认方法stream()生成流
- List
list = new ArrayList(); - Stream
listStream = list.stream(); -
- Set
set = new HashSet(); - Stream
setStream = set.stream(); -
- //Map体系的集合间接的生成流
- Map
map = new HashMap(); - Stream
keyStream = map.keySet().stream(); - Stream
valueStream = map.values().stream(); - Stream
> entryStream = map.entrySet().stream(); -
- //数组可以通过Arrays中的静态方法stream生成流
- String[] strArray = {"hello","world","java"};
- Stream
strArrayStream = Arrays.stream(strArray); -
- //同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
- Stream
strArrayStream2 = Stream.of("hello", "world", "java"); - Stream
intStream = Stream.of(10, 20, 30); - }
- }
概念
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
常见方法
方法名 | 说明 |
---|---|
Stream | 用于对流中的数据进行过滤 |
Stream | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static | 合并a和b两个流为一个流 |
Stream | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
filter代码演示
- public class MyStream3 {
- public static void main(String[] args) {
- // Stream
filter(Predicate predicate):过滤 - // Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
-
- ArrayList
list = new ArrayList<>(); - list.add("张三丰");
- list.add("张无忌");
- list.add("张翠山");
- list.add("王二麻子");
- list.add("张良");
- list.add("谢广坤");
-
- //filter方法获取流中的 每一个数据.
- //而test方法中的s,就依次表示流中的每一个数据.
- //我们只要在test方法中对s进行判断就可以了.
- //如果判断的结果为true,则当前的数据留下
- //如果判断的结果为false,则当前数据就不要.
- // list.stream().filter(
- // new Predicate
() { - // @Override
- // public boolean test(String s) {
- // boolean result = s.startsWith("张");
- // return result;
- // }
- // }
- // ).forEach(s-> System.out.println(s));
-
- //因为Predicate接口中只有一个抽象方法test
- //所以我们可以使用lambda表达式来简化
- // list.stream().filter(
- // (String s)->{
- // boolean result = s.startsWith("张");
- // return result;
- // }
- // ).forEach(s-> System.out.println(s));
-
- list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
-
- }
- }
limit&skip代码演示
- public class StreamDemo02 {
- public static void main(String[] args) {
- //创建一个集合,存储多个字符串元素
- ArrayList
list = new ArrayList(); -
- list.add("林青霞");
- list.add("张曼玉");
- list.add("王祖贤");
- list.add("柳岩");
- list.add("张敏");
- list.add("张无忌");
-
- //需求1:取前3个数据在控制台输出
- list.stream().limit(3).forEach(s-> System.out.println(s));
- System.out.println("--------");
-
- //需求2:跳过3个元素,把剩下的元素在控制台输出
- list.stream().skip(3).forEach(s-> System.out.println(s));
- System.out.println("--------");
-
- //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
- list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
- }
- }
concat&distinct代码演示
- public class StreamDemo03 {
- public static void main(String[] args) {
- //创建一个集合,存储多个字符串元素
- ArrayList
list = new ArrayList(); -
- list.add("林青霞");
- list.add("张曼玉");
- list.add("王祖贤");
- list.add("柳岩");
- list.add("张敏");
- list.add("张无忌");
-
- //需求1:取前4个数据组成一个流
- Stream
s1 = list.stream().limit(4); -
- //需求2:跳过2个数据组成一个流
- Stream
s2 = list.stream().skip(2); -
- //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
- // Stream.concat(s1,s2).forEach(s-> System.out.println(s));
-
- //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
- Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
- }
- }
概念
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
常见方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
代码演示
- public class MyStream5 {
- public static void main(String[] args) {
- ArrayList
list = new ArrayList<>(); - list.add("张三丰");
- list.add("张无忌");
- list.add("张翠山");
- list.add("王二麻子");
- list.add("张良");
- list.add("谢广坤");
-
- //method1(list);
-
- // long count():返回此流中的元素数
- long count = list.stream().count();
- System.out.println(count);
- }
-
- private static void method1(ArrayList
list) { - // void forEach(Consumer action):对此流的每个元素执行操作
- // Consumer接口中的方法void accept(T t):对给定的参数执行此操作
- //在forEach方法的底层,会循环获取到流中的每一个数据.
- //并循环调用accept方法,并把每一个数据传递给accept方法
- //s就依次表示了流中的每一个数据.
- //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
- list.stream().forEach(
- new Consumer
() { - @Override
- public void accept(String s) {
- System.out.println(s);
- }
- }
- );
-
- System.out.println("====================");
- //lambda表达式的简化格式
- //是因为Consumer接口中,只有一个accept方法
- list.stream().forEach(
- (String s)->{
- System.out.println(s);
- }
- );
- System.out.println("====================");
- //lambda表达式还是可以进一步简化的.
- list.stream().forEach(s->System.out.println(s));
- }
- }
概念
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
常用方法
方法名 | 说明 |
---|---|
R collect(Collector collector) | 把结果收集到集合中 |
工具类Collectors提供了具体的收集方式
方法名 | 说明 |
---|---|
public static | 把元素收集到List集合中 |
public static | 把元素收集到Set集合中 |
public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
代码演示
- // toList和toSet方法演示
- public class MyStream7 {
- public static void main(String[] args) {
- ArrayList
list1 = new ArrayList<>(); - for (int i = 1; i <= 10; i++) {
- list1.add(i);
- }
-
- list1.add(10);
- list1.add(10);
- list1.add(10);
- list1.add(10);
- list1.add(10);
-
- //filter负责过滤数据的.
- //collect负责收集数据.
- //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
- //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
- List
list = list1.stream().filter(number -> number % 2 == 0) - .collect(Collectors.toList());
-
- System.out.println(list);
-
- Set
set = list1.stream().filter(number -> number % 2 == 0) - .collect(Collectors.toSet());
- System.out.println(set);
- }
- }
- /**
- Stream流的收集方法 toMap方法演示
- 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
- "zhangsan,23"
- "lisi,24"
- "wangwu,25"
- 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
- */
- public class MyStream8 {
- public static void main(String[] args) {
- ArrayList
list = new ArrayList<>(); - list.add("zhangsan,23");
- list.add("lisi,24");
- list.add("wangwu,25");
-
- Map
map = list.stream().filter( - s -> {
- String[] split = s.split(",");
- int age = Integer.parseInt(split[1]);
- return age >= 24;
- }
-
- // collect方法只能获取到流中剩余的每一个数据.
- //在底层不能创建容器,也不能把数据添加到容器当中
-
- //Collectors.toMap 创建一个map集合并将数据添加到集合当中
-
- // s 依次表示流中的每一个数据
-
- //第一个lambda表达式就是如何获取到Map中的键
- //第二个lambda表达式就是如何获取Map中的值
- ).collect(Collectors.toMap(
- s -> s.split(",")[0],
- s -> Integer.parseInt(s.split(",")[1]) ));
-
- System.out.println(map);
- }
- }