jdk1.8中stream相关操作

来源:包括jdk文档,其他网友博客。做一个记录和笔记:

java.util.stream

基本概念:

java.util.stream包提供了“支持在流上的函数式风格的值操作”的工具。文档连接: java.util.stream

Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。活动流Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。

Java 8扩展了集合类,可以通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个串行Stream或者并行Stream。

串行Stream如下所示:

Stream<T> stream = collection.stream();

用流水比喻非常恰当,数据向流水一样流过,进行过滤,加工,最终输出。

流Stream的操作可以是 串行执行 或者 并行执行。 它们可以使用其中一种方式开始,然后切换到另外的一种方式,使用stream.sequential()或stream.parallel()来达到这种切换。

串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

javadoc包里给出的例子:

int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)
                                  .mapToInt(b -> b.getWeight())
                                  .sum();
 

注意,上面的代码使用了一个原始的流,以及一个只能用在原始流上的sum()方法。

流提供了流畅的API,可以进行数据转换和对结果执行某些操作。流操作既可以是“中间的”也可以是“末端的”。

  • 中间的 -中间的操作保持流打开状态,并允许后续的操作。上面例子中的filter和map方法就是中间的操作。这些操作的返回数据类型是流;它们返回当前的流以便串联更多的操作。
  • 末端的 - 末端的操作必须是对流的最终操作。当一个末端操作被调用,流被“消耗”并且不再可用。上面例子中的sum方法就是一个末端的操作。

通常,处理一个流涉及了这些步骤:

  1. 从某个源头获得一个流。
  2. 执行一个或更多的中间的操作。
  3. 执行一个末端的操作。

有几个更普通的关于流操作的特性需要考虑:

  • 有状态的 - 有状态的操作给流增加了一些新的属性,比如元素的唯一性,或者元素的最大数量,或者保证元素以排序的方式被处理。这些典型的要比无状态的中间操作代价大。
  • 短路 - 短路操作潜在的允许对流的操作尽早停止,而不去检查所有的元素。这是对无限流的一个特殊设计的属性;如果对流的操作没有短路,那么代码可能永远也不会终止。

对每个Sttream方法这里有一些简短的,一般的描述。查阅javadoc获取更详尽的解释。下面给出了每个操作的重载形式的链接。

中间的操作:

  • filter 1 - 排除所有与断言不匹配的元素。
  • map 1 2 3 4 - 通过Function对元素执行一对一的转换。
  • flatMap 1 2 3 4 5 - 通过FlatMapper将每个元素转变为无或更多的元素。
  • peek 1 - 对每个遇到的元素执行一些操作。主要对调试很有用。
  • distinct 1 - 根据.equals行为排除所有重复的元素。这是一个有状态的操作。
  • sorted 1 2 - 确保流中的元素在后续的操作中,按照比较器(Comparator)决定的顺序访问。这是一个有状态的操作。
  • limit 1 - 保证后续的操作所能看到的最大数量的元素。这是一个有状态的短路的操作。
  • substream 1 [2](http://javadocs.techempower.com/jdk18/api/java/util/stream/Stream.html#substream(long, long)) - 确保后续的操作只能看到一个范围的(根据index)元素。像不能用于流的String.substring一样。也有两种形式,一种有一个开始索引,一种有一个结束索引。二者都是有状态的操作,有一个结束索引的形式也是一个短路的操作。

末端的操作:

  • forEach 1 - 对流中的每个元素执行一些操作。
  • toArray 1 2 - 将流中的元素倾倒入一个数组。
  • reduce 1 [2](http://javadocs.techempower.com/jdk18/api/java/util/stream/Stream.html#reduce(T, java.util.function.BinaryOperator)) [3](http://javadocs.techempower.com/jdk18/api/java/util/stream/Stream.html#reduce(U, java.util.function.BiFunction, java.util.function.BinaryOperator)) - 通过一个二进制操作将流中的元素合并到一起。
  • collect 1 [2](http://javadocs.techempower.com/jdk18/api/java/util/stream/Stream.html#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)) - 将流中的元素倾倒入某些容器,例如一个Collection或Map.
  • min 1 - 根据一个比较器找到流中元素的最小值。
  • max 1 -根据一个比较器找到流中元素的最大值。
  • count 1 - 计算流中元素的数量。
  • anyMatch 1 - 判断流中是否至少有一个元素匹配断言。这是一个短路的操作。
  • allMatch 1 - 判断流中是否每一个元素都匹配断言。这是一个短路的操作。
  • noneMatch 1 - 判断流中是否没有一个元素匹配断言。这是一个短路的操作。
  • findFirst 1 - 查找流中的第一个元素。这是一个短路的操作。
  • findAny 1 - 查找流中的任意元素,可能对某些流要比findFirst代价低。这是一个短路的操作。
  • orElse :不满足条件时执行

javadocs中提到的 , 中间的操作是延迟的(lazy)。只有末端的操作会立即开始流中元素的处理。在那个时刻,不管包含了多少中间的操作,元素会在一个传递中处理(通常,但并不总是)。(有状态的操作如sorted() 和distinct()可能需要对元素的二次传送。)

示例1:

List<Person> persons = Arrays.asList(new Person("mkyong"),
		new Person("michael"), new Person("lawrence"));

Person result = persons.stream()				   // Convert to steam
	.filter(x -> "michael".equals(x.getName()))	// we want "michael" only
	.findAny()									// If 'findAny' then return found
	.orElse(null);	

示例2:再使用HttpClient连接池,自定义keepAlive策略时:

 public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
        return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))
                .stream()
                .filter(h -> StringUtils.equalsIgnoreCase(h.getName(), "timeout")
                        && StringUtils.isNumeric(h.getValue()))
                .findFirst()
                .map(h -> NumberUtils.toLong(h.getValue(), DEFAULT_SECONDS))
                .orElse(DEFAULT_SECONDS) * 1000;
 }
