前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Stream补充

Stream补充

作者头像
晚上没宵夜
发布2020-12-01 09:56:53
4770
发布2020-12-01 09:56:53
举报

实习的公司使用Stream来操作集合,熟悉代码阶段就令人头大,来补课了

1. 常见的接口

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

1.1 Consumer

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

代码语言:javascript
复制
@FunctionalInterface
public interface Consumer<T> {

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

1.2 Function

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

代码语言:javascript
复制
@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);
}
代码语言:javascript
复制
list.stream().map(s -> s + "-");	// Stream<R> map(Function<? super T, ? extends R> mapper);

1.3 Supplier

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

代码语言:javascript
复制
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
代码语言:javascript
复制
Collector toMap(Function keyMapper
			   ,Function valueMapper
			   ,BinaryOperator mergeFunction
			   ,Supplier<M> mapSupplier)

1.4 Predicate

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

代码语言:javascript
复制
@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);
}
代码语言:javascript
复制
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实例)

代码语言:javascript
复制
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开发手册规约提到:

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

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

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

toMap的参数:

代码语言:javascript
复制
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重复一般会使用后者覆盖策略
代码语言:javascript
复制
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 方法里会进行如下的判断:
代码语言:javascript
复制
if (value == null || remappingFunction == null)	throw new NullPointerException();

3. Reduce约简操作

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

代码语言:javascript
复制
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)
);
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 常见的接口
    • 1.1 Consumer
      • 1.2 Function
        • 1.3 Supplier
          • 1.4 Predicate
          • 2. 集合的操作
            • 2.1 Collectors
              • 2.2 转成集合
                • 2.2.1 toMap()规约
            • 3. Reduce约简操作
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档