Lambda&Stream

Lambda&Stream

- 能够掌握Lambda表达式的标准格式与省略格式(重点)
    作用:简化函数式接口的匿名内部类	
	()->{}
	(参数)->{重写接口中的抽象方法的方法体}
	(int a,int b)->{}==>省略数据类型 (a,b)->{}
	(int a)->{}==>省略数据类型 a->{}
	a->{只有一行代码}==>a->代码(return ; {} 一起省略)
- 能够通过集合、映射或数组方式获取流(重点)
	Collection集合中方法default Stream<E> stream()直接把集合转换为StreamArrayList<Integer> list = new ArrayList<>();
        Stream<Integer> stream1 = list.stream();
	Stream接口中的静态方法static <T> Stream<T> of(T... values) 把数组转换为StreamStream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8);
		String[] arr1 = {"a", "b", "c"};
        Stream<String> stream3 = Stream.of(arr1);
- 能够掌握常用的流操作(重点)
	forEach:遍历
	count:统计个数
	filter:过滤
	limit:获取前n个
	skip:跳过前n个
	map:映射,把一种数据类型转换为另外一种数据类型
	concat:组合 把两个流组合为一个流
- 能够将流中的内容收集到集合和数组中(重点)
	List<String> list = stream.collect(Collectors.toList());
	Set<String> set = stream.collect(Collectors.toSet());
	Object[] arr = stream.toArray();

第一章 Lambda表达式

1.函数式编程思想概述

面向对象思想:

​ 做一件事情,找一个能够解决这个事情的对象,调用对象的方法来完成这件事情

函数式编程思想:

​ 重视的是结果,怎么做事情,不重视完成的过程,找谁来做

2.使用Lambda表达式简化多线程匿名内部类(重点)

package com.itheima.demo01Lambda;

/*
    使用Lambda表达式简化多线程匿名内部类(重点)
 */
public class Demo01Lambda {
    public static void main(String[] args) {
        //使用匿名内部类的方式创建一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程,正在执行线程任务!");
            }
        }).start();

        //使用Lambda表达式,简化匿名内部类
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"线程,正在执行线程任务!");
        }).start();
    }
}

3.Lambda表达式的语法(重点)

Lambda表达式的语法:

​ 由一些参数,一个箭头,一些代码组成

格式:

(参数列表)->{重写抽象方法的方法体}

Lambda表达式作用:简化函数式接口的匿名内部类

lambda表达式使用前提:必须有接口,接口中有且只能有一个抽象方法(函数式接口)

Lambda表达式是可推导,可省略:能推导出来,Lambda表达式重写的就是接口中唯一的抽象方法

  • (参数列表):重写抽象方法的参数
  • ->:传递(固定写法):可以把参数传递到方法体中使用
  • {}:重写抽象方法的方法体
Lambda表达式的基本格式
	( )->{ }   Runnable接口-->public abstract void run();
	一些参数,一个箭头,一些代码
	():重写接口中唯一抽象方法的参数列表,没有参数就空着,有多个参数使用逗号隔开
	->:传递,可以把参数传递给{ }方法体使用
	{ }:重写接口中唯一抽象方法的方法体
Lambda表达式的使用前提:
	1.必须有接口
	2.接口中只能有且仅有一个抽象方法(函数式接口)     
注意:
	Lambda表达式是可推导可省略
	Lambda表达式的目的就是重写接口中唯一的抽象方法
	接口的方法只有一个,可以推导出重写的就是接口中唯一的抽象方法,所以可以简化代码   

4.使用Lambda表达式重写有参数有返回值的方法(重点)

需求:
创建一个数组,数组的类型使用Person
创建3个Person对象,存储到数组中
使用Arrays数组工具类中的方法sort,根据比较器产生的规则对Person对象进行排序(年龄升序)

package com.itheima.demo01Lambda;

import java.util.Arrays;
import java.util.Comparator;

/*
    使用Lambda表达式重写有参数有返回值的方法(重点)
    需求:
        创建一个数组,数组的类型使用Person
        创建3个Person对象,存储到数组中
        使用Arrays数组工具类中的方法sort,根据比较器产生的规则对Person对象进行排序(年龄升序)
    java.util.Arrays:数组工具类
        static  void  sort(T[] a, Comparator c)
            根据指定比较器产生的顺序对指定对象数组进行排序。
 */
