java8中流处理的示例分析

发布时间:2021-09-14 09:11:07 作者:小新
来源:亿速云 阅读:119

这篇文章主要为大家展示了“java8中流处理的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java8中流处理的示例分析”这篇文章吧。

我就随便举个例子,看看Stream有多优雅。

// 对苹果按颜色汇总并绩数量
Map<String, Long> appleCount = apples.stream()
 .collect(groupingBy(Apple::getColor, counting()));
// 过滤掉颜色为黑色的苹果,并汇总好苹果的总金额
Double sum = apples.stream()
 .filter(i->"black".equals(i.getColor()))
 .collect(toList);

一、lambda表达式

虽然本文重点是stream,但是stream中需要传递lambda表达式,所以简单介绍一下lambda表达式。lambda表达式其实就是匿名函数(anonymous function),是指一类无需定义标识符的函数或子程序。

java中匿名函数的表现形式,只留下入参和方法体中的内容

// 普通函数
public void run(String s){
 System.out.print(s+"哈哈");
}
// 我不要名字啦!!!
(s)->System.out.print(s+"哈哈")

诶,过去我们都用对象调方法的,你弄这个没名的东西啥时候用啊?

java中我们通过函数式接口来使用这种匿名函数。

函数式接口

1.java中只包含一个未实现方法的接口。其中可以有与Object中同名的方法和默认方法(java8中接口方法可以有默认实现)。

2.java中函数式接口使用@FunctionalInterface进行注解。Runnable、Comparator都是函数式接口。

3.java.util.function包下为我们提供很多常用的函数式接口,例如Function等。

用法举例:

// 实现Runnable中的run方法,替代匿名内部类。
Runnable r = ()->System.out.print("哈哈");
// 作为参数传递。
new Thread(()-> System.out.println("haha")).start();

ArrayList<Apple> list = new ArrayList<>();
list.forEach(i-> System.out.println(i.getWeight()));


// 简化策略模式
public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){
 List<Apple> apples = new ArrayList<>();
 for(Apple apple : inventory){
 if(p.test(apple)){
 apples.add(apple);
 }
 }
 return apples;
}
public class BigApple implement ApplePredicate{
 @Override
 public boolean test(Apple a){
 if(a.getWeight>10){
 return a
 }
 }
}
// 这是个简单的策略模式,根据用户的需要,创建不同的接口ApplePredicate实现类,调用时传入不同的实现类就可以,但问题是如果需求过多,创建的实现类也会很多,过于臃肿不方便管理。
xx.filterApple(inventory,new BigApple);
// 使用lambda表达式,不在需要创建BigApple类
xx.filterApple(inventory,i->(i.getWeight>10));

使用lambda表达式可以简化大量的模板代码,并且可以向方法直接传递代码。

总之

方法出参入参来自函数式接口

//入参s,返回void
(s)->System.out.println(s);
//入参空,返回void
()->System.out.print("haha");
//入参i,返回i+1
i->i+1
//后面写代码块
apple->{if(apple.getWeiht>5) return "BIG";
 else return "small";
 }

好了,不多啰嗦了,如果感兴趣推荐下面的文章或《Java8实战》的前三章。

1.Lambda表达式有何用处?如何使用?

2.java8实战

二、Stream

流是什么?

Java API的新成员,它允许你使用声明式方式处理数据集合(类似sql,通过查询语句表达,而不是临时编写一个实现)。

如果有人说lambda表达式不易于理解,那还勉强可以接受(其实过于复杂的lambda缺失不好阅读,但通常lambda不会做太复杂的实现),但流真的非常的易懂易用。这个语法糖真的是甜死了。

注意事项:

1.流只能使用一次,遍历结束就代表这个流被消耗掉了

2.流对集合的操作属于内部迭代,是流帮助我们操作,而不是外部迭代

3.流操作包含:数据源,中间操作链,终端操作三个部分。

基础流操作

List<Double> collect = list.stream()
 // 过滤掉黑色的苹果
 .filter(i -> "black".equals(i.getColor()))
 // 让苹果按照重量个价格排序
 .sorted(Comparator.comparing(Apple::getWeight)
 .thenComparing(i->i.getPrice()))
 // 筛选掉重复的数据
 .distinct()
 // 只要苹果的价格
 .map(Apple::getPrice)
 // 只留下前两条数据
 .limit(2)
 // 以集合的形式返回
 .collect(toList());
// 循环打印列表中元素
list.forEach(i->System.out.print(i));

