Stream

引入

1.方法引用::

相当于创建Class类的实例对象class,通过实例对象class调用对应方法
1.构造器方法引用:Class::new(调用默认构造器)
2.类静态方法引用:Class::static_method
3.类普通方法引用:Class::method
4.实例方法引用:Instance::method

2.函数式接口@FunctionalInterface

  • 函数式接口只有1个抽象方法,不包括与Object方法重名的方法(从Object继承过来的抽象方法)
  • 函数式接口定义
@FunctionalInterface//函数式接口注解,表示支持函数式操作
interface Action<T> {
    void execute(T t);//有且仅有的抽象方法
}
  • 函数式接口使用
1.作为函数式接口中抽象方法的execute的实现
	Action action = System.out::println;
	action.execute("hello");

2.回调方式
	static void test(Action action, String str) {
	    action.execute(str);
	}
	test(System.out::println, "hello");

3.新无参无返回值方法替换函数式接口的唯一抽象函数(与唯一抽象函数同型都可以这样做)
	public void sleepMethod(){
		System.out.println("hello");
	}
	//相当于sleepMethod替代run
	new Thread(ClassName::sleepMethod).start();

3.谓词Predicate

  • 将函数作为参数传递
@Data//这是一个苹果类
class Apple {
    private String color;
    private int weight;
    public Apple(String color, int weight) {
        this.color = color;
        this.weight = weight;
    }
    public static boolean isGreenApple(Apple apple) {
        return "green".equals(apple.getColor());
    }
    public static boolean isHeavyApple(Apple apple) {
        return apple.getWeight() > 150;
    }
}

public class TestPredicate {
	//利用predicate.test判断是否满足条件
    static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> predicate) {
        List<Apple> list = new ArrayList<>();
        for (Apple apple : inventory) {
        	//注意predicate的test方法是抽象方法
            if (predicate.test(apple)) {
                list.add(apple);
            }
        }
        return list;
    }

    public static void main(String[] args) {
        String[] colors = {"green", "yellow", "red"};
        Random random = new Random();
        List<Apple> list = new ArrayList<>();
        for (int i = 1; i < 10; i++) {
            list.add(new Apple(colors[random.nextInt(colors.length)], random.nextInt(100)));
        }
        //以上是创建苹果操作

        //此处Apple中isGreenApple与Predicate的test同型(返回值相同,参数相同),可以直接使用Apple::isHeavyApple方式替代test,isHeavyApple中实现作为test中的实现
        //此处就是之前讲解过方法的方法引用
        System.out.println(filterApples(list, Apple::isGreenApple));
        System.out.println(filterApples(list, Apple::isHeavyApple));

        //合并两个查询条件
        Predicate<Apple> predicate1 = Apple::isGreenApple;//替代test()
        Predicate<Apple> predicate2 = Apple::isHeavyApple;
        System.out.println(filterApples(list, predicate1.or(predicate2)));
    }
}

原文指路

  • 将元素集合看成流Stream,流在管道中传输,可以在管道节点上进行处理
  • 不会存储元素,而是按需计算
  • 不改变数据源,中间操作都返回流对象本身
  • 延迟执行,只有执行终端操作时中间操作才执行
  • 一个流只能迭代一次

基本操作

1.其他操作说在前

  • Collectors
//Collector作为collect()的参数,直接使用Collectors提供的基础实现
1.toList() toMap() toSet() joining() counting() maxBy() minBy() reducing()...

2.groupingBy():分组操作
	Map<String, List<Record>> map = list.stream()
   		.collect(Collectors.groupingBy(Record::getCustomerID));
   		//groupingBy(分组属性),返回Map<分组属性类型,List<流中数据类型>>
   		
3.summarizingInt() summarizingLong() summarizingDouble():返回类XXXSummaryStatistics含统计操作,getMax() getMin()..
	DoubleSummaryStatistics summaryStatistics = records.parallelStream()
	    .filter(record -> record.getCountry().equals("United Kingdom"))
	    .collect(Collectors.summarizingDouble(Record::getQuantity));
	summaryStatistics.getMax();
	summaryStatistics.getMin();
	summaryStatistics.getAverage();
	...