public class Demo02Lambda {
    public static void main(String[] args) {
        //创建一个数组,数组的类型使用Person
        Person[] arr = new Person[3];
        //创建3个Person对象,存储到数组中
        arr[0] = new Person("关羽",28);
        arr[1] = new Person("刘备",38);
        arr[2] = new Person("张飞",18);
        //使用Arrays数组工具类中的方法sort,根据比较器产生的规则对Person对象进行排序(年龄升序)
        Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //排序的规则 o1-o2:升序  o2-o1:降序
                return o1.getAge()-o2.getAge();
            }
        });
        //遍历数组
        for (Person p : arr) {
            System.out.println(p);
        }
        //使用Lambda表达式,简化Comparator接口的匿名内部类
        Arrays.sort(arr,(Person o1,Person o2)->{
            //根据年龄降序排序
            return o2.getAge()-o1.getAge();
        });
        System.out.println("---------------------------------------");
        //遍历数组
        for (Person p : arr) {
            System.out.println(p);
        }
    }
}
package com.itheima.demo01Lambda;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

5.Lambda表达式简化格式

Lambda表达式使用前提:有接口,接口中有且仅有一个抽象方法(函数式接口)
Lambda表达式是可推导,可以省略的
可以推导出,Lambda表达式重写的就是接口中唯一的抽象方法
也可以推导出方法的参数和方法有没有返回值,可以可以对参数和返回值在进行简化
格式:
	(参数列表)->{重写抽象方法的方法体}
简化:
	1.(参数列表):参数列表的数据类型是可以推导出来的,可以省略
		(int a)-->(a)
		(int a,String s)-->(a,s)
	2.(参数列表):参数列表中只有一个参数,()小括号也可以省略,但是参数列表没有参数,()小括号不能省略
		(int a)-->(a)-->a
		(int a,String s)-->a,s 错误,两个或者两个以上的参数不能省略()
		()-->不能省略-->()
	3.{重写抽象方法的方法体}:重写的方法体,如果只有一行代码(java中行是以分号隔开的)
		无论方法是否有返回值
		{ }和一行代码结束的分号(;)return关键字可以省略不写
		但是他们必须一起省略
package com.itheima.demo01Lambda;

import java.util.Arrays;

/*
    Lambda表达式简化格式
 */
public class Demo03Lambda {
    public static void main(String[] args) {
        //实现多线程的Lambda表达式
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"线程正在执行线程任务!");
            System.out.println(Thread.currentThread().getName()+"线程正在执行线程任务!");
            System.out.println(Thread.currentThread().getName()+"线程正在执行线程任务!");
            System.out.println(Thread.currentThread().getName()+"线程正在执行线程任务!");
        }).start();

        //简化lambda表达式 参数列表:只有一个()不能省略 方法体:省略的{ }和;
        new Thread(()->System.out.println(Thread.currentThread().getName()+"线程正在执行线程任务!")).start();

        //创建一个数组,数组的类型使用Person
        Person[] arr = new Person[3];
        //创建3个Person对象,存储到数组中
        arr[0] = new Person("关羽",28);
        arr[1] = new Person("刘备",38);
        arr[2] = new Person("张飞",18);
        //使用Arrays数组工具类中的方法sort,根据比较器产生的规则对Person对象进行排序(年龄升序)
        Arrays.sort(arr,(Person o1,Person o2)->{
            return o1.getAge()-o2.getAge();
        });
        //简化Lambda表达式 参数:省略数据类型   方法体:{ } return ;
        Arrays.sort(arr,(o1,o2)-> o1.getAge()-o2.getAge());
    }
}

第二章 Stream流

1.Stream流概述

我们可以把集合|数组,转换为Stream流,使用Stream流中的方法,对集合|数组进行操作

2.Stream流的基本体验

需求:

List list= new ArrayList<>();

Collections.addAll(list,“张无忌”,“周芷若”,“赵敏”,“张三丰”,“张翠山”,“灭绝师太”,“张三”);

1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中

2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中

3.对最后得到的集合进行遍历

package com.itheima.demo02Stream;

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

/*
    不使用Stream流,使用集合遍历的方式完成需求
 */
