JDK1.8新特性中较为重要的一块内容就是Stream API了,通过Stream API,我们改变了传统的集合操作,使得对集合的操作更加简单和可控。
初体验在Stream出现以前,我们是如何对集合进行处理的呢?
比如现在有一个需求,从一个字符串集合中找出长度大于5的字符串,该如何实现呢?代码如下:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); for (int i = 0 ; i < list.size(); i++) { if (list.get(i).length() > 5 ) { System.out.println(list.get(i)); } } }
这段代码非常基础,你也可以使用增强for循环实现这一需求:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); for (String str : list) { if (str.length() > 5 ) { System.out.println(str); } } }
如果要你将字符串长度大于5的字符串收集起来存入一个新的集合,你就得新建一个集合,然后在循环里进行添加:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); List newList = new ArrayList<>(); for (String str : list) { if (str.length() > 5 ) { newList.add(str); } } System.out.println(newList); }
上述的这些操作,在Stream API中将会非常容易实现,先看一个简单的例子:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); list.forEach(System.out::println); }
遍历一个集合变得非常简单,虽然这并不是Steam的API,但这一特性仍然是在JDK1.8之后才支持的,接下来我们就用Steam实现一下将字符串长度大于5的字符串收集成为一个新集合的需求:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); List newList = list.stream().map(str -> { if (str.length() > 5 ) { return str; } return null ; }).collect(Collectors.toList()); System.out.println(newList); }
我们首先不必纠结为什么这么写,先来看看它的效果:
[null , banana, null , orange, null , watermelon]
新集合中虽然都是长度大于5的字符串,但多了一些null值,所以,使用Stream的filter显然更适合这一需求:
public static void main (String[] args) { List list = Arrays.asList("apple" , "banana" , "pear" , "orange" , "peach" , "watermelon" ); List newList = list.stream().filter(str -> { return str.length() > 5 ; }).collect(Collectors.toList()); System.out.println(newList); }
运行结果:
[banana, orange, watermelon]
熟悉Lambda表达式的同学肯定能发现,这一写法还能能进行简化:
List newList = list.stream().filter(str -> str.length() > 5 ).collect(Collectors.toList());
Stream的创建见识到了Stream API的广大神通了吧,接下来我们回到最基本的问题,如何创建一个Stream?
public static void main (String[] args) { Stream stream = Stream.of(1 , 2 , 3 ); }
最简单的方式便是使用of方法,通过of方法可以创建一个由指定元素组成的Stream,但通常情况下我们并不会使用到该方法,而是使用下面的几个方法:
private static void method (List list,String[] array) { Stream listStream = list.stream(); Stream arrayStream = Arrays.stream(array); }
Stream还支持从指定范围的数组中创建一个流(集合不支持):
private static void method (List list,String[] array) { Stream stream = Arrays.stream(array, 0 , 5 ); }
创建一个不包含任何元素的流:
public static void main (String[] args) { Stream emptyStream = Stream.empty(); }使用generate方法创建流:
public static void main (String[] args) { Stream stream = Stream.generate(Math::random); }
创建流的方式还有很多,这里就不一一列举了。
map方法在最初的例子中,我们用到了map和filter方法,它们的作用分别是什么以及它们的用法是如何的呢?先来所说map方法,map方法类似于遍历操作,它会得到Stream中每个元素的映射,并对其一一生效,比如:
public static void main (String[] args) { Stream stream = Stream.of(1 , 2 , 3 , 4 , 5 ); List newList = stream.map(num -> { return num + 1 ; }).collect(Collectors.toList()); System.out.println(newList); }
这段程序的作用就是对流中的每个元素都做加1操作,运行结果如下:
[2 , 3 , 4 , 5 , 6 ]
对于那些需要对集合/流中的每个元素都要做相同操作的需求,就非常适合使用map方法,比如前后端分离开发中,后端经常需要从数据库中查询出数据,然后将其封装成VO传递给前端,这一需求就能够使用map方法实现:
private static void method () { List userList = userMapper.findAll(); List userVOList = userList.stream().map(user -> { UserVO userVO = new UserVO(); // 拷贝相同的属性 BeanUtils.copyProperties(user, userVO); // 处理前端需要的额外属性 userVO.setSex(user.getSex == 1 ? "男" : "女" ); return userVO; }).collect(Collectors.toList()); System.out.println(userVOList); } filter方法filter方法与map类似,它也会作用于流中的每个元素,但与其不同的是,filter方法是用来做过滤操作的,在filter中我们需要返回一个boolean类型的值,如果返回为true,则说明该值是我们需要的,如果为false,该值就会被抛弃掉,比如:
public static void main (String[] args) { Stream stream = Stream.of(1 , 35 , 7 , 4 , 3 , 5 , 54 , 57 , 36 ); List newList = stream.filter(num -> { return num > 30 ; }).collect(Collectors.toList()); System.out.println(newList); }
这段程序的作用是取出流中数值大于30的数,运行结果如下:
[35 , 54 , 57 , 36 ]
filter可以用来对流中的数据做过滤处理,比如只想要性别为男的数据;只想要工资超过2万的员工信息等等。
其它操作Stream的神奇操作远不止这些,下面再介绍一些比较常用的功能,比如找出一个集合中的最大值:
public static void main (String[] args) { List list = Arrays.asList(11 , 232 , 45 , 6346 , 14 ); int max = 0 ; for (Integer num : list) { if (num > max){ max = num; } } System.out.println(max); }
而如果使用Stream,它将变得非常简单:
public static void main (String[] args) { List list = Arrays.asList(11 , 232 , 45 , 6346 , 14 ); Optional max = list.stream().max(Comparator.naturalOrder()); System.out.println(max.get()); }
求最小值,只需使用min方法即可:
public static void main (String[] args) { List list = Arrays.asList(11 , 232 , 45 , 6346 , 14 ); Optional max = list.stream().min(Comparator.naturalOrder()); System.out.println(max.get()); }
求和:
public static void main (String[] args) { List list = Arrays.asList(11 , 232 , 45 , 6346 , 14 ); Optional sum = list.stream().reduce(Integer::sum); System.out.println(sum.get()); }
注意事项在使用Strema API时需要注意的地方就是Lambda表达式的编写,如:
List list = wordList.stream().filter(word -> { return word.startsWith("p" ); list.forEach(System.out::println);
对于这样的一段程序,因为Lambda表达式体中仅包含了一条返回语句,所以表达式可以简写:
List list = wordList.stream(). filter(word -> word.startsWith("p" )).collect(Collectors.toList()); list.forEach(System.out::println);
又比如:
List numList = Arrays.asList(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ); Optional sum = numList.stream().reduce((x, y) -> { return x + y; }); System.out.println(sum);
首先因为Lambda表达式体仅包含一条返回语句,所以可以简写:
Optional sum = numList.stream().reduce((x, y) -> x + y);
我们也可以调用Integer类的静态方法sum进行求和:
Optional sum = numList.stream().reduce((x, y) -> Integer.sum(x, y));
又因为Lambda表达式体中仅包含一条语句,且该语句调用了一个绝对存在的方法,则可以简写为:
Optional sum = numList.stream().reduce(Integer::sum);
这就是Lambda表达式中的方法引用,具体细节可以去了解一下Lambda的相关内容。
最后就是Stream的一些其他类型,当你使用of方法创建一个流时:
Stream stream = Stream.of(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 );
调用Stream类的of方法传入的是基本类型数据,但是会得到一个包装类型的Stream,我们知道,基本类型需要装箱成为包装类型,这一操作在数据量庞大的情况下是比较低效的,Stream API也考虑到这一点,所以提供了对应包装类型的Strema,如下:
IntStream intStream = IntStream.of(1 , 2 , 'a' , 'z' ); LongStream longStream = LongStream.of(10L ); DoubleStream doubleStream = DoubleStream.of(1.1f , 2.2 );
浏览
32 点赞
评论
收藏
分享
手机扫一扫分享
分享
举报
点赞
评论
收藏
分享
手机扫一扫分享
分享
举报