-->mapToXXX中统计操作与XXXSummaryStatistics中统计操作的区别是
		mapToXXX只有用时才执行相应的统计操作
		XXXSummaryStatistics不管需要统计什么,都一次性将要统计的都统计了
		两者存在性能上的区别
  • Optional
1.Optional表示值存在或不存在,解决NullPointerException异常
2.常用方法
	isPresent():值存在返回true,反之false
	get():返回当前值,若值不存在会抛出异常
	orElse(T):值存在时返回该值,否则返回T的值
3.OptionalInt,OptionalLongOptionalDouble

2.生成操作

  • XXX.stream()
1.Arrays.stream(myArray)
2.为集合创建串行流
	list.stream();
	set.stream();
3.为集合创建并行流
	list.parallelStream();
	set.parallelStream();
4.Map间接生成流
	map.keySey().stream();
	map.values().stream();
	map.entrySet().stream();
5.文件生成流
	Stream<String> stream = Files.lines(Paths.get("data.txt"))
	//读取每一行生成流
  • Stream.of()
Stream.of(myArray);
Stream.of("11","22");
Stream.of(11,22,33);
  • Stream.empty()
Stream.empty()
  • Stream.iterate()
依次对新生成的值执行对应函数操作后生成流
	Stream.iterate(0, (x) -> x + 3)//生成流,首元素为0,之后依次加3
		.limit(4);
  • Stream.generate()
接受函数生成新的值组成流
	Stream.generate(Math :: random)//生成元素为0到1的随机数的流
	Stream.generate(() -> 1)//生成元素全为1的流
  • 读取文件到流并包装成对象返回对象集合
List<String> lines = Files.readAllLines(path);//Path
List<Record> records = lines.parallelStream()//创建并行流
        .skip(1)//跳过第0行
        .map(line -> line.split(";"))//按;分割,返回String[]
        .map(t -> new Record(t))//通过Record构造函数将结果数组包装成对象,t是数组,Record构造方法对数组操作
        .collect(Collectors.toList());//将对象转为list

3.中间操作

  • 普通操作
1.Stream<T> filter(Predicate predicate):对流中元素过滤,保留参数为ture的元素
	list.stream()
		.filter(s -> s.startsWith("王"))//筛选王开头字符串
		.filter(s -> s.length()==3)//筛选长度为3字符串
		.forEach(s -> System.out.println(s));
		
2.Stream<T> limit​(long maxSize):从前开始获取指定数量的流
	list.stream()
		.limit(3)//取前三个数据流
		.forEach(System.out::println);
		
3.Stream<T> skip​(long n):跳过前n个流,返回剩余的流
	list.stream()
		.skip(3)//跳过前三个数据流
		.forEach(System.out::println);
		
4.Stream<T> distinct​():返回去重后的流
	list.stream()
		.distinct()//对list中数据去重
		.forEach(System.out::println);
		
5.static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流
	Stream<String> s1 = list11.stream();
	Stream<String> s2 = list22.stream();
	Stream.concat(s1,s2)//合并s1与s2
		.forEach(System.out::println);
  • 聚合操作
1.Optional<T> max(Comparator comparator)
	//返回Integer集合中的最大值——自然排序
	Optional<Integer> max = list.stream()
		.max(Integer::compareTo);
	//返回Integer集合中的最大值——自定义排序
	Optional<Integer> max2 = list.stream()
		.max(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1.compareTo(o2);
			}
		});
	//返回字符串集合中最长元素
	Optional<String> max = list.stream()
		.max(Comparator.comparing(String::length));
	System.out.println("最长的字符串:" + max.get());
	
2.Optional<T> min(Comparator comparator)
3.long count()
  • 排序操作
1.Stream<T> sorted​():返回按自然顺序排序后的流
	list.stream()
		.sorted()//排序
		.forEach(System.out::println);
		
2.Stream<T> sorted​(Comparator comparator):返回根据提供的Comparator排序的流
	list.stream()
		.sorted((s11,s22)->s11.length()-s22.length())//内含排序规则
		.forEach(System.out::println); 