public class Demo01List {
    public static void main(String[] args) {
        List<String> list= new ArrayList<>();
        Collections.addAll(list,"张无忌","三张","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");

        //1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
        List<String> zhangList= new ArrayList<>();
        for (String s : list) {
            if(s.startsWith("张")){
                zhangList.add(s);
            }
        }
        System.out.println(zhangList);//[张无忌, 张三丰, 张翠山, 张三]

        //2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
        List<String> sanList= new ArrayList<>();
        for (String s : zhangList) {
            if(s.length()==3){
                sanList.add(s);
            }
        }

        //3.对最后得到的集合进行遍历
        for (String s : sanList) {
            System.out.println(s);
        }
    }
}
package com.itheima.demo02Stream;

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

/*
    使用Stream流完成需求
    Stream流可以使我们的代码更加优雅==>简化
 */
public class Demo02Stream {
    public static void main(String[] args) {
        List<String> list= new ArrayList<>();
        Collections.addAll(list,"张无忌","三张","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
        //1.首先晒选出所有姓张的人,把姓张的人存储到一个新的集合中
        //2.筛选名字中是3个字的人,把名字是3个字的人存储到一个新的集合中
        //3.对最后得到的集合进行遍历
        //把集合转换为Stream流,使用Stream流中的方法操作
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length()==3).forEach(s -> System.out.println(s));
    }
}

3.流式思想概述

流式思想:流水线

Lambda&Stream_第1张图片

4.获取Stream流的方式(重点)

package com.itheima.demo02Stream;

import java.util.*;
import java.util.stream.Stream;

/*
    获取Stream流的方式(重点)
    1.在JDK1.8版本之后,Collection接口中,定义了一个方法叫stream,用于把集合转换为Stream流对象
        default Stream stream() 返回以此集合作为源的顺序 Stream 。
        Collection接口下的所有的集合(ArrayList,LinkedList,HashSet)都可以使用此方法,获取Stream流
        注意:Map集合不能转换为Stream流的
    2.在JDK1.8版本之后,增加一个接口名字Stream,在接口中有一个静态方法叫of,用于把可变参数(数组)转换为Stream流
        java.util.stream.Stream接口
        静态方法:
            static  Stream of(T... values) 方法的参数可以传递可变参数,也可以传递数组
            可变参数的底层就是一个数组,使用数组来接收传递的不同个数的参数
            可变参数作用:可以接收任意同种数据类型的参数(0个,1个,2个...10000个...)
 */
public class Demo03Stream {
    public static void main(String[] args) {
        show02();
    }

    /*
        使用静态of方法,把可变参数(数组),转换为Stream流
     */
    private static void show02() {
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
        Stream<String> stream3 = Stream.of("你好", "我好", "大家好", "才是真的好");
        //可变参数底层采用的数组,所以可以传递可变参数方法,都可以传递数组
        String[] arr1 = {"你好", "我好", "大家好", "才是真的好"};
        Stream<String> stream4 = Stream.of(arr1);
        //可变参数的数组类型必须是包装类
        int[] arr2 = {1,2,3,4,5};
        //把arr2这个数组,作为一个元素转换为Stream流
        Stream<int[]> stream5 = Stream.of(arr2);
        System.out.println(stream5.count());//1 统计个数

        Integer[] arr3 = {1,2,3,4,5};
        Stream<Integer> stream6 = Stream.of(arr3);
        System.out.println(stream6.count());//5 统计个数
    }

    /*
        把Collection接口下的集合转换为Stream流
        注意:
            Stream流是有泛型的,泛型跟着集合走
     */
    private static void show01() {
        ArrayList<String> list = new ArrayList<>();
        //把ArrayList集合转换为Stream流
        Stream<String> stream1 = list.stream();

        LinkedList<Integer> linked = new LinkedList<>();
        //把LinkedList集合转换为Stream流
        Stream<Integer> stream2 = linked.stream();

        HashSet<Double> set = new HashSet<>();
        //把HashSet集合转换为Stream流
        Stream<Double> stream3 = set.stream();

        HashMap<String,Integer> map = new HashMap<>();
        //注意:Map集合不能转换为Stream流的
        //map.stream();//Cannot resolve method 'stream()'

        Set<String> keySet = map.keySet();
        //可以把Map集合中所有的key转换为Stream流
        Stream<String> stream4 = keySet.stream();

        Collection<Integer> values = map.values();
        //可以把Map集合中所有的value转换为Stream流
        Stream<Integer> stream5 = values.stream();

        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        //可以把Map集合中所有的entry对象转换为Stream流
        Stream<Map.Entry<String, Integer>> stream6 = entrySet.stream();
    }
}

