Java SE 8 流库(四)
1.8. 收集数据
<R,A> R collect(Collector<? super T,A,R> collector) 使用给定的收集器来收集当前流中的元素
void forEach(Consumer<? super T> action) 对此流的每个元素执行操作
void forEachOrdered(Consumer<? super T> action) 为流的每个元素执行操作,如果流具有已定义的遇到顺序,则按流的遇到顺序执行操作
Object[] toArray() 返回包含此流的元素的数组
Stream.toArray(),会返回一个Object[]数组,如果想要数组具有正确的类型,可以将其传递到数组构造器中;
static <T> Stream<T> iterate(T seed,UnaryOperator<T> f) 返回一个由函数f迭代应用到初始元素种子产生的无限顺序排序流,产生由种子,f(种子),f(f(种子))等组成的流。Stream中的第一个元素(位置0)将是提供的种子。 对于n> 0,位置n处的元素将是对位置n-1处的元素应用函数f的结果
Iterator<T> iterator() 返回此流的元素的迭代器
public static <T> Collector<T,?,List<T>> toList()
public static <T> Collector<T,?,Set<T>> toSet() 将产生的元素收集到列表或集合中的收集器;
public static <T,C extends Collection<T>> Collector<T,?,C> toCollection(Supplier<C> collectionFactory)
产生一个将元素收集到集合中的收集器,可以传递一个诸如TreeSet :: new的构造器引用;
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,?,IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
public static <T> Collector<T,?,LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
public static <T> Collector<T,?,DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
产生能够生成(int|long|double) SummaryStatistics对象收集器,通过它可以获得将Mapper应用于每个元素后产生的结果的个数,总和,平均值,最大值,和最小值
public class IntSummaryStatistics extends Object implements IntConsumer 对象中的方法:
public final int getMax()
public final double getAverage()
public final int getMax()
public final int getMin()
public final long getSum()
1 package com.itheima05.Test_JavaSE.Test_20180101; 2 3 import java.nio.charset.StandardCharsets; 4 import java.nio.file.Files; 5 import java.nio.file.Paths; 6 import java.util.*; 7 import java.util.stream.Collectors; 8 import java.util.stream.Stream; 9 10 /** 11 * Created by Lenovo on 2018/1/1. 12 */ 13 public class Demo01 { 14 15 private static final String filePath = "G:\\Idea\\src\\com\\itheima05\\Test_JavaSE\\Test_20180101\\word.txt"; 16 17 18 public static void main(String[] args) throws Exception{ 19 20 //实例1(iterate) 21 Iterator<Integer> it = Stream.iterate(0, n -> n + 1) 22 .limit(10).iterator(); 23 while (it.hasNext()){ 24 System.out.println(it.next()); 25 } 26 27 Object[] numbers = Stream.iterate(0, n -> n + 1) 28 .limit(10) 29 .toArray(); 30 //得到一个数组 31 System.out.println("numbers:"+numbers); 32 33 //获取数组中的第一个元素 34 int number = (int)numbers[0]; 35 System.out.println("number:"+ number); 36 37 //强转为int数组(会有转化异常出现) 38 try { 39 Integer[] intNum = (Integer[]) numbers; 40 System.out.println("Integer[]:"+intNum); 41 } catch (Exception e) { 42 System.out.println(e); 43 } 44 45 //将数组的正确类型传递到数组的构造器中 46 Integer[] arrayNums = Stream.iterate(0, n -> n + 1) 47 .limit(10).toArray(Integer[]::new); 48 System.out.println("arrayNums:" + arrayNums); 49 50 //转化为set集合 51 Set<String> noVowelsSet = noVowels().collect(Collectors.toSet()); 52 show("noVowelsSet",noVowelsSet); 53 54 //TreeSet 55 TreeSet<String> noVowelsTreeSet = noVowels().collect(Collectors.toCollection(TreeSet::new)); 56 show("noVowelsTreeSet",noVowelsTreeSet); 57 58 //joining 59 String noVowelsJoining = noVowels().limit(10).collect(Collectors.joining()); 60 System.out.println("noVowelsJoining:"+noVowelsJoining); 61 62 //joining(",") 63 String noVowelsJoining2 = noVowels().limit(10).collect(Collectors.joining(",")); 64 System.out.println("noVowelsJoining2:"+noVowelsJoining2); 65 66 //summarizingInt 67 IntSummaryStatistics summary = noVowels().collect(Collectors.summarizingInt(String::length)); 68 double average = summary.getAverage(); 69 int max = summary.getMax(); 70 long count = summary.getCount(); 71 System.out.println("average:"+average); 72 System.out.println("max:"+max); 73 System.out.println("count:"+count); 74 75 //forEach 76 System.out.println("forEach:"); 77 noVowels().limit(10).forEach(System.out::println); 78 } 79 public static Stream<String> noVowels() throws Exception{ 80 81 String contens = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8); 82 List<String> wordList = Arrays.asList(contens.split("\\PL+")); 83 Stream<String> words = wordList.stream(); 84 return words.map(s -> s.replaceAll("[aeiouAEIOU]","")); 85 } 86 87 public static <T> void show(String label, Set<T> set) { 88 89 System.out.println(label + ":" + set.getClass().getName()); 90 System.out.println("{" + set.stream() 91 .limit(10) 92 .map(Object::toString) 93 .collect(Collectors.joining(",")) + "}"); 94 } 95 }
1.9. 收集到映射表中
场景1:
假设我们有一个Stream<Person>,并且想要将其元素收集到一个映射表中,这样后续就可以通过他们的ID来查找人员了;
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper)
该方法有两个函数引元,keyMapper和valueMapper
在通常情况下,值应该是实际元素,因此第二个函数可以使用Function.identity();
场景2:
如果有多个元素具有相同的键,那么就会存在冲突,收集器将会抛出一个IllegalStateException对象。可以通过提过3个函数引元来覆盖这种行为,该函数会针对给定的已有的值和新值来解决冲突并确定键对应的值。这个函数应该返回已有值,新值,或它们的组合;
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,BinaryOperator<U> mergeFunction)
场景3:
假设我们想要了解给定国家的所有语言,这样我们就需要一个Map<String,Set<String>>;
例如:卢森堡=[德文, 法文]
首先我们为每一种语言都存储一个单例集,无论如何是,只要找到了给定的国家的新语言,我们都会将已有的集和新集做并操作;
public static <T,K,U,M extends Map<K,U>> Collector<T,?,M> toMap(Function<? super T,? extends K> keyMapper,Function<? super T,? extends U> valueMapper,BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
实例1:
Person类:
1 public class Person { 2 3 private int id; 4 private String name; 5 6 public Person(int id, String name) { 7 this.id = id; 8 this.name = name; 9 } 10 public int getId() { 11 return id; 12 } 13 public void setId(int id) { 14 this.id = id; 15 } 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 @Override 23 public String toString() { 24 return "Person{" + 25 "id=" + id + 26 ", name='" + name + '\'' + 27 '}'; 28 } 29 }
CollectingIntoMaps类:
1 public class CollectingIntoMaps { 2 3 4 public static void main(String[] args) { 5 6 //通过id查找Name 7 Map<Integer, String> idToName = person(). 8 collect(Collectors.toMap(Person::getId, Person::getName)); 9 System.out.println("idToName:"+idToName); 10 //输出 11 //idToName:{1001=xiaoming, 1002=xiaohei, 1003=xiaobao} 12 13 //通过id查找Name(第二种方法) 14 Map<Integer, Person> idToName2 = person(). 15 collect(Collectors.toMap(Person::getId, Function.identity())); 16 System.out.println("idToName2:"+idToName2); 17 //输出2 18 //idToName2:{1001=Person{id=1001, name='xiaoming'}, 19 //1002=Person{id=1002, name='xiaohei'}, 20 //1003=Person{id=1003, name='xiaobao'}} 21 Map<Integer, Person> idToName3 = person(). 22 collect(Collectors.toMap(Person::getId, Function.identity(), 23 (existingValue,newValue) -> 24 {throw new IllegalStateException();},TreeMap::new)); 25 //默认情况下,当两个元素产生相同的键时,会抛出IllegalStateException异常 26 System.out.println("idToName3:"+idToName3.getClass().getName()+idToName3); 27 } 28 29 public static Stream<Person> person(){ 30 31 return Stream.of(new Person(1001,"xiaoming"), 32 new Person(1002,"xiaohei"),new Person(1003,"xiaobao")); 33 } 34 35 }
实例2:
1 public class Demo02 { 2 3 public static void main(String[] args) { 4 5 Stream<Locale> locales = Stream.of(Locale.getAvailableLocales()); 6 Map<String, String> languageNames = locales.collect(Collectors.toMap(Locale::getDisplayLanguage, 7 l -> l.getDisplayLanguage(l), 8 (existingValue, newValue) -> existingValue)); 9 System.out.println("languageNames:"+languageNames); 10 11 // 12 locales = Stream.of(Locale.getAvailableLocales()); 13 Map<String, Set<String>> countryLanguageSets = locales.collect(Collectors.toMap(Locale::getDisplayCountry, 14 l -> Collections.singleton(l.getDisplayLanguage()), 15 (a, b) -> { 16 Set<String> union = new HashSet<>(a); 17 union.addAll(b); 18 return union; 19 })); 20 System.out.println("countryLanguageSets:"+countryLanguageSets); 21 } 22 }
1.10. 群组和分区
public static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier)
public static <T,K> Collector<T,?,ConcurrentMap<K,List<T>>> groupingByConcurrent(Function<? super T,? extends K> classifier)
产生一个收集器,它会产生一个映射表或并发映射表,其键是将classifier应用于所有收集到的元素上所产生的的结果,而值是有具有相同键的元素构成的一个个列表;
public static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(Predicate<? super T> predicate)
产生一个收集器,它会产生一个映射表,其键是true/false,而值是有满足/不满足断言的元素构成的列表;
实例:
1 ** 2 * Created by Lenovo on 2018/1/3. 3 * public static Locale[] getAvailableLocales() 4 * public String getCountry() 5 */ 6 public class Demo03 { 7 8 public static void main(String[] args) { 9 10 //集组 11 Stream<Locale> locales = Stream.of(Locale.getAvailableLocales()); 12 Map<String, List<Locale>> countryToLocale = locales. 13 collect(Collectors.groupingBy(Locale::getCountry)); 14 List<Locale> localeList = countryToLocale.get("CH"); 15 System.out.println(localeList); 16 17 //分区 18 locales = Stream.of(Locale.getAvailableLocales()); 19 Map<Boolean, List<Locale>> languageToLocale = locales. 20 collect(Collectors.partitioningBy(l -> l.getLanguage().equals("en"))); 21 System.out.println(languageToLocale.get(true)); 22 } 23 }
当分类函数是断言函数(返回boolean值的函数)时,流的元素可以使用分区为两个列表:该函数返回true的元素和其他元素,这种情况下,使用partitioningBy比使用groupingBy更高效;