Stream 流

一、Java 8 新特性

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。

1.1、传统集合的多步遍历代码

几乎所有的集合(如 Collection 接口或 Map 接口等)都支持直接或间接的遍历操作。而当我们需要对集合中的元 素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。例如:

	public static void listDemo() {
        List<String> list = new ArrayList<> ();
        list.add ("1");
        list.add ("2");
        list.add ("3");
        list.add ("4");
        list.add ("5");
        for (String l : list) {
            System.out.print (l + " "); // 1 2 3 4 5
        }
    }

1.2、循环遍历的弊端

Java 8 的Lambda 让我们可以更加专注于做什么(What),而不是怎么做(How),现在,我们仔细体会一下上例代码,可以发现:

  • for循环的语法就是“怎么做”
  • for循环的循环体才是“做什么”

为什么使用循环?因为要进行遍历。但循环是遍历的唯一方式吗?遍历是指每一个元素逐一进行处理,而并不是从第一个到最后一个顺次处理的循环。前者是目的,后者是方式。试想一下,如果希望对集合中的元素进行筛选过滤:

  • 将集合A根据条件一过滤为子集B;
  • 然后再根据条件二过滤为子集C。

那怎么办?在Java 8之前的做法可能为:

	public static void listDemo() {
        List<String> list = new ArrayList<> ();
        list.add ("1");
        list.add ("12");
        list.add ("3");
        list.add ("14");
        list.add ("5");
        List<String> list1 = new ArrayList<> ();
        for (String li : list) {
        	// 过滤条件1
            if (li != null && li.startsWith ("1")) {
                list1.add (li);
            }
        }
        System.out.println (list1); // [1, 12, 14]
        List<String> result = new ArrayList<> ();
        for (String li : list1) {
        	// 过滤条件2
            if (li != null && li.length () == 2) {
                result.add (li);
            }
        }

        for (String li : result) {
            System.out.print (li + " "); // 12 14 
        }
    }

使用Stream 处理同样的逻辑,代码如下,可以看出使用Stream 的代码更简洁,更优雅。

	public static void listStreamDemo() {
        List<String> list = new ArrayList<> ();
        list.add ("1");
        list.add ("12");
        list.add ("3");
        list.add ("14");
        list.add ("5");
       	
        list.stream ()
                .filter (s -> s.startsWith ("1"))
                .filter (s -> s.length () == 2)
                .forEach (System.out::println);
    }

二、获取流

获取一个流非常简单,有以下几种常用的方式:

  • 所有的 Collection 集合都可以通过 stream 默认方法获取流;
  • Stream 接口的静态方法 of 可以获取数组对应的流。

2.1、根据 Map 获取流

  • java.util.Map 接口不是 Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,
  • 所以获取对应的流 需要分key、value或entry等情况:
	Map<String, String> map = new HashMap<> ();
	Stream<String> keyStream = map.keySet ().stream ();
	Stream<String> valueStream = map.values ().stream ();
	Stream<Map.Entry<String, String>> entryStream = map.entrySet ().stream ();

2.2、根据数组获取流

		int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Stream<int[]> intStream = Stream.of (intArray);
        
        Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Stream<Integer> integerStream = Stream.of (integerArray);

三、常用方法

3.1、过滤:filter

可以通过 filter 方法将一个流转换成另一个子集流。方法签名:

	Stream<T> filter(Predicate<? super T> predicate);

该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件,该接口唯一一个抽象方法:

	boolean test(T t);

3.1.1、基本使用

	private static void filterDemo() {
        List<String> list = new ArrayList<> ();
        list.add ("1");
        list.add ("12");
        list.add ("3");
        list.add ("14");
        list.add ("5");
        System.out.println (list);
        // list.stream ().filter (new Predicate () {
        //     @Override
        //     public boolean test(String s) {
        //         if (s.length () == 2) {
        //             return true;
        //         } else {
        //             return false;
        //         }
        //     }
        // });
        list.stream ().filter (s -> s.length () == 2);
    }

3.1.2、filter 自定义引用类型的去重规则