5.Stream的常用方法(重点)

流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

  • 终结方法:方法的返回值类型不再是Stream接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用。本小节中,终结方法包括countforEach方法。
  • 非终结方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为非终结方法。)

函数拼接与终结方法

在上述介绍的各种方法中,凡是返回值仍然为Stream接口的为函数拼接方法,它们支持链式调用;而返回值不再为Stream接口的为终结方法,不再支持链式调用。如下表所示:

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

备注:本小节之外的更多方法,请自行参考API文档。

1).forEach方法:用于遍历

package com.itheima.demo03StreamMethod;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;

/*
   Stream流中的常用方法_forEach:用于遍历Stream流中的元素
       void forEach​(Consumer action) 对此流的每个元素执行操作。
       参数:
           Consumer action:是一个消费型的接口,参数可以传递Lambda表达式
           唯一的抽象方法:
               void accept​(T t) :消费一个指定泛型类型的数据
   注意:
       forEach方法是一个终结方法,没有返回值;也不能使用链式编程调用Stream流中的其他方法了
*/
public class Demo01forEach {
    public static void main(String[] args) {
        List<String> list= new ArrayList<>();
        Collections.addAll(list,"张无忌","三张","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
        //把List集合转换为Stream流
        Stream<String> stream = list.stream();
        //forEach方法参数传递的是Consumer接口的匿名内部类对象
        /*stream.forEach(new Consumer() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/
        
        //Consumer接口是一个函数式接口,所以可以使用Lambda表达式,简化Consumer接口匿名内部类
        /*
            IllegalStateException: stream has already been operated upon or closed
            抛出非法状态异常:Stream流对象只能使用一次,使用完毕就会被销毁了,就不能在使用了
         */
        /*stream.forEach((String s)->{
            System.out.println(s);
        });*/

        //简化Stream流对象
        stream.forEach(s -> System.out.println(s));
    }
}

2).count方法:统计个数

package com.itheima.demo03StreamMethod;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

/*
   Stream流中的常用方法_count方法:统计个数
       long count​() 返回此流中的元素数。
   注意:
       count方法是一个终结方法,返回值类型是long类型;也不能使用链式编程调用Stream流中的其他方法了
*/
public class Demo02count {
    public static void main(String[] args) {
        //使用Stream接口中的静态方法of获取Stream流对象
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        long c1 = stream1.count();
        System.out.println("c1:"+c1);//c1:9

        List<String> list= new ArrayList<>();
        Collections.addAll(list,"张无忌","三张","周芷若","赵敏","张三丰","张翠山","灭绝师太","张三");
        Stream<String> stream2 = list.stream();
        long c2 = stream2.count();
        System.out.println("c2:"+c2);//c2:8
    }
}

3).filter方法:过滤

package com.itheima.demo03StreamMethod;

import java.util.function.Predicate;
import java.util.stream.Stream;

/*
   Stream流中的常用方法_filter方法:用于过滤Stream流中的元素
       Stream filter​(Predicate predicate)
       参数:
           Predicate predicate:函数式接口,参数传递lambda表达式
           唯一的抽象方法:
               boolean test​(T t) 用于对接口指定泛型类型的数据进行判断
   注意:
        filter方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo03filter {
    public static void main(String[] args) {
        //获取Stream流对象
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊", "灰太狼", "红太狼", "小灰灰");
        //需求:对stream中的元素进行过滤,只要包含"羊羊"的元素,存储到一个新的Stream流中
        /*Stream stream2 = stream.filter(new Predicate() {
            @Override
            public boolean test(String s) {
                //返回true:满足条件,把元素添加到新的流中  返回false:不满足条件,把元素过滤掉
                return s.contains("羊羊");
            }
        });*/

        //使用Lambda表达式简化Predicate接口的匿名内部类
        /*Stream stream2 = stream.filter((String s) -> {
            return s.contains("羊羊");
        });*/

        //简化Lambda表达式
        //Stream stream2 = stream.filter(s->s.contains("羊羊"));

        //System.out.println(stream2.count());//6
        //对stream2流对象进行遍历
        //stream2.forEach(s -> System.out.println(s));

        //链式编程
        stream.filter(s->s.contains("羊羊")).forEach(s -> System.out.println(s));
    }
}

