1、通过 java.util.Collection.stream()
2、通过数组来创建流
3、静态方法:使用Stream的静态方法:of()、iterate()、generate()
- public class StreamJ {
- public static void main(String[] args){
- // getOfStream();
- getDusk();
-
- }
- public void anyMatch(){
- List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
- boolean b = strings.stream().anyMatch(s -> s == "abc");
- System.out.println(b);
- }
- //创建一个空流
- public static void getDusk(){
- Stream<String> ao=Stream.empty();
- //创建无限流,通过limit提取指定大小
- //随机产生20个数字,是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n
- Stream.generate(()->"number"+new Random().nextInt()).limit(20).forEach(System.out::println);
- //创建20个Student
- Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);
- }
- //通过 java.util.Collection.stream() 方法用集合创建流
- public static void getStream(){
- List<String> sl= Arrays.asList("a","b","c","d");
- //创建一个顺序流
- Stream<String> sortD=sl.stream();
- //创建一个并行流
- Stream<String> parallelStream=sl.parallelStream();
- }
- //通过数组来创建流
- public static void getArrayStream(){
- int[] arr={1,2,3,4,5};
- IntStream inStream= Arrays.stream(arr);
- }
- //使用Stream的静态方法:of()、iterate()、generate()
- public static void getOfStream(){
- Stream<Integer> instream=Stream.of(1,2,3,4,5);
- //指定一个常量seed,生成从seed到常量f的流(1,2,3,4,5)
- Stream<Integer> insreamt=Stream.iterate(0,(a)->a+1).limit(6);
- insreamt.forEach(System.out::println);
-
- //一下俩种写法输出是一样的UnaryOperator.identity()是Java8的一元运算符,输入是什么,输出就是什么
- Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
- Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
-
- //下面是对循环的写法
- Stream.iterate(0,(a)->a+1).limit(6).forEach(a->{
- System.out.print(a +"\n");
- });
-
- Stream<Double> dStream=Stream.generate(Math::random).limit(5);
- dStream.forEach(System.out::println);
-
- //以上代码等同于
- DoubleStream intStream = DoubleStream.generate(()
- -> { return (int)(Math.random()); });
- intStream.limit(5).forEach(System.out::println);
-
- }
-
- static class Student{
- private String name;
- private int age;
-
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
- }
以下几点需要注意:
lambda表达式的一种简写,这种简写的学名叫eta-conversion或者叫η-conversion 把 x -> System.out.println(x) 简化为 System.out::println 的过程称之为 eta-conversion 把 System.out::println 简化为 x -> System.out.println(x) 的过程称之为 eta-expansion 范式: 类名::方法名 方法调用 person -> person.getAge(); 可以替换成 Person::getAge x -> System.out.println(x) 可以替换成 System.out::println out是一个PrintStream类的对象,println是该类的方法,依据x的类型来重载方法 创建对象 () -> new ArrayList<>(); 可以替换为 ArrayList::new new关键字实际上调用的是ArrayList的构造方法
//描述:一元运算,接受一个T类型参数,输出一个与入参一模一样的值 System.out.println(UnaryOperator.identity().apply(10)); // 10 System.out.println(UnaryOperator.identity().apply(10.01)); // 10.01 System.out.println(UnaryOperator.identity().apply(false)); // false System.out.println(UnaryOperator.identity().apply("10")); // 10 UnaryOperatorb = x->x.intValue(); // lambda表达式,这样就只能输入Integer类型了 System.out.println(b.apply(10));
流多种形式:
- //创建普通流
- Stream<String> stream = strs.stream();
- //创建并行流
- Stream<String> stream1 = strs.parallelStream();
- //创建一个空的stream
- Stream<Integer> stream = Stream.empty();
- //创建无限流,通过limit提取指定大小
- Stream.generate(()->"number"+new Random().nextInt()).limit(100).forEach(System.out::println);
- Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);
-
-
-
- Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println);
- Stream.iterate(0,x->x).limit(10).forEach(System.out::println);
- //Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的
- Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
基本数值型流:
- IntStream
- LongStream
- DoubleStream
当然我们也可以用 Stream
、Stream >、Stream ,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。
基本数值型流:
- IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
- IntStream.range(1, 3).forEach(System.out::println);
- IntStream.rangeClosed(1, 3).forEach(System.out::println);
流转换为其它数据结构 :
- // 1. Array
- String[] strArray1 = stream.toArray(String[]::new);
- // 2. Collection
- List<String> list1 = stream.collect(Collectors.toList());
- List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
- Set set1 = stream.collect(Collectors.toSet());
- Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
- // 3. String
- String str = stream.collect(Collectors.joining()).toString();
常见操作分类:
当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。注意:这些中间操作是惰性求值的,也就是说,只有在终止操作被调用时才开始执行。这种方式可以大大减少操作的开销,使得Stream的处理更加高效。
- Intermediate(中间操作符):
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
- Terminal(最终操作符):
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
- Short-circuiting(对符合条件的流元素进行最终操作):
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
实例:
- 1)filter
-
- /**
- * 功能描述:根据条件过滤集合数据
- * @return : void
- */
- @Test
- public void filter(){
- List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
- List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
- System.out.println(filtered);
- }
- 2)distinct
-
- /**
- * 功能描述:去除集合中重复数据
- * @return : void
- */
- @Test
- public void distinct(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- List<String> distincted = strings.stream().distinct().collect(Collectors.toList());
- System.out.println(distincted);
- }
- 3)limit
-
- /**
- * 功能描述:指定获取集合前x条数据,重新构造一个新的集合
- * @return : void
- */
- @Test
- public void limit(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- List<String> limited = strings.stream().limit(3).collect(Collectors.toList());
- System.out.println(limited);
- }
- 4)skip
-
- /**
- * 功能描述:排除集合前x条数据,把后面的数据重新构造一个新的集合
- * @return : void
- */
- @Test
- public void skip(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- List<String> skiped = strings.stream().skip(3).collect(Collectors.toList());
- System.out.println(skiped);
- }
- 5)map
-
- /**
- * 功能描述:对集合中所有元素统一处理
- * @return : void
- */
- @Test
- public void map(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- List<String> mapped = strings.stream().map(str->str+"-itcast").collect(Collectors.toList());
- System.out.println(mapped);
- }
- 6)flatMap
-
- /**
- * 功能描述:对集合中所有元素统一处理
- * @return : void
- */
- @Test
- public void flatMap(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- Stream<String> stringStream = strings.stream().map(x -> x);
- Stream<String> stringStream1 = strings.stream().flatMap(x -> Arrays.asList(x.split(" ")).stream());
- }
- 7)sorted
-
- /**
- * 功能描述 : 对集合进行排序
- * @return : void
- */
- @Test
- public void sorted(){
- List<String> strings1 = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
- List<String> strings2 = Arrays.asList("张三", "李四", "王五", "赵柳", "张哥","李哥", "王哥");
- List<Integer> strings3 = Arrays.asList(10, 2, 30, 22, 1,0, -9);
- List<String> sorted1 = strings1.stream().sorted().collect(Collectors.toList());
- List<String> sorted2 = strings2.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA))).collect(Collectors.toList());
- List<Integer> sorted3 = strings3.stream().sorted().collect(Collectors.toList());
- System.out.println(sorted1);
- System.out.println(sorted2);
- System.out.println(sorted3);
- }
Map、flatMap区别
map:对流中每一个元素进行处理
flatMap:流扁平化,让你把一个流中的“每个值”都换成另一个流,然后把所有的流连接起来成为一个流
总结:map是对一级元素进行操作,flatmap是对二级元素操作。
本质区别:map返回一个值;flatmap返回一个流,多个值。应用场景:map对集合中每个元素加工,返回加工后结果;flatmap对集合中每个元素加工后,做扁平化处理后(拆分层级,放到同一层)然后返回
- /**
- * 方法一
- * 功能描述: 通过使用map、flatMap把字符串转换为字符输出对比区别
- * @return : void
- */
- @Test
- public void flatMap2Map(){
- List<String> strings = Arrays.asList("abc", "abc", "bc", "efg", "abcd","jkl", "jkl");
- final Stream<Character> flatMap = strings.stream().flatMap(Java8StreamTest::getCharacterByString);
- flatMap.forEach(System.out::println);
- //----------------------------------------------
- final Stream<Stream<Character>> mapStream = strings.stream().map(Java8StreamTest::getCharacterByString);
- //mapStream.forEach(System.out::println);
- System.out.println("------------------------------------------------");
- mapStream.forEach(stream-> {stream.forEach(character->{System.out.println(character);});});
-
- }
-
- 公共方法(字符串转换为字符流)
-
- /**
- * 功能描述:字符串转换为字符流
- * @param str
- * @return : java.util.stream.Stream<java.lang.Character>
- */
- public static Stream<Character> getCharacterByString(String str) {
- List<Character> characterList = new ArrayList<>();
- for (Character character : str.toCharArray()) {
- characterList.add(character);
- }
- return characterList.stream();
- }
终止操作符:
- 1)anyMatch
-
- /**
- * 功能描述 : 判断集合中是否至少存在一个元素满足条件
- * @return : void
- */
- @Test
- public void anyMatch(){
- List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
- boolean b = strings.stream().anyMatch(s -> s == "abc");
- System.out.println(b);
- }
- 2)allMatch
-
- /**
- * 功能描述 : 判断集合中是否所有元素都满足条件
- * @return : void
- */
- @Test
- public void allMatch(){
- List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
- boolean b = strings.stream().allMatch(s -> s == "abc");
- System.out.println(b);
- }
- 3)noneMatch
-
- /**
- * 功能描述 : 判断集合中是否所有元素都不满足条件
- * @return : void
- */
- @Test
- public void noneMatch(){
- List<String> strings = Arrays.asList("abc", "abd", "aba", "efg", "abcd","jkl", "jkl");
- boolean b = strings.stream().noneMatch(s -> s == "abc");
- System.out.println(b);
- }
- 4)findAny
-
- /**
- * 功能描述 : 返回当前流中任意元素
- * @return : void
- */
- @Test
- public void findAny(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- Optional<String> any = strings.stream().findAny();
- if(any.isPresent()) out.println(any.get());
- }
- 5)findFirst
-
- /**
- * 功能描述 : 返回当前流中第一个元素
- * @return : void
- */
- @Test
- public void findFirst(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- Optional<String> first = strings.stream().findFirst();
- if(first.isPresent()) System.out.println(first.get());
- }
- 6)forEach java
-
- /**
- * 功能描述 : 遍历流
- * @return : void
- */
- @Test
- public void foreach(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- strings.stream().forEach(s -> System.out.println(s));
- }
- 7)collect
-
- /**
- * 功能描述 : 流转换为其他形式
- * @return : void
- */
- @Test
- public void collect(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- Set<String> set = strings.stream().collect(Collectors.toSet());
- List<String> list = strings.stream().collect(Collectors.toList());
- Map<String, String> map = strings.stream().collect(Collectors.toMap(v ->v.concat("_name"), v1 -> v1, (v1, v2) -> v1));
- System.out.println(set);
- System.out.println(list);
- System.out.println(map);
- }
- 8)reduce
-
- /**
- * 功能描述 : 将流中元素反复结合起来,得到一个值
- * @return : void
- */
- @Test
- public void reduce(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- //reduce方法一
- Optional<String> reduce1 = strings.stream().reduce((acc,item) -> {return acc+item;});
- //reduce方法二
- String reduce2 = strings.stream().reduce("itcast", (acc, item) -> {
- return acc + item;
- });
- //reduce方法三
- ArrayList<String> reduce3 = strings.stream().reduce(
- new ArrayList<String>(),
- new BiFunction<ArrayList<String>, String, ArrayList<String>>() {
- @Override
- public ArrayList<String> apply(ArrayList<String> acc, String item) {
- acc.add(item);
- return acc;
- }
- },
- new BinaryOperator<ArrayList<String>>() {
- @Override
- public ArrayList<String> apply(ArrayList<String> acc, ArrayList<String> item) {
- return acc;
- }
- }
- );
- if(reduce1.isPresent())out.println(reduce1.get());
- System.out.println(reduce2);
- System.out.println(reduce3);
- }
-
- 9)count
-
- /**
- * 功能描述 : 返回流中元素总数
- * @return : void
- */
- @Test
- public void count(){
- List<String> strings = Arrays.asList("cv", "abd", "aba", "efg", "abcd","jkl", "jkl");
- long count = strings.stream().count();
- System.out.println(count);
- }
forEach
forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。
- // Java 8
- roster.stream()
- .filter(p -> p.getGender() == Person.Sex.MALE)
- .forEach(p -> System.out.println(p.getName()));
- // Pre-Java 8
- for (Person p : roster) {
- if (p.getGender() == Person.Sex.MALE) {
- System.out.println(p.getName());
- }
- }
- 转换成大写字母:
- List<String> output = wordList.stream().
- map(String::toUpperCase).
- collect(Collectors.toList());
-
- 输出平方数:
- List<Integer> nums = Arrays.asList(1, 2, 3, 4);
- List<Integer> squareNums = nums.stream().
- map(n -> n * n).
- collect(Collectors.toList());
-
- flatMap一对多:
- Stream<List<Integer>> inputStream = Stream.of(
- Arrays.asList(1),
- Arrays.asList(2, 3),
- Arrays.asList(4, 5, 6)
- );
- Stream<Integer> outputStream = inputStream.
- flatMap((childList) -> childList.stream());
filter:
- 留下偶数:
- Integer[] sixNums = {1, 2, 3, 4, 5, 6};
- Integer[] evens =
- Stream.of(sixNums).filter(n -> n%2 == 0).toArray(Integer[]::new);
-
- 把单词挑出来:
- List<String> output = reader.lines().
- flatMap(line -> Stream.of(line.split(REGEXP))).
- filter(word -> word.length() > 0).
- collect(Collectors.toList());
peek:不是一个最终操作,不会影响“哪些元素会流过”,所以十分适合在调试的时候,用来打印出流经管道的元素。forEach 不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环。
- Stream.of("one", "two", "three", "four")
- .filter(e -> e.length() > 3)
- .peek(e -> System.out.println("Filtered value: " + e))
- .map(String::toUpperCase)
- .peek(e -> System.out.println("Mapped value: " + e))
- .collect(Collectors.toList());
reduce:这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce
- // 字符串连接,concat = "ABCD"
- String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
- // 求最小值,minValue = -3.0
- double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
- // 求和,sumValue = 10, 有起始值
- int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
- // 求和,sumValue = 10, 无起始值
- sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
- // 过滤,字符串连接,concat = "ace"
- concat = Stream.of("a", "B", "c", "D", "e", "F").
- filter(x -> x.compareTo("Z") > 0).
- reduce("", String::concat);
sorted:对 Stream 的排序通过 sorted 进行,它比数组的排序更强之处在于你可以首先对 Stream 进行各类 map、filter、limit、skip 甚至 distinct 来减少元素数量后,再排序,这能帮助程序明显缩短执行时间。
- List<Person> persons = new ArrayList();
- for (int i = 1; i <= 5; i++) {
- Person person = new Person(i, "name" + i);
- persons.add(person);
- }
- List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
- System.out.println(personList2);
min/max/distinct
- 找出字符最长的一行:
- BufferedReader br = new BufferedReader(new FileReader("c:\\SUService.log"));
- int longest = br.lines().
- mapToInt(String::length).
- max().
- getAsInt();
- br.close();
- System.out.println(longest);
-
-
- 用distinct找出全文的单词,转小写,并排序:
- List<String> words = br.lines().
- flatMap(line -> Stream.of(line.split(" "))).
- filter(word -> word.length() > 0).
- map(String::toLowerCase).
- distinct().
- sorted().
- collect(Collectors.toList());
- br.close();
- System.out.println(words);
limit和skip
- 这是一个有 10,000 个元素的 Stream,但在 short-circuiting 操作 limit 和 skip 的作用下,管道中 map 操作指定的 getName() 方法的执行次数为 limit 所限定的 10 次,而最终返回结果在跳过前 3 个元素后只有后面 7 个返回。
- public void testLimitAndSkip() {
- List<Person> persons = new ArrayList();
- for (int i = 1; i <= 10000; i++) {
- Person person = new Person(i, "name" + i);
- persons.add(person);
- }
- List<String> personList2 = persons.stream().
- map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
- System.out.println(personList2);
- }
- private class Person {
- public int no;
- private String name;
- public Person (int no, String name) {
- this.no = no;
- this.name = name;
- }
- public String getName() {
- System.out.println(name);
- return name;
- }
- }
Stream 有三个 match 方法,从语义上说:
- allMatch:Stream 中全部元素符合传入的 predicate,返回 true
- anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
- noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
它们都不是要遍历全部元素才能返回结果。例如 allMatch 只要一个元素不满足条件,就 skip 剩下的所有元素,返回 false。对清单 13 中的 Person 类稍做修改,加入一个 age 属性和 getAge 方法。
- List<Person> persons = new ArrayList();
- persons.add(new Person(1, "name" + 1, 10));
- persons.add(new Person(2, "name" + 2, 21));
- persons.add(new Person(3, "name" + 3, 34));
- persons.add(new Person(4, "name" + 4, 6));
- persons.add(new Person(5, "name" + 5, 55));
- boolean isAllAdult = persons.stream().
- allMatch(p -> p.getAge() > 18);
- System.out.println("All are adult? " + isAllAdult);
- boolean isThereAnyChild = persons.stream().
- anyMatch(p -> p.getAge() < 12);
- System.out.println("Any child? " + isThereAnyChild);
Stream.generate
通过实现 Supplier 接口,你可以自己来控制流的生成。
- Stream.generate(new PersonSupplier()).
- limit(10).
- forEach(p -> System.out.println(p.getName() + ", " + p.getAge()));
- private class PersonSupplier implements Supplier<Person> {
- private int index = 0;
- private Random random = new Random();
- @Override
- public Person get() {
- return new Person(index++, "StormTestUser" + index, random.nextInt(100));
- }
- }
Collectors 来进行分组操作:
groupingBy/partitioningBy
- 按照年龄进行分组:
-
- Map<Integer, List<Person>> personGroups = Stream.generate(new PersonSupplier()).
- limit(100).
- collect(Collectors.groupingBy(Person::getAge));
- Iterator it = personGroups.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<Integer, List<Person>> persons = (Map.Entry) it.next();
- System.out.println("Age " + persons.getKey() + " = " + persons.getValue().size());
- }
-
-
-
- 按照未成年人和成年人归组:
- Map<Boolean, List<Person>> children = Stream.generate(new PersonSupplier()).
- limit(100).
- collect(Collectors.partitioningBy(p -> p.getAge() < 18));
- System.out.println("Children number: " + children.get(true).size());
- System.out.println("Adult number: " + children.get(false).size());