相信Java8的Stream 大家都已听说过了,但是可能大家不会用或者用的不熟,笔者将在《玩转Java8Stream》系列文章中带大家从零开始使用,循序渐进,带你走向Stream的巅峰。
什么是操作符呢?操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一样。
Stream的操作符大体上分为两种: 中间操作符 和 终止操作符
对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符。
中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作):
数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。
这里只介绍了Stream,并没有涉及到 IntStream 、 LongStream 、 DoubleStream ,这三个流实现了一些特有的操作符,我将在后续文章中介绍到。
说了这么多,只介绍这些操作符还远远不够;俗话说,实践出真知。那么,Let‘s go。
map操作将原来的单词 转换成了每个单的长度,利用了String自身的length()方法,该方法返回类型为int。这里我直接使用了lambda表达式,关于lambda表达式 还请读者们自行了解吧。
public class Main { public static void main(String[] args) { Stream.of("apple","banana","orange","waltermaleon","grape") .map(e->e.length()) //转成单词的长度 int .forEach(e->System.out.println(e)); //输出 } }
当然也可以这样,这里使用了成员函数引用,为了便于读者们理解,后续的例子中将使用lambda表达式而非函数引用。
public class Main { public static void main(String[] args) { Stream.of("apple","banana","orange","waltermaleon","grape") .map(String::length) //转成单词的长度 int .forEach(System.out::println); } }
结果如图:
public class Main { public static void main(String[] args) { Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .mapToInt(e -> e.length()) //转成int .forEach(e -> System.out.println(e)); } }
mapToInt如图:
public class Main { public static void main(String[] args) { Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .mapToLong(e -> e.length()) //转成long ,本质上是int 但是存在类型自动转换 .forEach(e -> System.out.println(e)); } }
mapToLong 如图:
public class Main { public static void main(String[] args) { Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .mapToDouble(e -> e.length()) //转成Double ,自动类型转换成Double .forEach(e -> System.out.println(e)); } }
mapToDouble如图:
public class Main { public static void main(String[] args) { Stream.of("a-b-c-d","e-f-i-g-h") .flatMap(e->Stream.of(e.split("-"))) .forEach(e->System.out.println(e)); } }
flatmap 如图:
flatmapToInt、flatmapToLong、flatmapToDouble 跟flatMap 都类似的,只是类型被限定了,这里就不在举例子了。
limit 限制元素的个数,只需传入 long 类型 表示限制的最大数
public class Main { public static void main(String[] args) { Stream.of(1,2,3,4,5,6) .limit(3) //限制三个 .forEach(e->System.out.println(e)); //将输出 前三个 1,2,3 } }
limit如图:
public class Main { public static void main(String[] args) { Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1) .distinct() //去重 .forEach(e->System.out.println(e)); } }
distinct 如图:
- filter 对某些元素进行过滤,不符合筛选条件的将无法进入流的下游
public class Main { public static void main(String[] args) { Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1) .filter(e->e>=5) //过滤小于5的 .forEach(e->System.out.println(e)); } }
filter 如图:
public class Main { public static void main(String[] args) { User w = new User("w",10); User x = new User("x",11); User y = new User("y",12); Stream.of(w,x,y) .peek(e->{e.setName(e.getAge()+e.getName());}) //重新设置名字 变成 年龄+名字 .forEach(e->System.out.println(e.toString())); } static class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '/'' + ", age=" + age + '}'; } } }
peek 如图:
public class Main { public static void main(String[] args) { Stream.of(1,2,3,4,5,6,7,8,9) .skip(4) //跳过前四个 .forEach(e->System.out.println(e)); //输出的结果应该只有5,6,7,8,9 } }
skip 如图:
这里Integer 实现了比较器
public class Main { public static void main(String[] args) { Stream.of(2,1,3,6,4,9,6,8,0) .sorted() .forEach(e->System.out.println(e)); } }
sorted 默认比较器如图:
这里使用自定义比较,当然User 可以实现Comparable 接口
public class Main { public static void main(String[] args) { User x = new User("x",11); User y = new User("y",12); User w = new User("w",10); Stream.of(w,x,y) .sorted((e1,e2)->e1.age>e2.age?1:e1.age==e2.age?0:-1) .forEach(e->System.out.println(e.toString())); } static class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '/'' + ", age=" + age + '}'; } } }
如图:
这里我使用collect 将元素收集到一个set中
public class Main { public static void main(String[] args) { Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .collect(Collectors.toSet()) //set 容器 .forEach(e -> System.out.println(e)); } }
咦?,不是说终止操作符只能使用一次吗,为什么这里调用了forEach 呢?forEach不仅仅是是Stream 中得操作符还是各种集合中得一个语法糖,不信咋们试试。
public class Main { public static void main(String[] args) { Set<String> stringSet = Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .collect(Collectors.toSet()); //收集的结果就是set stringSet.forEach(e->System.out.println(e)); set的语法糖forEach }
结果如图:
public class Main { public static void main(String[] args) { long count = Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .count(); System.out.println(count); } }
count 如图:
这里找到第一个元素 apple
public class FindFirst { public static void main(String[] args) { Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .findFirst(); stringOptional.ifPresent(e->System.out.println(e)); } }
findFirst 结果如图:
public class FindAny { public static void main(String[] args) { Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape") .parallel() .findAny(); //在并行流下每次返回的结果可能一样也可能不一样 stringOptional.ifPresent(e->System.out.println(e)); } }
findAny 在并行流下 使用结果:
输出了orange
输出了banana
这里 的作用是是判断数据流中 一个都没有与aa 相等元素 ,但是流中存在 aa ,所以最终结果应该是false
public class NoneMatch { public static void main(String[] args) { boolean result = Stream.of("aa","bb","cc","aa") .noneMatch(e->e.equals("aa")); System.out.println(result); } }
noneMatch 如图:
public class Main { public static void main(String[] args) { Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1) .min((e1,e2)->e1.compareTo(e2)); integerOptional.ifPresent(e->System.out.println(e)); }
min如图:
public class Main { public static void main(String[] args) { Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1) .max((e1,e2)->e1.compareTo(e2)); integerOptional.ifPresent(e->System.out.println(e)); } }
max 如图:
这里实现了一个加法,指定了初始化的值
public class Main { public static void main(String[] args) { int sum = Stream.of(0,9,8,4,5,6,-1) .reduce(0,(e1,e2)->e1+e2); System.out.println(sum); } }
reduce 如图:
forEach 其实前就已经见过了,对每个数据遍历迭代
这里通过并行的方式输出数字
public class ForEachOrdered { public static void main(String[] args) { Stream.of(0,2,6,5,4,9,8,-1) .parallel() .forEachOrdered(e->{ System.out.println(Thread.currentThread().getName()+": "+e);}); } }
forEachOrdered 如图:
public class ToArray { public static void main(String[] args) { Object[] objects=Stream.of(0,2,6,5,4,9,8,-1) .toArray(); for (int i = 0; i < objects.length; i++) { System.out.println(objects[i]); } } }
toArray 如图:
Java8Stream 第一篇就带大家认识到这里,如果你能跟着我的文章把每一个例子都敲一遍,相信都能掌握这些操作符的初步用法;后续文章我会带大家一步步深入Stream。