4).limit方法:获取前n个元素

package com.itheima.demo03StreamMethod;

import java.util.stream.Stream;

/*
   Stream流中的常用方法_limit方法:获取前n个元素
       Stream limit​(long maxSize) 返回由此流的元素组成的流,截短长度不能超过 maxSize 。
       例如:
           limit(4);获取流中的前4个元素,把前4个元素存储到一个新的Steam流中
   注意:
   1.传递数字大于流的长度,返回流中所有的元素
   2.limit方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo04limit {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊", "灰太狼", "红太狼", "小灰灰");
        //把stream流中的前6个元素,存储到一个新的Stream流中返回
        //Stream stream2 = stream.limit(6);
        //遍历stream2流对象
        //stream2.forEach(s -> System.out.println(s));
        //链式编程
        stream.limit(6).forEach(s -> System.out.println(s));
    }
}

5).skip:跳过前n个元素

package com.itheima.demo03StreamMethod;

import java.util.stream.Stream;

/*
   Stream流中的常用方法_skip方法:跳过前n个元素
       Stream skip​(long n)
       skip(3)==> 跳过前3个元素,把剩余的元素存储到一个新的Stream流中
   注意:
       1.skip跳过的元素数量大于流中的个数,返回一个没有元素的空流
       2.skip方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo05skip {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊", "灰太狼", "红太狼", "小灰灰");
        //需求:使用skip方法跳过(6)元素,把剩余的三个狼存储到一个新的Stream流中
        //Stream stream2 = stream.skip(6);
        //遍历stream2流对象
        //System.out.println(stream2.count());//3
        //stream2.forEach(s -> System.out.println(s));
        //链式编程
        stream.skip(6).forEach(s -> System.out.println(s));
    }
}

6).map方法:映射,类型转换

Lambda&Stream_第2张图片

package com.itheima.demo03StreamMethod;

import java.util.function.Function;
import java.util.stream.Stream;

/*
   Stream流中的常用方法_map方法:映射,类型转换
        Stream map​(Function mapper)
       参数:
           Function mapper:函数式接口,可以传递Lambda表达式
           接口中唯一的抽象方法:
               R apply​(T t) 根据参数类型T获取类型R类型的返回值,用于类型转换 T转换R
   注意:
       map方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo06map {
    public static void main(String[] args) {
        //创建一个String类型的Stream流
        Stream<String> stream1 = Stream.of("11", "22", "33");
        //使用map方法,把String类型的Stream,转换为Integer类型的Stream流
        /*Stream stream2 = stream1.map(new Function() {
            @Override
            public Integer apply(String s) {
                //把字符串类型参数,转换为Integer类型返回
                return Integer.parseInt(s);
            }
        });*/

        //使用Lambda表达式简化函数式接口Function的匿名内部类
       /* Stream stream2 = stream1.map((String s) -> {
            return Integer.parseInt(s);
        });*/

        //简化Lambda表达式
        //Stream stream2 = stream1.map(s -> Integer.parseInt(s));

        //遍历stream2流对象
        //stream2.forEach(s-> System.out.println(s+10));//21,32,43

        //链式编程
        stream1.map(s -> Integer.parseInt(s)).forEach(s-> System.out.println(s+10));

        //创建一个String类型的Stream流
        Stream<String> stream3 = Stream.of("迪丽热巴", "古力娜扎", "佟丽娅");
        //把String类型的Stream流,转换为Person类型的Stream流
        //Stream stream4 = stream3.map(s -> new Person(s));
        //遍历stream4流对象
        //stream4.forEach(p-> System.out.println(p));
        //链式编程
        stream3.map(s -> new Person(s)).forEach(p-> System.out.println(p));
    }
}
package com.itheima.demo03StreamMethod;

public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

7).concat方法:组合

package com.itheima.demo03StreamMethod;

import java.util.stream.Stream;

/*
   Stream流中的常用方法_concat方法:组合,把两个Stream流,组合为一个新的Stream流
       static  Stream concat​(Stream a, Stream b)
   注意:
       concat方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)
*/
public class Demo07concat {
    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊");
        Stream<String> stream2 = Stream.of("迪丽热巴", "古力娜扎", "佟丽娅");
        //使用Stream接口中的静态方法concat,把以上两个流对象组合为一个新的流对象
        //Stream stream = Stream.concat(stream1, stream2);
        //遍历stream流对象
        //stream.forEach(s -> System.out.println(s));