实体类
	// 省
	public class Province {
        private String pname; // 省名称

        private List<City> cities;

        public String getPname() {
            return pname;
        }

        public void setPname(String pname) {
            this.pname = pname;
        }

        public List<City> getCities() {
            return cities;
        }

        public void setCities(List<City> cities) {
            this.cities = cities;
        }

        @Override
        public String toString() {
            return "Province{" +
                    "pname='" + pname + '\'' +
                    ", cities=" + cities +
                    '}';
        }
    }

	// 市
    public class City {
        private String cid; // 城市id
        private String cname; // 城市名称

        public City(String cid, String cname) {
            this.cid = cid;
            this.cname = cname;
        }

        public String getCid() {
            return cid;
        }

        public void setCid(String cid) {
            this.cid = cid;
        }

        public String getCname() {
            return cname;
        }

        public void setCname(String cname) {
            this.cname = cname;
        }

        @Override
        public String toString() {
            return "City{" +
                    "cid='" + cid + '\'' +
                    ", cname='" + cname + '\'' +
                    '}';
        }
    }
用例
	static List<City> cities = new ArrayList<> ();
    static {
        cities.add (new City ("12", "上海"));
        cities.add (new City ("12", "上海"));
        cities.add (new City ("12", "上海"));
        cities.add (new City ("13", "南京"));
        cities.add (new City ("14", "常州"));
    }
    
    private static void filterDistinctDemo() {
        // cities.stream ().filter (distinctByKey(city -> city.getCname ())).forEach (city -> System.out.println (city));
        // 下面这行代码等同于上面
        cities.stream ().filter (distinctByKey (new Function<City, String> () {
            // 回调函数
            @Override
            public String apply(City city) {
                // 去重字段
                return city.getCname ();
            }
        })).forEach (city -> System.out.println (city)); 
    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<> ();
        // return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
        // 下面这段代码等同于上面这行
        Predicate<T> predicate = new Predicate<T> () {
        	// filter:test 方法返回true时,保留;返回false时,过滤
            @Override
            public boolean test(T t) {
                // keyExtractor.apply (t) 会回掉上面的apply 方法,回去返回值
                Boolean b = seen.putIfAbsent (keyExtractor.apply (t), Boolean.TRUE);
                // putIfAbsent 首次插入到map 的key,该方法返回null,不是首次时返回true
                return b == null;
            }
        };
        return predicate;
    }

运行结果
	City{cid='12', cname='上海'}
	City{cid='13', cname='南京'}
	City{cid='14', cname='常州'}

3.2、映射:map

如果需要将流中的元素映射到另一个流中,可以使用 map 方法。该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。 方法签名:

	<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map 用例
	public static void mapDemo() {
        Stream<String> original = Stream.of("10", "12", "18");
        Stream<Integer> result = original.map(Integer::parseInt);
    }
	
	public static void mapDemo2 () {
        Stream<City> cityStream = entities.stream ().map (entity -> {
            City city = new City (entity.getCid (), entity.getCname ());
            return city;
        });
    }

3.3、最多截取流的个数:limit

limit 方法可以对流进行截取,只取用前n个。参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作。方法签名:

	Stream<T> limit(long maxSize);
limit 实例
	public static void limitDemo() {
        Stream<String> original = Stream.of("10", "12", "18").limit (2);
        original.forEach (o -> {
            System.out.print (o + " ");
        });
    }
运行结果
	10 12 

3.4. 跳过前几个:skip

如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流;如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。方法签名:

	Stream skip(long n);
skip 用例
	public static void skipDemo() {
        Stream<String> original = Stream.of("10", "12", "18").skip (2);
        original.forEach (o -> {
            System.out.print (o + " ");
        });
    }
运行结果
	18  

3.5、统计个数:count

正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数。该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。方法签名:

	long count();
count 用例
	public static void countDemo () {
        long count = Stream.of ("10", "12", "18").skip (2).count ();
        System.out.println (count);
    }
运行结果
	1  

3.6、组合:concat

如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat 。方法签名:

	public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
contact 用例
	public  static void contactDemo() {
        Stream<String> a = Stream.of ("10", "12", "18");
        Stream<Integer> b = Stream.of (1, 2, 3, 4);
        Stream.concat (a, b).forEach (s -> {
            System.out.print (s + " ");
        });
    }
运行结果
	10 12 18 1 2 3 4

3.7、逐一处理:forEach、forEachOrdered

