随机名言

Stream补充



最近看的项目使用Stream来操作集合,熟悉代码阶段就令人头大,来补课了


1. 常见的接口

我们常用Lambda来表达这些函数式接口,所以看着比较陌生,其实日常都有使用到。下面说明时会先给出源码,然后再给出使用事例


1.1 Consumer

传入参数,内部进行操作,没有返回值

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}
list.stream().forEach(s -> System.out.println(s));	// forEach(Consumer<? super T> action)

1.2 Function

传入参数,内部进行转换,有返回值

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}
list.stream().map(s -> s + "-");	// Stream<R> map(Function<? super T, ? extends R> mapper);

1.3 Supplier

创建一个容器并且返回出去

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
Collector toMap(Function keyMapper
			   ,Function valueMapper
			   ,BinaryOperator mergeFunction
			   ,Supplier<M> mapSupplier)

1.4 Predicate

传入参数,进行判断,返回boolean

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
list.stream().anyMatch(s -> s >= 10);	// anyMatch(Predicate<? super T> predicate)




2. 集合的操作

后期才知道流可以转变成的神奇之处,前来学习


先来看流的收集方法: collect(Collector<? super T, A, R> collector) ,其主要将流中元素收集成另外一个数据结构(如:集合,String,整数等),而参数是一个Collector实例(后面会说明)


2.1 Collectors

Collectors是一个工具类,其常用的方法有:

  • toList(),返回一个Collector实例,这就是上面所说的Collector实例
  • toSet(),返回一个Collector实例
  • toMap(),返回一个Collector实例
  • joining()
  • collectingAndThen()
  • counting()

2.2 转成集合

流转成集合十分的简单,往 collect() 方法里面传入Collector实例即可(Collectors工具类生成的Collector实例)

List list = Arrays.stream(array).collect(Collectors.toList());
Set  set  = Arrays.stream(array).collect(Collectors.toSet());
Map  map  = Arrays.stream(array).collect(Collectors.toMap());

2.2.1 toMap()规约

阿里巴巴Java开发手册规约提到:

【强制】在使用 java.util.stream.Collectors 类的 toMap() 方法转为 Map 集合时,一定要使用含有参数类型为BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key 值时会抛出 IllegalStateException 异常

使用toMap()方法转换成集合时,一般会遇到两个问题:

  • Key重复问题
  • Value空指针异常

toMap的参数:

public static Collector toMap(Function keyMapper
							 ,Function valueMapper
							 ,BinaryOperator mergeFunctio
							 ,Supplier mapSupplier) {
							 
	BiConsumer accumulator = 
	(map, element) -> map.merge(keyMapper.apply(element)
							   ,valueMapper.apply(element)
							   ,mergeFunction);
							   
    return new CollectorImpl (mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
  • 前两个是Function,传参内部操作并返回的,正常都是getKey(),getValue()
  • 第三个是BiFunction实现类(类似于Function),但接收两参数返回一个值,进行合并操作的
  • 第四个是Supplier,是提供的容器,默认是HashMap

为了避免上述的两个问题,我们可以进行如下操作:

  • Key重复一般会使用后者覆盖策略
ArrayList<User> list = new ArrayList();

list.add(new User("张三", 30));
list.add(new User("张三", 80));
list.add(new User("李四", 40));
list.add(new User("王五", 50));

Map map = list.stream().collect(Collectors.toMap(User::getName,User::getAge,(v1, v2) -> v2));

map.forEach((k,v) -> System.out.println(k + "---" + v));

----------------------------------------------------------------------

李四---40
张三---80
王五---50

  • 而Value的NPE问题是因为底层使用了 java.util.HashMap,其 merge 方法里会进行如下的判断:
if (value == null || remappingFunction == null)	throw new NullPointerException();




3. Reduce约简操作

以前约简不会用,现在接触才发现这就是迭代的形式啊,这次的输出值作为下次的输入值


int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 传入前两个参数累加,返回值作为下次的第一个参数,下次往后移动一格
System.out.println(
        Arrays.stream(nums).reduce((left, right) -> left += right).getAsInt()
);

// 有个初始值,结果不为空就不用Optional类包装了,不会NPE
System.out.println(
        Arrays.stream(nums).reduce(100,(left, right) -> left += right)
);


posted @ 2020-11-29 09:33  Howlet  阅读(129)  评论(0编辑  收藏  举报

Copyright © By Howl