        //链式编程
        Stream.concat(stream1,stream2).forEach(s -> System.out.println(s));
    }
}

6.综合案例(练习)

现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)
依次进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名,3个字成员的姓名存储到一个新的集合中
2. 第一个队伍筛选之后只要前3个人,把前3个人存储到一个新的集合中
3. 第二个队伍只要姓张的成员姓名,把姓张的成员姓名存储到一个新的集合中
4. 第二个队伍筛选之后不要前2个人,跳过前2个人,把其余的人存储到一个新的集合中
5. 将两个队伍合并为一个队伍,把两个过滤之后集合组合为一个新的集合
6. 根据姓名创建 Person 对象,Person对象存储到一个新的集合
7. 打印整个队伍的Person对象信息。

List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
one.add("张无忌");
one.add("周伯通");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");

1).不使用Stream流的方式

package com.itheima.demo04StreamTest;

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

/*
    现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)
    依次进行以下若干操作步骤:
    1. 第一个队伍只要名字为3个字的成员姓名,把3个字成员的姓名存储到一个新的集合中
    2. 第一个队伍筛选之后只要前3个人,把前3个人存储到一个新的集合中
    3. 第二个队伍只要姓张的成员姓名,把姓张的成员姓名存储到一个新的集合中
    4. 第二个队伍筛选之后不要前2个人,跳过前2个人,把其余的人存储到一个新的集合中
    5. 将两个队伍合并为一个队伍,把两个过滤之后集合组合为一个新的集合
    6. 根据姓名创建 Person 对象,把Person对象存储到一个新的集合
    7. 打印整个队伍的Person对象信息。
 */
public class Demo01List {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
        one.add("张无忌");
        one.add("周伯通");

        //1. 第一个队伍只要名字为3个字的成员姓名,把3个字成员的姓名存储到一个新的集合中
        List<String> one1 = new ArrayList<>();
        for (String s : one) {
            if(s.length()==3){
                one1.add(s);
            }
        }
        System.out.println(one1);//[宋远桥, 苏星河, 洪七公, 张无忌, 周伯通]

        //2. 第一个队伍筛选之后只要前3个人,把前3个人存储到一个新的集合中
        List<String> one2 = new ArrayList<>();
        for (int i = 0; i < 3; i++) {//i=0,1,2
            one2.add(one1.get(i));
        }
        System.out.println(one2);//[宋远桥, 苏星河, 洪七公]

        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");

        //3. 第二个队伍只要姓张的成员姓名,把姓张的成员姓名存储到一个新的集合中
        List<String> two1 = new ArrayList<>();
        for (String s : two) {
            if(s.startsWith("张")){
                two1.add(s);
            }
        }
        System.out.println(two1);//[张无忌, 张三丰, 张二狗, 张天爱, 张三]

        //4. 第二个队伍筛选之后不要前2个人,跳过前2个人,把其余的人存储到一个新的集合中
        List<String> two2 = new ArrayList<>();
        for (int i = 2; i < two1.size(); i++) {
            two2.add(two1.get(i));
        }
        System.out.println(two2);//[张二狗, 张天爱, 张三]

        //5. 将两个队伍合并为一个队伍,把两个过滤之后集合组合为一个新的集合
        //[宋远桥, 苏星河, 洪七公] [张二狗, 张天爱, 张三]
        List<String> all = new ArrayList<>();
        /*for (String s : one2) {
            all.add(s);
        }
        for (String s : two2) {
            all.add(s);
        }*/

        /*
            java.util.Collection接口
                boolean addAll(Collection c) 将指定集合中的所有元素添加到此集合
         */
        all.addAll(one2);
        all.addAll(two2);

        System.out.println(all);//[宋远桥, 苏星河, 洪七公, 张二狗, 张天爱, 张三]

        //6. 根据姓名创建 Person 对象,把Person对象存储到一个新的集合
        List<Person> list = new ArrayList<>();
        for (String s : all) {
            list.add(new Person(s));
        }

        //7. 打印整个队伍的Person对象信息。
        for (Person p : list) {
            System.out.println(p);
        }
    }
}

2).使用Stream流的方式

