Java------Stream流式编程高级API【mapTo、Collectors、groupingBy、flatMap】(五)
mapTo,折叠操作
折叠操作又称为规约操作,是从一系列输入元素中,通过组合操作组成单个摘要结果。比如:查找一组数字的和、最大值、最小值、个数等。
常用的折叠操作:
max()、min()、count()、sum()、groupby()、groupby()+max()。
以上为了方便对纯数字的流进行处理。
提供了三种基本类型的Stream。
IntStream、DoubleStream、LongStream。
通过Stream接口中的三个方法可以得到这三个对象。
IntStream mapToInt(ToIntFunction<? super T> mapper);
//ToIntFunction函数式接口,放lamba表达式
@FunctionalInterface
public interface ToIntFunction<T> {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
int applyAsInt(T value);
}
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
示例一:得到数字流,求最大、最小
@Test
public void test1() {
int[] intArr = new int[]{1,2,3,4,5,1,2};
IntStream stream = Arrays.stream(intArr);
//求个数
long count = stream.count();
System.out.println(count);
//求最大值
OptionalInt max = Arrays.stream(intArr).max();
// int asInt = stream.max().getAsInt();
//直接输出max会报错,
System.out.println(max);
// System.out.println(asInt);
//求最小值 会报错, stream has already been operated upon or closed
OptionalInt min = stream.min();
System.out.println(min);
}
其中调用max值时,返回的类型是OptionalInt,打印输出的结果时:OptionalInt[5],如果想获取它的value。则需要调用getAsInt()方法。
OptionalInt max = Arrays.stream(intArr).max();
根据源码:如果没有值的话,会抛出异常,有值,则返回value
public int getAsInt() {
if (!isPresent) {
throw new NoSuchElementException("No value present");
}
return value;
}
而流直接调用max方法,也会抛出异常,stream has already been operated upon or closed。此时需要新建一个流
OptionalInt min = stream.min();
Arrays.stream(intArr).min();
案例二:List数组、map进行数字流处理
@Test
public void test1() {
Map<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.put("d",4);
map.put("e",5);
Stream<Map<String, Integer>> map1 = Stream.of(map);
long a = map1.mapToInt(x -> x.get("a")).count();
//1
System.out.println(a);
List<Studengt> list = new ArrayList<>();
list.add(new Studengt("aa",1));
list.add(new Studengt("bb",2));
list.add(new Studengt("cc",9));
OptionalInt max = list.stream().mapToInt(x -> x.getAge()).max();
//9
System.out.println(max.getAsInt());
}
Collectors 实现将流转list、set、map
使用Collectors收集器,实现对流进行可变的折叠操作。将流转成List、Set、Map。
在Stream接口中有一个collect方法收集器进行操作
collect源码
<R, A> R collect(Collector<? super T, A, R> collector);
Collector源码
public interface Collector<T, A, R> {
如何得到收集器对象?在收集器中制定了转换list、map、set的方法。
在collectors中定义了很多收集器创建方法,toList实现转list、toSet转set,toMap转map。
1.创建流对象
2.创建收集器对象
3.执行stream流对象的collection方法,进行收集,转成List、set、Map。
案例三:stream转List。
String[] strArr = new String[]{"a","bb","ccc","dddd"};
//默认返回arrylist
List<String> collect = Arrays.stream(strArr).collect(Collectors.toList());
collect.stream().forEach(System.out::println);
//指定linkList,LinkedList::new构造方法引用
LinkedList<String> collect1 = Arrays.stream(strArr).collect(Collectors.toCollection(LinkedList::new));
案例四:基本类型数组转流对象
int数组调用stream方法,返回的时IntStream对象,这样的对象时无法调用。
int[] intArr = new int[]{1,22,333,4444,55555};
//语句报错无法执行
Arrays.stream(intArr).collect(Collectors.toList());
此时调用的collect方法时,另一个需要传入三个参数的方法。
<R> R collect(Supplier<R> supplier,
ObjIntConsumer<R> accumulator,
BiConsumer<R, R> combiner);
如果想要正常转List,则需要调用.stream().boxed()方法。
.boxed():将流中的元素进行装箱,将基本类型的数组转成含有包装类的流。
如代码所示
int[] intArr = new int[]{1,22,333,4444,55555};
//语句报错无法执行
List<Integer> collect1 = Arrays.stream(intArr).boxed().collect(Collectors.toList());
案例五:list转Map,方法一样,但是map需要指定key、和value,转为年龄为key,Student对象为value的Map
List<Studengt> list = new ArrayList<>();
list.add(new Studengt("aa",1));
list.add(new Studengt("bb",2));
list.add(new Studengt("cc",9));
Map<Integer, Studengt> collect1 = list.stream().collect(Collectors.toMap(x -> x.getAge(), x -> x));
map中key唯一,当使用合并流,流转map时,如果指定的key一样,则会报错,但也有解决办法
List<Studengt> list = new ArrayList<>();
list.add(new Studengt("aa",1));
list.add(new Studengt("bb",2));
list.add(new Studengt("cc",9));
List<Studengt> list2 = new ArrayList<>();
list2.add(new Studengt("aa",1));
list2.add(new Studengt("bbc",8));
list2.add(new Studengt("ddd",9));
Stream.concat(list.stream(),list2.stream()).collect(Collectors.toMap(x->x.getAge(),x->x));
两个map的key冲突时,解决办法:指定冲突时,使用哪一个value。
List<Studengt> list = new ArrayList<>();
list.add(new Studengt("aa",1));
list.add(new Studengt("bb",2));
list.add(new Studengt("cc",9));
List<Studengt> list2 = new ArrayList<>();
list2.add(new Studengt("aa",1));
list2.add(new Studengt("bbc",8));
list2.add(new Studengt("ddd",9));
Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1));
collect.forEach((key,va)-> System.out.println(key+"+++++"+va));
//输出结果
1+++++Studengt{name='aa', age=1}
2+++++Studengt{name='bb', age=2}
8+++++Studengt{name='bbc', age=8}
9+++++Studengt{name='cc', age=9}
默认是HashMap类型,如何指定为TreeMap类型?
与List指定LinkList一样,传入构造方法的引用,此时是自然排序
Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1, TreeMap::new));
如何指定为TreeMap类型,指定排序,不用自然排序?
Supplier<TreeMap<Integer,Studengt>> treeMapSupplier = ()->new TreeMap<>(Comparator.reverseOrder());
Map<Integer, Studengt> collect = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toMap((x) -> x.getAge(), x -> x, (x1, x2) -> x1, treeMapSupplier));
collect.forEach((key,va)-> System.out.println(key+"+++++"+va));
List转Set
如果使用TreeSet,则元素需要实现Compare接口
实体类改造:
public class Studengt implements Comparable<Studengt>{
@Override
public int compareTo(Studengt o) {
return this.getAge()-o.getAge();
}
示例六List转Set
System.out.println("===========hashSet=============");
//转set,默认hashset
Set<Studengt> collect = concat.collect(Collectors.toSet());
collect.forEach(System.out::println);
System.out.println("===========TreeSet,默认排序=============");
//转TreeSet
TreeSet<Studengt> collect2 = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toCollection(TreeSet::new));
collect2.forEach(System.out::println);
System.out.println("===========TreeSet,age降序排序=============");
//转TreeSet,并且指定age降序排序
Supplier<TreeSet<Studengt>> treeSetSupplier = ()->new TreeSet<>((o1,o2)->(int)(o2.getAge()-o1.getAge()));
TreeSet<Studengt> collect3 = Stream.concat(list.stream(), list2.stream()).collect(Collectors.toCollection(treeSetSupplier));
collect3.forEach(System.out::println);
}