Java基础学习笔记(十五)—— Sream流

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Sream流

1 Stream流初体验

  • 案例需求
    • 创建一个集合存储多个字符串元素
    • 把集合中所有以“张”开头的元素存储到一个新的集合
    • 把"张"开头的集合中的长度为3的元素存储到一个新的集合
    • 遍历上一步得到的集合
  • 示例代码
public static void main(String[] args) {
	//集合的批量添加
	ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
	//list.add()

	//遍历list1把以张开头的元素添加到list2中。
	ArrayList<String> list2 = new ArrayList<>();
	for (String s : list1) {
		if(s.startsWith("张")){
			list2.add(s);
		}
	}

	//遍历list2集合把其中长度为3的元素再添加到list3中。
	ArrayList<String> list3 = new ArrayList<>();
	for (String s : list2) {
		if(s.length() == 3){
			list3.add(s);
		}
	}
	for (String s : list3) {
		System.out.println(s);
	}

	System.out.println("=======================");
	
   //Stream流
	list1.stream().filter(s->s.startsWith("张"))
			.filter(s->s.length() == 3)
			.forEach(s-> System.out.println(s));
}

注意:List.of 是JDK9及以后的

2 Stream流概述

  • Stream流的好处
    • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义
    • Stream流把真正的函数式编程风格引入到Java中
    • 代码简洁
  • Stream流的三类方法
    • 获取Stream流
      • 创建一条流水线并把数据放到流水线上准备进行操作
    • 中间方法
      • 流水线上的操作
      • 一次操作完毕之后还可以继续进行其他操作
    • 终结方法
      • 一个Stream流只能有一个终结方法
      • 是流水线上的最后一个操作

3 生成Stream流

  • Collection体系集合
    • 使用默认方法stream()生成流 default Stream<E> stream()
  • Map体系集合
    • 把Map转成Set集合间接的生成流
  • 数组
    • 通过Arrays中的静态方法stream生成流
  • 同种数据类型的多个数据
    • 通过Stream接口的静态方法of(T… values)生成流
public static void main(String[] args) {
	//单列集合
	//method1();

	//双列集合
	//method2();

	//数组
	//method3();

	//同种数据类型的多个数据
	//method4();
}

private static void method4() {
	Stream.of(1,2,3,4,5,6,7,8).forEach(s-> System.out.println(s));
}

private static void method3() {
	int [] arr = {1,2,3,4,5};
	Arrays.stream(arr).forEach(s-> System.out.println(s));
}

private static void method2() {
	HashMap<String,Integer> hm = new HashMap<>();
	hm.put("zhangsan",23);
	hm.put("lisi",24);
	hm.put("wangwu",25);
	hm.put("zhaoliu",26);
	hm.put("qianqi",27);

	//双列集合不能直接获取Stream流
	//1.keySet
	//先获取到所有的键
	//再把这个Set集合中所有的键放到Stream流中
	//hm.keySet().stream().forEach(s-> System.out.println(s));


	//2.entrySet
	//先获取到所有的键值对对象
	//再把这个Set集合中所有的键值对对象放到Stream流中
	hm.entrySet().stream().forEach(s-> System.out.println(s));
}

private static void method1() {
	ArrayList<String> list = new ArrayList<>();
	list.add("aaa");
	list.add("bbb");
	list.add("ccc");

//        Stream<String> stream = list.stream();
//        stream.forEach(s-> System.out.println(s));
	list.stream().forEach(s-> System.out.println(s));
}

4 中间操作方法

中间操作的意思是执行完此方法之后Stream流依然可以继续执行其他操作

在这里插入图片描述

filter方法

public static void main(String[] args) {
//        Stream<T> filter​(Predicate predicate):过滤
//                Predicate接口中的方法	boolean test​(T t):对给定的参数进行判断返回一个布尔值

	ArrayList<String> 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<String>() {
//                    @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));
}

其他中间方法

public static void main(String[] args) {
	ArrayList<String> list = new ArrayList<>();
	list.add("张三丰");
	list.add("张无忌");
	list.add("张翠山");
	list.add("王二麻子");
	list.add("张良");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");


	//method1(list);
	//method2(list);
	//method3();
	//method4(list);


}

private static void method4(ArrayList<String> list) {
	//        Stream<T> distinct​():去除流中重复的元素。依赖(hashCode和equals方法)
	list.stream().distinct().forEach(s-> System.out.println(s));
}

private static void method3() {
	//static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流
	ArrayList<String> list = new ArrayList<>();
	list.add("张三丰");
	list.add("张无忌");
	list.add("张翠山");
	list.add("王二麻子");
	list.add("张良");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");
	list.add("谢广坤");

	ArrayList<String> list2 = new ArrayList<>();
	list2.add("张三丰");
	list2.add("张无忌");
	list2.add("张翠山");
	list2.add("王二麻子");
	list2.add("张良");
	list2.add("谢广坤");


//        Stream<String> stream1 = list.stream();
//        Stream<String> stream2 = list2.stream();
//
//        Stream<String> stream3 = Stream.concat(stream1, stream2);
//        stream3.forEach(s-> System.out.println(s));

	Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.println(s));
}