forEach 与for循环中的“for-each”昵称不同,该方法并不保证元素的逐一消费动作在流中是被有序执行的。

	void forEach(Consumer<? super T> action);

forEachOrdered 是按顺序处理的,没有forEach 的处理速度快

	void forEachOrdered(Consumer<? super T> action);

对Stream 流这两个方法是一样的,因为stream() 是串行流,对parallelStream () 前者是无序的,后者是有序的

forEach、forEachOrdered 用例
	public static void forEachDemo() {
        List<Integer> numbers = new ArrayList<> (Arrays.asList (1, 2, 3, 4, 5, 6, 7, 8, 9));
        // 串行流 输出是有序的
        numbers.stream ().forEach (n -> {
            System.out.print (n + " ");
        });
        System.out.println ("\r\n-----------------");
        
        // 输出是有序的
        numbers.stream ().forEachOrdered (n -> {
            System.out.print (n + " ");
        });
        System.out.println ("\r\n-----------------");
        
        // 并行流 输出是无序的
       	numbers.parallelStream ().forEach (n -> {
            System.out.print (n + " ");
        });
        System.out.println ("\r\n-----------------");
        
        // 输出是有序的
        numbers.parallelStream ().forEachOrdered (n -> {
            System.out.print (n + " ");
        });
    }
运行结果
	1 2 3 4 5 6 7 8 9 
	-----------------
	1 2 3 4 5 6 7 8 9 
	-----------------
	6 5 7 9 8 2 3 1 4 
	-----------------
	1 2 3 4 5 6 7 8 9 

3.8、并发流 :parallel、parallelStream

stream 转换为并发流,Stream 的父接口 java.util.stream.BaseStream 中定义了一个 parallel 方法:

	S parallel();

只需要在流上调用一下无参数的 parallel 方法,那么当前流即可变身成为支持并发操作的流,返回值仍然为 Stream 类型。例如:

	public static void parallelDemo() {
		List<Integer> numbers = new ArrayList<> (Arrays.asList (1, 2, 3, 4, 5, 6, 7, 8, 9));
        numbers.stream ().parallel ().forEach (n -> {
            System.out.print (n + " ");
        });
	}
运行结果
	6 5 8 9 3 4 7 2 1

直接获取并发流,在通过集合获取流时,也可以直接调用接口 java.util.Collection 中的parallelStream 方法来直接获取支持并发操作的流。方法定义为:

	default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
用例
	public static void parallelStreamDemo() {
		List<Integer> numbers = new ArrayList<> (Arrays.asList (1, 2, 3, 4, 5, 6, 7, 8, 9));
        numbers.parallelStream ().forEach (n -> {
            System.out.print (n + " ");
        });
	}
运行结果
	6 5 7 9 8 2 3 1 4 

3.9、去重:distinct

该方法用于去除集合中重复的元素,方法签名为:

	Stream<T> distinct();

基本类型或引用类型的String 可以直接使用该方法去重,如果是其他的引用类型的数据,需要重写hashCodeequals 方法,自定义去重规则。

用例
	 public static void listDemo() {
        List<String> list = new ArrayList<> ();
        list.add ("1");
        list.add ("1");
        list.add ("1");
        list.add ("12");
        list.add ("3");
        list.add ("14");
        list.add ("5");
        list.stream ().distinct ().forEach (s -> {
            System.out.print (s + " ");
        });
   	}
运行结果
	1 12 3 14 5 

3.10、收集到集合中:collect

Stream流提供 collect 方法,其参数需要一个 java.util.stream.Collector 接口对象来指定收集到哪种 集合中。幸运的是, java.util.stream.Collectors 类提供一些方法,可以作为 Collector 接口的实例:

	public final class Collectors {
		// 转换为 List 集合。
		public static <T> Collector<T, ?, List<T>> toList();
		// 转换为 Set 集合。
		public static <T> Collector<T, ?, Set<T>> toSet();
		// 转换为 Map 集合。
		public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
	                                    Function<? super T, ? extends U> valueMapper);
	    // 转换成集合,集合类型由参数类型确定                           
	    public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory);
	                                     
	   // 拼接字符串,有多个重载方法
	   public static Collector<CharSequence, ?, String> joining();                                  
	   public static Collector<CharSequence, ?, String> joining(CharSequence delimiter);   
	   public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
	                                                             CharSequence prefix,
	                                                             CharSequence suffix);      
	    // 最大值、最小值、求和、平均值                                                         
	    public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator);
	    public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator);
	    public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper);      
	    public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper);                   
	    
	    // 分组:可以分成true和false两组,也可以根据字段分成多组                                 
		public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier);
		public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream)
		public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> 
			groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream)
		// 只能分成true和false两组
		public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate);
		
		 // 映射
		 public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
	                               Collector<? super U, A, R> downstream);
	     // 
		 public static <T, U> Collector<T, ?, U> reducing(U identity,
	                                Function<? super T, ? extends U> mapper,
	                                BinaryOperator<U> op);
	}