package com.itheima.demo04StreamTest;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/*
    现在有两个 ArrayList 集合存储队伍当中的多个成员姓名,要求使用Stream流的方式
    依次进行以下若干操作步骤:
    1. 第一个队伍只要名字为3个字的成员姓名,把3个字成员的姓名存储到一个新的集合中
    2. 第一个队伍筛选之后只要前3个人,把前3个人存储到一个新的集合中
    3. 第二个队伍只要姓张的成员姓名,把姓张的成员姓名存储到一个新的集合中
    4. 第二个队伍筛选之后不要前2个人,跳过前2个人,把其余的人存储到一个新的集合中
    5. 将两个队伍合并为一个队伍,把两个过滤之后集合组合为一个新的集合
    6. 根据姓名创建 Person 对象,把Person对象存储到一个新的集合
    7. 打印整个队伍的Person对象信息。
 */
public class Demo02Stream {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
        one.add("张无忌");
        one.add("周伯通");
        //1. 第一个队伍只要名字为3个字的成员姓名,把3个字成员的姓名存储到一个新的集合中
        //2. 第一个队伍筛选之后只要前3个人,把前3个人存储到一个新的集合中
        //把集合转换为Stream流
        Stream<String> oneStream = one.stream().filter(s -> s.length() == 3).limit(3);

        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");
        //3. 第二个队伍只要姓张的成员姓名,把姓张的成员姓名存储到一个新的集合中
        //4. 第二个队伍筛选之后不要前2个人,跳过前2个人,把其余的人存储到一个新的集合中
        //把集合转换为Stream流
        Stream<String> twoStream = two.stream().filter(s -> s.startsWith("张")).skip(2);

        //5. 将两个队伍合并为一个队伍,把两个过滤之后集合组合为一个新的集合
        //6. 根据姓名创建 Person 对象,把Person对象存储到一个新的集合
        //7. 打印整个队伍的Person对象信息。
        Stream.concat(oneStream,twoStream).map(s -> new Person(s)).forEach(p-> System.out.println(p));
        
        /*Stream.concat(
                one.stream().filter(s -> s.length() == 3).limit(3),
                two.stream().filter(s -> s.startsWith("张")).skip(2))
        .map(s -> new Person(s)).forEach(p-> System.out.println(p));*/
    }
}

7.收集Stream结果(重点)

把Stream流转换为集合或者把Stream流转换为数组

1).把Stream流转换为集合:收集到集合中

package com.itheima.demo05Stream;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*
    把Stream流转换为集合:收集到集合中
    可以使用Stream流中的方法collect​把Stream转换为集合
        R collect​(Collector collector)
        参数:
            Collector是一个接口,需要传递接口的实现类对象
    java.util.stream.Collectors:操作Collector的工具类
        static  Collector> toList​() 返回Collector接口的实现类对象,可以把Stream流转换为List集合
        static  Collector> toSet​()   返回Collector接口的实现类对象,可以把Stream流转换为Set集合
 */
public class Demo01StreamToCollection {
     public static void main(String[] args) {
         Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊","美羊羊");
         //把stream流对象转换为List:收集到List集合中==>1.有序  2.允许重复 3.包含带索引的方法
         //List list = stream.collect(Collectors.toList());
         //System.out.println(list);//[美羊羊, 喜羊羊, 沸羊羊, 慢羊羊, 暖羊羊, 懒羊羊, 美羊羊]

         //把stream流对象转换为Set:收集到Set集合中==>1.不允许存储重复元素 2.不包含带索引的方法
         Set<String> set = stream.collect(Collectors.toSet());
         System.out.println(set);//[美羊羊, 沸羊羊, 暖羊羊, 喜羊羊, 懒羊羊, 慢羊羊]
         System.out.println(set.getClass());//class java.util.HashSet
     }
}

2).把Stream流转换为数组:收集到数组中

package com.itheima.demo05Stream;

import java.util.stream.Stream;

/*
    将流中的元素收集到数组(将流转成数组)
    Stream接口中的方法
        Object[] toArray() 把Stream流转换为数组
 */
public class Demo02StreamToArray {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "沸羊羊", "慢羊羊", "暖羊羊", "懒羊羊","美羊羊");
        Object[] arr = stream.toArray();
        for (Object o : arr) {
            System.out.println(o);
        }
    }
}

你可能感兴趣的:(11,22,33,java)