这篇文章主要给大家介绍了关于java中for循环操作集合使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
前言
前段时间公司书架多了一本《java8 实战》,毕竟久闻lambda的大名,于是借来一阅。这一看,简直是惊为天人啊,lambda,stream,java8里简直是满脑子骚操作,看我的一愣一愣的。我甚至是第一次感觉到了什么叫优雅。
本文主要介绍java8中的流处理,看看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 -> booleanpredicatesorted中间排序(t,t)->intcomparatormap中间映射t->rfunction<t,r>limit中间截断 distinct中间去重,根据equals方法 skip中间跳过前n个元素终端
操作类型作用foreach终端消费流中的每个元素,使用lambda进行操作count终端返回元素个数,longcollect终端将流归约成一个集合,如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] 归约操作reducelist<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 apistream<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); 三、总结
至此,本文讲述了常见的流操作,目前排序、筛选、求和、归约等大多数操作我们都能实现了。与过去相比,操作集合变的简单多了,代码也变的更加简练明了。
目前vert.x,spring新出的webflux都通过lambda表达式来简化代码,不久的将来,非阻塞式框架的大行其道时,lambda表达式必将变的更加重要!
至于开篇见到的分组!!!下篇文章见~
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对CodeAE代码之家的支持。
原文链接:https://www.cnblogs.com/cdream-zs/p/10504499.html
|