3.10.1、toList 的用例

	public static void toListDemo() {
        List<String> list = Stream.of ("10", "12", "18").collect (Collectors.toList ());
        System.out.println (list); // [10, 10, 12, 18]
    }

3.10.2、toSet 的用例

	public static void toSetDemo() {
        Set<String> set = Stream.of ("10", "10", "12", "18").collect (Collectors.toSet ());
        System.out.println (set); // [12, 18, 10]
    }

3.10.3、toMap 的用例

注意:不能有相同的key 否则会抛出java.lang.IllegalStateException: Duplicate key (重复的Key值)

	public static void toMapDemo() {
        Map<String, String> map = Stream.of ("10", "12", "18").collect (Collectors.toMap (key -> "key" + key, value -> value));
        System.out.println (map); // {key12=12, key18=18, key10=10}
    }

3.10.4、toCollection 的用例

	public static void toCollectionDemo() {
        ArrayList<String> list = Stream.of ("10", "10", "12", "18").collect (Collectors.toCollection (ArrayList::new));
        System.out.println (list); // [10, 10, 12, 18]
        
        TreeSet<String> set = Stream.of ("10", "10", "12", "18").collect (Collectors.toCollection (TreeSet::new));
        System.out.println (set); // [10, 12, 18]
    }

3.10.5、joining 的用例

	public static void joiningDemo() {
        String join = Stream.of ("10", "10", "12", "18").collect (Collectors.joining ());
        System.out.println (join); // 10101218

        join = Stream.of ("10", "10", "12", "18").collect (Collectors.joining (","));
        System.out.println (join); // 10,10,12,18

        join = Stream.of ("10", "10", "12", "18").collect (Collectors.joining (", ", "[", "]"));
        System.out.println (join); // [10, 10, 12, 18]
    }

3.10.6、元素聚合的用例

	public static void demo() {
        Optional<String> optional = Stream.of ("10", "10", "12", "18").collect (Collectors.maxBy ((s1, s2) -> Integer.valueOf (s1) - Integer.valueOf (s2)));
        System.out.println (optional.get ()); // 18

        String max = Stream.of ("10", "10", "12", "18").collect (Collectors.collectingAndThen (Collectors.maxBy ((String s1, String s2) -> Integer.valueOf (s1) - Integer.valueOf (s2)), Optional::get));
        System.out.println (max); // 18

        String min = Stream.of ("10", "10", "12", "18").collect (Collectors.collectingAndThen (Collectors.minBy ((s1, s2) -> Integer.valueOf (s1) - Integer.valueOf (s2)), Optional::get));
        System.out.println (min); // 10

        Integer sum = Stream.of ("10", "10", "12", "18").collect (Collectors.summingInt (s -> Integer.valueOf (s.toString ())));
        System.out.println (sum); // 50

        Double average = Stream.of ("10", "10", "12", "18").collect (Collectors.averagingDouble (s -> Integer.valueOf (s.toString ())));
        System.out.println (average); // 12.5
    }