private static void method2(ArrayList<String> list) {
	//        Stream<T> skip​(long n):跳过指定参数个数的数据
	list.stream().skip(2).forEach(s-> System.out.println(s));
}

private static void method1(ArrayList<String> list) {
	//        Stream<T> limit​(long maxSize):截取指定参数个数的数据
	list.stream().limit(2).forEach(s-> System.out.println(s));
}

5 终结操作方法

终结操作的意思是执行完此方法之后Stream流将不能再执行其他操作

在这里插入图片描述

public static void main(String[] args) {
	ArrayList<String> 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<String> list) {
	//        void forEach​(Consumer action):对此流的每个元素执行操作
//                      Consumer接口中的方法	void accept​(T t):对给定的参数执行此操作
	//在forEach方法的底层,会循环获取到流中的每一个数据.
	//并循环调用accept方法,并把每一个数据传递给accept方法
	//s就依次表示了流中的每一个数据.
	//所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
	list.stream().forEach(
			new Consumer<String>() {
				@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));
}

6 收集操作方法

对数据使用Stream流的方式操作完毕后可以把流中的数据收集到集合中

常用方法

在这里插入图片描述

工具类Collectors提供了具体的收集方式

在这里插入图片描述

 /**
 * Stream流的收集方法
 * 练习:
 * 定义一个集合并添加一些整数1,2,3,4,5,6,7,8,9,10
 * 将集合中的奇数删除只保留偶数。
 * 遍历集合得到246810。
 */
public static void main(String[] args) {
	ArrayList<Integer> 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<Integer> list = list1.stream().filter(number -> number % 2 == 0)
			.collect(Collectors.toList());
	System.out.println(list);


	Set<Integer> set = list1.stream().filter(number -> number % 2 == 0)
			.collect(Collectors.toSet());
	System.out.println(set);
	
	// List和Set区别:Set有去重功能
}
/**
 * Stream流的收集方法
 *
 * 创建一个ArrayList集合并添加以下字符串。字符串中前面是姓名后面是年龄
 * "zhangsan,23"
 * "lisi,24"
 * "wangwu,25"
 * 保留年龄大于等于24岁的人并将结果收集到Map集合中姓名为键年龄为值
 */
 public static void main(String[] args) {
	ArrayList<String> list = new ArrayList<>();
	list.add("zhangsan,23");
	list.add("lisi,24");
	list.add("wangwu,25");

	Map<String, Integer> 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);
}

注意:

  • Stream流只能操作流中的数据而无法直接修改集合、数组等数据源中的数据

7 Stream流案例

案例需求

现在有两个ArrayList集合分别存储6名男演员名称和6名女演员名称要求完成如下的操作

  • 男演员只要名字为3个字的前三人
  • 女演员只要姓林的并且不要第一个
  • 把过滤后的男演员姓名和女演员姓名合并到一起
  • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

标准类演员类Actor已存在

测试类

public static void main(String[] args) {
	ArrayList<String>  manList = new ArrayList<>();
	manList.add("张国立");
	manList.add("张晋");
	manList.add("刘烨");
	manList.add("郑伊健");
	manList.add("徐峥");
	manList.add("王宝强");

	ArrayList<String>  womanList = new ArrayList<>();
	womanList.add("郑爽");
	womanList.add("杨紫");
	womanList.add("关晓彤");
	womanList.add("张天爱");
	womanList.add("杨幂");
	womanList.add("赵丽颖");

	//男演员只要名字为3个字的前两人
	Stream<String> stream1 = manList.stream().filter(name -> name.length() == 3).limit(2);

	//女演员只要姓杨的并且不要第一个
	Stream<String> stream2 = womanList.stream().filter(name -> name.startsWith("杨")).skip(1);


	Stream.concat(stream1,stream2).forEach(name -> {
		Actor actor = new Actor(name);
		System.out.println(actor);
	});
}
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java