Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,分组等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。其形式好比下面的图:
代码语言:javascript复制 -------------------- ------ ------ --- -------
| stream of elements -----> |filter -> |sorted -> |map -> |collect|
-------------------- ------ ------ --- -------
以上的流程转换为 Java 代码为:
代码语言:javascript复制List<Integer> newList = list.stream()
.filter(b -> b.getColor() == RED)
.sorted((x,y) -> x.getWeight() - y.getWeight())
.mapToInt(Widget::getWeight)
.sum();
此方式每次操作都返回一个新的流,可以再转为集合,而不改变原始集合的值。
Strean流的创建:
代码语言:javascript复制// 1,校验通过Collection 系列集合提供的stream()或者paralleStream()
List<String> list = new ArrayList<>();
Strean<String> stream1 = list.stream();
// 2.通过Arrays的静态方法stream()获取数组流
String[] str = new String[10];
Stream<String> stream2 = Arrays.stream(str);
// 3.通过Stream类中的静态方法of
Stream<String> stream3 = Stream.of("aa","bb","cc");
//of方法还可以装多个集合
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));
// 4.创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0,(x) -> x 2);
方法介绍:
1.forEach():循环迭代流中的每个数据
代码语言:javascript复制 //java 8 前
System.out.println("java 8 前");
for(User user: list){
System.out.println(user);
}
// java 8 lambda
System.out.println("java 8 lambda");
list.forEach(user -> System.out.println(user));
// java 8 stream lambda
System.out.println("java 8 stream lambda");
list.stream().forEach(user -> System.out.println(user));
2.collect(): 从流转成集合
collect方法十分强大,可以将流转成各种集合,甚至还能对进行分组等操作
代码语言:javascript复制 List<User> list = Arrays.asList(
new User("张三", 11),
new User("王五", 20),
new User("王五", 91)
);
//将流转换为list集合
List<User> newList = list.stream().collect(Collectors.toList());
System.out.println(newList.toString());
//将流转换为map集合(以age为key,以name为value值)
Map<Integer, String> map = list.stream().collect(Collectors.toMap(User::getAge, User::getName));
//[User{age=11, name='张三'}, User{age=20, name='王五'}, User{age=91, name='王五'}]
System.out.println(map.toString());//{20=王五, 91=王五, 11=张三}
//以name相同进行分组
Map<String, List<User>> groupMap = list.stream()
.collect(Collectors.groupingBy(User::getName));
System.out.println(groupMap);
//{张三=[User{age=11, name='张三'}], 王五=[User{age=20, name='王五'}, User{age=91, name='王五'}]}
这里需要注意的问题是,上面每次调用方法都用list.stream(),如果你想把它提取出来,想下面这样运行就会报错,因为stream流每次使用完以后就自动关闭了。
代码语言:javascript复制 //获取stewam流
Stream<User> stream = list.stream();
//将流转换为list集合
List<User> newList = stream.collect(Collectors.toList());
//继续往下面走就会报错,因为此时stream流已经关闭了!!!
Map<Integer, String> map = stream.collect(Collectors.toMap(User::getAge, User::getName));
错误信息如下:
代码语言:javascript复制Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.wenxue.jdk8.StreamTest.main(StreamTest.java:147)
3.filter(): 过滤,可以对原集合进行过滤,从而输出满足条件的新集合。
代码语言:javascript复制 List<Integer> numList = Arrays.asList(1,2,3,4,5);
List<Integer> collect3 = numList.stream().filter(n -> n>3).collect(Collectors.toList());
System.out.println(collect3); //[4, 5]
如上所示,filter(n -> n>3)的第一个n是遍历的集合值,第二个表达式n>3表示要输出集合中大于3的数,于是就成功的过滤了原集合,踢掉了小于表达式的值,得到了新的集合[4,5]。
4.map(): 增强集合,可以对集合中的值进行操作,得到新的值,从而得到新的集合。
代码语言:javascript复制 List<String> list = Arrays.asList("a", "b", "c", "d");
List<String> newList = list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(newList); //[A, B, C, D]
如上所示,调用map方法,将原list的值都按表示式增强,进而转成大写,于是得到了增强后的集合。
map()与filter()的区别:
map()可以对集合原始进行操作,自定义返回新的结果集;而fliter是过滤(取满足条件的值),不能修改集合元素的值
5.sorted():排序
代码语言:javascript复制 public void testSort() {
List<Integer> nums = Arrays.asList(3, 1, 2, 5);
// java 1.8 前
System.out.println("java 8 前");
Collections.sort(list, new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge().compareTo(o2.getAge());
}
});
// java 1.8 stream 方法引用
nums.stream().sorted().forEach(a -> System.out.println(a));//1 2 3 5
}
从上面我们可以看出,在jdk1.8以前要实现一个排序十分的麻烦,而使用jdk1.8却可以很简单的就做到了。
如果你还想指定一个排序规则,1.8也能满足你,sorted()方法还可以提供一个参数,来用于指定比较规则:
代码语言:javascript复制//使用User对象的年龄排序
list.stream().sorted(Comparator.comparing(User::getAge))
.forEach(user -> System.out.println(user));
6.limit():截断,将集合截断,取截断前的值
代码语言:javascript复制 @Test
public void testLimit(List<User> list) {
// 从第三个开始截断,只输出前三个
// java 8 前
System.out.println("java 8 前");
for (int i = 0; i < 3; i ) {
System.out.println(list.get(i));
}
// java 8 stream
System.out.println("java 8 stream");
list.stream().limit(3).forEach(user -> System.out.println(user));
}
7.skip():截断,将集合截断,取截断后的值(与limi相反)
代码语言:javascript复制 @Test
public void testSkip() {
// 跳过前三个元素,从第四个开始输出
// java 8 前
System.out.println("java 8 前");
for (int i = 3; i < list.size(); i ) {
System.out.println(list.get(i));
}
// java 8 stream
System.out.println("java 8 stream");
list.stream().skip(3).forEach(user -> System.out.println(user));
}
8.distinct():去重,注意:必须重写对应泛型的hashCode()和equals()方法
代码语言:javascript复制 /**
* 使用jdk1.8的distinct() 去重,注意:必须重写对应泛型的hashCode()和equals()方法
*/
@Test
public void testDistinct() {
// 注意使用Arrays.asList() 返回的是Arrays的内部类ArrayList,操作remove,add会报错
List<User> users = new ArrayList(list);
// 为list去除重复数据
// java 8 前
System.out.println("java 8 前");
for (int i = 0; i < users.size() - 1; i ) {
for (int j = users.size() - 1; j > i; j--) {
if (users.get(j).getAge() == users.get(i).getAge() && users.get(j).getName()
.equals(users.get(i).getName())) {
users.remove(i);
}
}
}
for (User user : users) {
System.out.println(user);
}
// java 8 stream
System.out.println("java 8 stream");
users.stream().distinct().forEach(user -> System.out.println(user));
}
实战例子: 按照年龄大于18去重,从小到大排序,并且只取前二个
代码语言:javascript复制 list.stream().filter(user1 -> user1.getAge() > 18).distinct().sorted(
Comparator.comparing(User::getAge)).limit(2)
.forEach(user1 -> System.out.println(user));
9.mapToInt():计算,使用该方法可进行max,min,sum,avg,count等计算
代码语言:javascript复制 /**
* 测试计算,mapToInt()方法是先返回一个可计算的对象,进而才能调用计算方法
*/
@Test
public void testNum() {
IntSummaryStatistics num = list.stream().mapToInt(u -> u.getAge())
.summaryStatistics();
System.out.println("总共人数:" num.getCount());
System.out.println("平均年龄:" num.getAverage());
System.out.println("最大年龄:" num.getMax());
System.out.println("最小年龄:" num.getMin());
System.out.println("年龄之和:" num.getSum());
}
10.findFirst() :使用该方法获取第一个元素
代码语言:javascript复制 List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
Intger num = list.stream().findFirst().get();
System.out.println(num);//1
11.flatMap():合并流,将原来的stream中的所有元素都展开组成一个新的stream。
上面我们讲到了使用of()方法可以创建集合,并且可以包裹多个集合,那么又怎样将多个再合并呢?使用flatMap()方法就能做到。
代码语言:javascript复制 @Test
public void testFlatMap() {
//创建一个 装有两个泛型为integer的集合
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));
// 将两个合为一个
Stream<Integer> newStream = stream.flatMap(
(Function<List<Integer>, Stream<Integer>>) integers -> integers.stream());
// 转为新的集合
List<Integer> collect = newStream.collect(toList());
System.out.println("新stream大小:" collect.size());//5
System.out.println("-----合并后-----");
collect.forEach(o -> System.out.println(o));//1,2,3,4,5
}
12.reduce() :智能运算
reduce 操作可以实现从一组元素中生成一个值
sum()
、max()
、min()
、count()
等都是reduce操作,因为常用所以设为单独函数
例子1:找到年龄最大的,并求所有人的年龄之和
代码语言:javascript复制 @Test
public void reduce() {
List<User> list = Arrays.asList(
// name,age
new User("张三", 11),
new User("王五", 20),
new User("王五", 91)
);
Optional<User> reduce = list.stream().reduce((s1, s2) -> s1.getAge() > s2.getAge() ? s1 : s2);
User user = reduce.get();
System.out.println(user); //User{age=91, name='王五'}
//当然也可以使用更简单的方法max()
Optional<User> max = list.stream().max(Comparator.comparing(User::getAge));
User user2 = max.get();
System.out.println(user2);// //User{age=91, name='王五'}
// 求年龄之和
Integer reduce3 = list.stream().reduce(0, // 该参数为初始值
(integer, user3) -> integer user3.getAge(), // 该参数为累加器
(integer, integer2) -> integer integer2);// 多个部分累加
System.out.println(reduce); //122
}
这里我要说明的是reduce类似于智能运算,它是一种设计思想,其中的max,count等之类的方法已经实现了这种模式。
13.使用collect()做字符串join
代码语言:javascript复制 @Test
public void reduce() {
// 使用Collectors.joining()拼接字符串
Stream<String> stream = Stream.of("张三","李四","王五","赵六");
// String s = stream.collect(Collectors.joining()); // 张三李四王五赵六
// String s = stream.collect(Collectors.joining("-")); // 张三-李四-王五-赵六
String s = stream.collect(Collectors.joining("-", "(", ")")); // (张三-李四-王五-赵六)
System.out.println(s);
}
以上就是java1.8的Stream流的所有操作方法,看以看出1.8的版本还是蛮强大的,同学们赶紧学习下吧! -- 龚文学