3.10.7、分组partitioningBy、groupingBy 用例

	public static void groupByDemo() {
        Map<Boolean, List<String>> partition = Stream.of ("10", "1", "2", "12", "18", "200").collect (Collectors.partitioningBy (s -> s.length () == 2));
        System.out.println (partition); // {false=[1, 2, 200], true=[10, 12, 18]}

        Map<Boolean, List<String>> partitioning = Stream.of ("10", "1", "2", "12", "18", "200").collect (Collectors.partitioningBy (s -> s.length () == 2, Collectors.toList ()));
        System.out.println (partitioning); // {false=[1, 2, 200], true=[10, 12, 18]}

        Map<Boolean, List<String>> grouping = Stream.of ("10", "1", "2", "12", "18", "200").collect (Collectors.groupingBy (s -> s.length () == 2));
        System.out.println (grouping); // {false=[1, 2, 200], true=[10, 12, 18]}

        /**
         * entities:
         * [
         *    ProvinceEntity{pname='上海', cid='11', cname='上海'}, 
         *    ProvinceEntity{pname='浙江', cid='12', cname='杭州'}, 
         *    ProvinceEntity{pname='浙江', cid='13', cname='台州'}, 
         *    ProvinceEntity{pname='浙江', cid='14', cname='宁波'}, 
         *    ProvinceEntity{pname='浙江', cid='15', cname='温州'}, 
         *    ProvinceEntity{pname='江苏', cid='16', cname='南京'}, 
         *    ProvinceEntity{pname='江苏', cid='17', cname='无锡'}, 
         *    ProvinceEntity{pname='江苏', cid='18', cname='盐城'}, 
         *    ProvinceEntity{pname='江苏', cid='19', cname='扬州'}, 
         *    ProvinceEntity{pname='江苏', cid='111', cname='宿迁'}
         * ]
         */
        Map<String, List<String>> provinces = entities.stream ().collect (Collectors.groupingBy (entity -> entity.getPname (), Collectors.mapping (entity -> entity.getCname (), Collectors.toList ())));
        System.out.println (provinces); // {上海=[上海], 浙江=[杭州, 台州, 宁波, 温州], 江苏=[南京, 无锡, 盐城, 扬州, 宿迁]}

        ConcurrentHashMap<Boolean, Integer> collect = Stream.of ("10", "1", "2", "12", "18", "200").collect (Collectors.groupingBy (s -> s.length () == 2, ConcurrentHashMap::new, Collectors.summingInt (s -> Integer.valueOf (s))));
        System.out.println (collect); // {false=203, true=40}
	}

3.10.8、映射mapping 方法用例

	public static void mappingDemo() {
		/**
         * [
         *    ProvinceEntity{pname='上海', cid='11', cname='上海'},
         *    ProvinceEntity{pname='浙江', cid='12', cname='杭州'},
         *    ProvinceEntity{pname='浙江', cid='13', cname='台州'},
         *    ProvinceEntity{pname='浙江', cid='14', cname='宁波'},
         *    ProvinceEntity{pname='浙江', cid='15', cname='温州'},
         *    ProvinceEntity{pname='江苏', cid='16', cname='南京'},
         *    ProvinceEntity{pname='江苏', cid='17', cname='无锡'},
         *    ProvinceEntity{pname='江苏', cid='18', cname='盐城'},
         *    ProvinceEntity{pname='江苏', cid='19', cname='扬州'},
         *    ProvinceEntity{pname='江苏', cid='111', cname='宿迁'}
         * ]
         */
        List<String> cities = entities.stream ().collect (Collectors.mapping (ProvinceEntity::getCname, Collectors.toList ()));
        System.out.println (cities); // [上海, 杭州, 台州, 宁波, 温州, 南京, 无锡, 盐城, 扬州, 宿迁]
	}

3.10.9、reducing 方法用例

用例
	private static void reducingDemo() {
        // sum: 是每次累计计算的结果,s是数组中的元素
        Integer reducing = Stream.of ("10", "1", "2", "12", "18", "200").collect (Collectors.reducing (0, s -> Integer.valueOf (s),  (sum, s) -> {
            System.out.print("sum = " + sum + "; ");
            System.out.println("s = " + s);
            return sum + s;
        }));
        System.out.println ("reducing = " + reducing);
        System.out.println ("----------------");

        // 下面这段代码和上面的一样
        int sum = 0;
        List<String> integers = Arrays.asList("10", "1", "2", "12", "18", "200");
        for (String item : integers) {
            int s = Integer.valueOf (item);
            System.out.print ("sum = " + sum + "; ");
            System.out.println("s = " + s);
            sum = sum + s;
        }
        System.out.println("sum = " + sum);
        System.out.println ("----------------");

        Integer result = Stream.of ("5", "1", "2", "4", "3", "6").collect (Collectors.reducing (1, x -> Integer.valueOf (x + 1), (multiply, x) -> {
            System.out.print("x = " + x + "; ");
            System.out.println ("multiply = " + multiply);
            return multiply * x;
        }));

        System.out.println("result = " + result);
	}
