Java1.8之Stream流基本使用

前言

Java1.8中引入了流的概念,具体实现是java.util.stream.Stream接口,流的性能是高效的,在多核CPU中,可以充分的的利用CPU资源,代码写起来也比常规的写法更简洁,在实际开发中,用得也比较多

我总结了一下Stream流的基本用法和常用方法,让我们来感受一下吧

基础

在使用流之前,需要准备三件事情:

  • 数据源
  • 中间操作链:用来形成流水线
  • 终端操作:用来生成最终结果

中间操作

操作返回类型说明使用场景
filterStream<T>返回一个由与此流匹配的元素组成的流过滤元素
mapStream<R>返回由应用给定结果组成的流类型转换
limitStream<T>返回一个被截断指定长度的流数据截取
sortedStream<T>返回由该流的元素组成的流,根据自然顺序排序 如果此流的元素不是Comparable,可能会引起ClassCastException异常数据排序
distinctStream<T>返回由不同元素组成的流数据去重

终端操作

操作返回类型说明使用场景
forEachvoid消费流中的每个元素并对其应用Lambda遍历元素
countlong返回流中元素的个数统计数量
collect<R> R把流规约成一个集合,可以是List、Map、Integer数据归约
anyMatchboolean流中元素任意一个满足判断条件数据判断
allMatchboolean流中元素全部满足判断条件数据判断

实战

MockData

在实际开发中,我们使用的更多的是DTO,所以新建一个类,再造些数据

@Data
@AllArgsConstructor
static class DTO {
    private String name;

    private Integer age;
    @Override
    public String toString() {
        return "(name=" + this.name + ", age=" + this.age + ")";
    }
}

List<DTO> list = Arrays.asList(new DTO("苹果", 20), new DTO("香蕉", 35), new DTO("橘子", 15), new DTO("芒果", 50));   

中间操作

filter 过滤

Api:

// 返回 predicate(过滤条件) 为True的元素
Stream<T> filter(Predicate<? super T> predicate);

示例

// 过滤价格大于20的水果
list.stream().filter(o -> o.getPrice() > 20).forEach(System.out::println);       

输出如下:

(name=香蕉, price=35)
(name=芒果, price=50

map 类型转换

Api:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

IntStream mapToInt(ToIntFunction<? super T> mapper);

LongStream mapToLong(ToLongFunction<? super T> mapper);

DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);

类型转换的Api很多,这里只用map举例,其他Api用法大同小异,当我们要把类中的price转换成String或者其他类型的时候,可以这样

// 类型转换map(转换过程,需要有return) 将price转换成Double类型,并只返回Double类型的age
List<Double> collect = list.stream().map(o -> Double.valueOf(o.getPrice())).collect(Collectors.toList());
System.out.println(collect);

输出如下

[20.0, 35.0, 15.0, 50.0]

limit 数据截取

Api:

Stream<T> limit(long maxSize);

maxSize表示返回元素的最大数量

list.stream().limit(2).forEach(System.out::println);

输出如下

(name=苹果, price=20)
(name=香蕉, price=35)

sorted 数据排序

Api:

// 原生排序  如果T没有实现Comparable,会引起ClassCastException异常
Stream<T> sorted();

// 可以自定义排序规则  扩展性高
Stream<T> sorted(Comparator<? super T> comparator);

先来看看原生排序,会发生异常:
java.lang.ClassCastException: xxxxxxx cannot be cast to java.lang.Comparable

// 排序
List<DTO> collect1 = list.stream().sorted().collect(Collectors.toList());
System.out.println(collect1);

输出如下

Exception in thread "main" java.lang.ClassCastException: com.steam.T_ForeachSteam$DTO cannot be cast to java.lang.Comparable
	at java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47)
	at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
	at java.util.TimSort.sort(TimSort.java:220)
	at java.util.Arrays.sort(Arrays.java:1512)
	at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:348)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
	at com.steam.T_ForeachSteam.main(T_ForeachSteam.java:35)

自定义排序

list.stream().sorted(Comparator.comparing(DTO::getPrice)).forEach(System.out::println);

输出如下:

(name=橘子, price=15)
(name=苹果, price=20)
(name=香蕉, price=35)
(name=芒果, price=50)

倒序

list.stream().sorted(Comparator.comparing(DTO::getPrice).reversed()).forEach(System.out::println);

输出如下:

(name=芒果, price=50)
(name=香蕉, price=35)
(name=苹果, price=20)
(name=橘子, price=15)

distinct 去重

Api:

// 底层是一个HashSet的实现
Stream<T> distinct()
List<Integer> distinctList = Arrays.asList(10, 11, 10);
distinctList.stream().distinct().forEach(o -> System.out.print(o + " "));

输出如下

10 11

终端操作

count 数据计数统计

Api:

long count();
List<String> anyMatchList = Arrays.asList("1","2","3","4","5");
long count = anyMatchList.stream().count();
System.out.println(count);

输出如下

5

allMatch anyMatch 条件返回

Api:

boolean allMatch(Predicate<? super T> predicate);
List<String> addList = new ArrayList<>();
List<String> anyMatchList = Arrays.asList("1","2","3","4","5");
// 返回值可以理解为是否遍历了所有元素
boolean b = anyMatchList.stream().allMatch(o -> {
    addList.add(o);
    // 为false时返回
    return addList.size() < 2;
});
System.out.println(addList.toString() + b);

输出如下

[1, 2]false

Api:

boolean allMatch(Predicate<? super T> predicate);
List<String> addList1 = new ArrayList<>();
// 返回值可以理解为是否有一个元素满足返回条件
boolean any = anyMatchList.stream().anyMatch(o -> {
    addList1.add(o);
    // 为true时返回
    return addList1.size() < 2;
});
System.out.println(addList1.toString() + any);

输出如下

[1]true

collect 数据规约

Api:

<R, A> R collect(Collector<? super T, A, R> collector);

<R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);

使用

 List<DTO> list = Arrays.asList(new DTO("苹果", 20), new DTO("香蕉", 35),
         new DTO("菠萝", 20), new DTO("水蜜桃", 35),
         new DTO("橘子", 15), new DTO("芒果", 50));
 // 根据price分组
 Map<Integer, List<DTO>> collect = list.stream().collect(Collectors.groupingBy(DTO::getPrice));
 System.out.println(JSON.toJSONString(collect));

 // 转换成set集合
 System.out.println(Stream.of("a", "b", "c","a").collect(Collectors.toSet()));
 
 // 转换成map
 Map<String, String> collect1 = Stream.of("a", "b", "c", "a").collect(Collectors.toMap(x -> x, x -> x + x,(oldVal, newVal) -> newVal));
 collect1.forEach((k,v) -> System.out.println(k + ":" + v));

输出如下

{50:[{"name":"芒果","price":50}],35:[{"name":"香蕉","price":35},{"name":"水蜜桃","price":35}],20:[{"name":"苹果","price":20},{"name":"菠萝","price":20}],15:[{"name":"橘子","price":15}]}
[a, b, c]
a:aa
b:bb
c:cc

总结

Java Stream Api繁多,需要读者手动写代码感受一下。
笔者水平有限,文中有不正之处还请各位不吝指出,Stream涉及知识面广,笔者一时也无法全面叙出,文章会不定时更新和巩固,欢迎给我留言,我会在第一时间回复

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值