一、代替for循环

在List aList中,查找userName为zhangsan的对象A。

1、查找集合中的第一个对象——filter
aList.stream() .filter(...) .findFirst()
1  Optional<Person> firstPerson= aList.stream() .filter(a -> "zhangsan".equals(a.getUserName())) .findFirst();

关于Optional,java API中给了解释。

1 //容器对象,该对象可以包含或不包含非空值。如果存在一个值,isPresent()将返回true,并且 get()将返回该值。
2 A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

所以,我们可以这样子使用:

1 if (firstPerson.isPresent()) {
2      Person a = firstPerson.get();   //获取对象
3 }else {
4    //没有查到的逻辑
5 }
2、查找满足条件的对象,并返回集合——filter、collect
aList.stream() .filter(...) .collect(Collectors.toList())
List<Person> firstPerson= aList.stream() .filter(a -> "zhangsan".equals(a.getUserName())) .collect(Collectors.toList());
3、对象列表 - > 字符串列表,即:获取对象集合中所有的userName的集合。——map

注意:stream().map( A::getXXX ) 等价于 stream().map(t -> t.getXXX)

aList.stream.map(...).collect(Collectors.toList())
1 //方法一
2 List<String> idList = aList.stream.map(A::getUserName).collect(Collectors.toList());
3 //方法二
4 List<String> collect = staff.stream().map(x -> x.getUserName()).collect(Collectors.toList());

4、对象集合 - > 其他对象集合 , 此示例说明如何将 A对象集合转换为 D对象集合。

 1 public static void main(String[] args) {
 2 
 3         List<Person> voList= Arrays.asList(
 4                 new Person("zhangsan", "男", "java开发"),
 5                 new Person("lisi", "女", "安卓"),
 6                 new Person("makie", "女", "go语言")
 7         );
 8 
 9         // convert inside the map() method directly.
10         List<D> result = voList.stream().map(temp -> {
11             D obj = new D();
12             obj.setName(temp.getUserName());
13             obj.setSex(temp.getSex());
14             if ("zhangsan".equals(temp.getUserName())) {
15                 obj.setExtra("this field is for zhangsan only!");
16             }
17             return obj;
18         }).collect(Collectors.toList());
19 
20         System.out.println(result);
21 
22     }输出结果为:D{name='zhangsan', sex="男", extra='this field is for zhangsan only!'}, D{name='lisi', sex="女", extra='null'}, D{name='makie', sex="女", extra='null'}

二、List转Map

id为key,A对象为value,可以这么做:

1 /**
2  * List -> Map
3  * 需要注意的是:
4  * toMap 如果集合对象有重复的key,会报错Duplicate key错误 ..
5  *  对象a1,对象a2的id都为1。
6  *  可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
7  */
8 Map<Integer, Person> aMap = aList.stream().collect(Collectors.toMap(A::getId, a -> a,(k1,k2)->k1));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值