3.unordered()优化机制
	禁止排序unordered
		-->对每一个CPU上的数据去重,然后再合并这些CPU,再去重
	未禁止排序
		-->对所有CPU上的统一一起排序,排序后尽量让CPU中存放相同的数据(对所有CPU排序然后分到每个CPU,尽量让相同数据在同一CPU上),最后分别对每个CPU去重
  • 映射操作map
    在这里插入图片描述
1.<R> Stream<R> map(Function mapper):将流中的每个元素T映射为RStream<T> -> Stream<R>
	list.stream()
		.map(s -> Integer.parseInt(s))//将字符串类型流转成int型后返回
		.forEach(System.out::println);
	//方法引用改写
	list.stream()
		.map(Integer::parseInt)
			//此处难理解,但也好理解
			//parseInt方法替代Function函数式接口中唯一抽象方法apply
			//不用传参,流自己进去方里转int(就这么理解吧)
		.forEach(System.out::println);
		
2.IntStream mapToInt(ToIntFunction mapper):返回新流类型为IntStream,其中包含特定函数对此流结果进行操作,如
	int result = list.stream()
		.mapToInt(Integer::parseInt)
		.sum();//sum()返回流中数据总和,此方法是IntStream的
		//如max().getAsInt()或min().getAsInt()...
		//注意:经过以上统计操作后流已经空可,不可复用****
	System.out.println(result);
	
3.LongStream mapToLong(ToLongFunction mapper)
4.DoubleStream mapToDouble(ToDoubleFunction mapper)
  • 映射操作flatMap
    在这里插入图片描述
1.<R> Stream<R> flatMap(Function mapper):将流中的每个元素T映射为流,再把每个流连接成为新流,下面的代码好理解
	List<String> list = new ArrayList<>();
	list.add("aaa bbb ccc");
	list.add("ddd eee fff");
	list.add("ggg hhh iii");
	list = list.stream()
		.map(s -> s.split(" "))//将list中str按空格分割成数组 Stream<String> -> Stream<String[]>
			.flatMap(Arrays::stream)//将Stream<String[]>中数组中字符串都看成单独的流
			.collect(toList());

2.IntStream flatMapToInt(Function mapper)
3.LongStream flatMapToLong(Function mapper)
4.DoubleStream flatMapToDouble(Function mapper)
  • 发现操作
1.Optional<T> findFirst():返回流中第一个元素
2.Optional<T> findAny():串行流返回第一个元素,并行流返回其中一个元素
  • 匹配操作
1.boolean anyMatch(Predicate predicate):任意流满足参数条件返回true
	boolean b = list.stream()
		.anyMatch(person -> person.getAge()==20);
		
2.boolean allMatch(Predicate predicate):所有流满足参数条件返回true
	boolean result = list.stream()
		.allMatch(Person::isStudent);//此处使用方法引用将test替换成isStudent

3.boolean noneMatch(Predicate predicate):没有流满足参数条件返回true
	boolean result = list.stream()
		.noneMatch(Person::isStudent);
  • 归约操作
1.T reduce(T identity, BinaryOperator<T> accumulator):第一个参数表示初始值,第二个参数表示规约操作
	//计算年龄总和——1
	int age = list.stream()
		.reduce(0, (person1,person2)->person1.getAge()+person2.getAge());
	//计算年龄总和——2
	int sum = list.stream()
		.map(Person::getAge)
		.reduce(0, (a, b) -> a + b);
	//计算年龄总和——3
	int sum = list.stream()
		.map(Person::getAge)
		.reduce(0, Integer::sum);

2.Optional<T> reduce(BinaryOperator<T> accumulator):不含初始值,考虑结果不存在情况返回Optional,与上的不同就是再get以下获取结果
3.<U> U reduce(U identity,BiFunction accumulator,BinaryOperator<U> combiner);

4.终结操作

  • 一个流只能有一个终结操作,终结后流被用光,无法再被操作
  • forEach:迭代流中每个数据
1.void forEach(Consumer action):不按顺序迭代
2.void forEachOrdered(Consumer action):按顺序迭代
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值