运行结果
	sum = 0; s = 10
	sum = 10; s = 1
	sum = 11; s = 2
	sum = 13; s = 12
	sum = 25; s = 18
	sum = 43; s = 200
	reducing = 243
	----------------
	sum = 0; s = 10
	sum = 10; s = 1
	sum = 11; s = 2
	sum = 13; s = 12
	sum = 25; s = 18
	sum = 43; s = 200
	sum = 243
	----------------
	x = 51; multiply = 1
	x = 11; multiply = 51
	x = 21; multiply = 561
	x = 41; multiply = 11781
	x = 31; multiply = 483021
	x = 61; multiply = 14973651
	result = 913392711

3.11. 收集到数组中 : toArray

Stream提供 toArray 方法来将结果放到一个数组中,由于泛型擦除的原因,返回值类型是Object[]的:

	Object[] toArray();

有了Lambda和方法引用之后,可以使用 toArray 方法的另一种重载形式传递一个 IntFunction 的函数,继而从外面指定泛型参数。方法签名:

	<A> A[] toArray(IntFunction<A[]> generator);

有了它,上例代码中不再局限于 Object[] 结果,而可以得到自定义的结果:

	public  static void toArrayDemo () {
        Object[] objects = Stream.of ("10", "12", "18").toArray ();
        String[] strings = Stream.of ("10", "12", "18").toArray (String[]::new);
    }

四、综合案例

实例
	private static class ProvinceEntity {
        private String pname;
        private String cid;
        private String cname;

        public ProvinceEntity(String pname, String cid, String cname) {
            this.pname = pname;
            this.cid = cid;
            this.cname = cname;
        }

        public String getPname() {
            return pname;
        }

        public void setPname(String pname) {
            this.pname = pname;
        }


        public String getCid() {
            return cid;
        }

        public void setCid(String cid) {
            this.cid = cid;
        }

        public String getCname() {
            return cname;
        }

        public void setCname(String cname) {
            this.cname = cname;
        }
    }

    static List<ProvinceEntity> entities = new ArrayList<> ();

    static {
        entities.add (new ProvinceEntity ("上海", "11", "上海"));
        entities.add (new ProvinceEntity ("上海", "11", "上海"));
        entities.add (new ProvinceEntity ("浙江", "12", "杭州"));
        entities.add (new ProvinceEntity ("浙江", "13", "台州"));
        entities.add (new ProvinceEntity ("浙江", "14", "宁波"));
        entities.add (new ProvinceEntity ("浙江", "15", "温州"));
        entities.add (new ProvinceEntity ("江苏", "16", "南京"));
        entities.add (new ProvinceEntity ("江苏", "17", "无锡"));
        entities.add (new ProvinceEntity ("江苏", "18", "盐城"));
        entities.add (new ProvinceEntity ("江苏", "19", "扬州"));
        entities.add (new ProvinceEntity ("江苏", "111", "宿迁"));
    }

    private static void steamDemo() {
    	// 
        Map<String, List<City>> collect = entities.stream ().collect (Collectors.groupingBy (entity -> {
            String pname = entity.getPname ();
            if (pname == null) {
                pname = "";
            }
            return pname;
        }, Collectors.mapping (entity -> {
            City city = new City (entity.getCid (), entity.getCname ());
            return city;
        }, Collectors.toList ())));
        System.out.println (collect);
    }
运行结果
{	
	上海=[City{cid='11', cname='上海'}], 
	浙江=[City{cid='12', cname='杭州'}, City{cid='13', cname='台州'}, City{cid='14', cname='宁波'}, City{cid='15', cname='温州'}], 
	江苏=[City{cid='16', cname='南京'}, City{cid='17', cname='无锡'}, City{cid='18', cname='盐城'}, City{cid='19', cname='扬州'}, City{cid='111', cname='宿迁'}]
}

你可能感兴趣的:(Java,源码,Stream,java,1.8)