Apple::getPrince<=>i -> i.getPrince()可以看做是仅涉及单一方法的语法糖,效果与lambda表达式相同,但可读性更好。

同理

下面列表为常见操作

中间

操作类型作用函数描述函数
filter中间过滤T -> booleanPredicate
sorted中间排序(T,T)->intComparator
map中间映射T->RFunction<T,R>
limit中间截断

distinct中间去重,根据equals方法

skip中间跳过前n个元素

终端

操作类型作用
forEach终端消费流中的每个元素,使用lambda进行操作
count终端返回元素个数,long
collect终端将流归约成一个集合,如List,Map甚至是Integer

筛选与切片

List<String> strings = Arrays.asList("Hello", "World");
List<String> collect1 = strings.stream()
 // String映射成String[]
 .map(i -> i.split(""))
 // Arrays::Stream 数据数组,返回一个流String[]->Stream<String>
 // flatMap各数组并不分别映射成一个流,而是映射成流的内容 Stream<String>->Stream
 .flatMap(Arrays::stream)
 .collect(toList());
System.out.println(collect);
----->输出 [H, e, l, l, o, W, o, r, l, d]

归约操作reduce

List<Integer> integers = Arrays.asList(12, 3, 45, 3, 2,-1);
// 有初始值的叠加操作
Integer reduce = integers.stream().reduce(3, (i, j) -> i + j);
Integer reduce2 = integers.stream().reduce(5, (x, y) -> x < y ? x : y);
// 无初始值的叠加操作
Optional<Integer> reduce1 = integers.stream().reduce((i, j) -> i + j);
// 无初始值的最大值
Optional<Integer> reduce4 = integers.stream().reduce(Integer::min);
// 无初始值的最大值
Optional<Integer> reduce5 = integers.stream().reduce(Integer::max);
// 求和
Optional<Integer> reduce6 = integers.stream().reduce(Integer::sum);

reduce做的事情是取两个数进行操作,结果返回取下一个数操作,以次类推。

Optional是java8引入的新类,避免造成空指针异常,在集合为空时,结果会包在Optional中,可以用isPresent()方法来判断是否为空值。

无初始值的情况下可能为空,故返回Optional

中间

操作类型作用函数描述函数
flatmap中间使通过的流返回内容T -> booleanPredicate

终端

操作类型作用
anyMatch终端返回boolean,判断是否有符合条件内容
noneMatch终端返回boolean,判断是否无符合条件内容
allMatch终端返回boolean,判断是全为符合条件内容
findAny终端Optional,随机找一个元素返回
findFirst终端Optional,返回第一个元素
reduce终端Optional (T,T)->T 归约操作

数值流

包装类型的各种操作都会有拆箱操作和装箱操作,严重影响性能。所以Java8为我们提供了原始数值流。

// 数值流求平均值
OptionalDouble average = apples.stream()
 .mapToDouble(Apple::getPrice)
 .average();
// 数值流求和
OptionalDouble average = apples.stream()
 .mapToDouble(Apple::getPrice)
 .sum();
// 数值流求最大值,没有则返回2
double v = apples.stream()
 .mapToDouble(Apple::getPrice)
 .max().orElse(2);
// 生成随机数
IntStream s = IntStream.rangeClosed(1,100);

下面列表为常见数值流操作操作

中间

操作类型作用
rangeClosed(1,100)中间生成随机数(1,100]
range(1,100)中间生成随机数(1,100)
boxed()中间包装成一般流
mapToObj中间返回为对象流
mapToInt中间映射为数值流

终端,终端操作与List一般流类似

构建流

值创建

Stream<String> s = Stream.of("java","python");

数组创建

int[] i = {2,3,4,5};
Stream<int> = Arrays.stream(i);

由文件生成,NIO API已经更新,以便利用Stream API

Stream<String> s = Files.lines(Paths.get("data.txt"),Charset.defaultCharset());

由函数创建流:无限流

// 迭代
Stream.iterate(0,n->n+2)
 .limit(10)
 .forEach(System.out::println);
// 生成,需要传递实现Supplier<T>类型的Lambda提供的新值
Stream.generate(Math.random)
 .limit(5)
 .forEach(System.out::println);

以上是“java8中流处理的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. Java8中Stream流操作的示例分析
  2. Javascript中流程控制的示例

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:shell初学者必学的几个脚本

下一篇:linux中怎么解决文件已删除但空间不释放的问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》