一、flatMap的用法和含义住要通过一个案例来讲解,
案例:对给定单词列表 ["Hello","World"],你想返回列表["H","e","l","o","W","r","d"]
第一种方式
public class Java8FlatMap {
public static void main(String[] args) {
// 第一种方式
String[] words = new String[]{"Hello","World"};
List<String[]> a = Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(toList());
a.forEach(System.out::println);
}
}
//output
[Ljava.lang.String;@23ceabc1
[Ljava.lang.String;@5d5eef3d
这个实现方式是由问题的,传递给map方法的lambda为每个单词生成了一个String[](String列表)。因此,map返回的流实际上是Stream<String[]> 类型的。你真正想要的是用Stream<String>来表示一个字符串。
下方图是上方代码stream的运行流程
第二种方式:flatMap(对流扁平化处理)
public class Java8FlatMap {
public static void main(String[] args) {
String[] words = new String[]{"Hello","World"};
// 第二种方式
List<String> b = Arrays.stream(words)
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(toList());
b.forEach(System.out::println);
}
}
使用flatMap方法的效果是,各个数组并不是分别映射一个流,而是映射成流的内容,所有使用map(Array::stream)时生成的单个流被合并起来,即扁平化为一个流。
下图是运用flatMap的stream运行流程,
二、Optional 的使用
Optional 作用:编码过程中会遇见很多为 NULL 的情况,Optional 作用就是优雅的处理 NULL 情况。
如何创建 Optional 对象?
public static void main(String[] arg){
//1、声明一个空的Optional对象
Optional<Student> optStu = Optional.empty();
//2、依据一个非空值创建一个Optional对象,如果 of() 方法传入NULL 会抛出 NullPointerException 错误
Student student = new Student(20,"");
Optional<Student> createOptByOf = Optional.of(student);
//3、可接受null的Optional
Optional<Student> createOptByOf = Optional.ofNullable(student);
}
Optional提供了多种方法读取Optional实例中的变量值
- get() 如果变量存在,直接返回封装的变量,否则爆出一个NoSuchElementException异常。最简单最不安全的方法
- orElse(T other) 它允许你在Optional对象不包含值时提供一个默认值
- orElseGet(Supplier<? extends X> other) 只有在Optional为空时才调用,
- orElseThrow(Supplier<? extends X> exceptionSupplier) 和get方法类似,遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希望抛出的异常类型
- ifPresent(Consumer<? Super T>) 让你能再变量值存在时执行一个作为参数传入的一个方法,否则就不进行任何操作。
Optional 方法应用示例
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
三、Collectors 收集器简单方法
收集器常用方法
- toList() 将流中所有的项目收集到一个List
- toSet() 将流中所有项目收集到一个Set,删除重复项
- toCollection() 将流中所有项目收集到给定的供应源创建的集合
- counting() 计算流中元素个数
- summingInt() 对流中项目的一个整数属性求和
- averagingInt() 计算流中项目Integer属性的平均值
- summarizingInt() 收集关于流中项目Integer 属性的统计值,例如最大、最小、总和与平均值
- join() String shortMenu = menuStream.map(Dish::getName).collect(joining(","));
- maxBy() 一个包裹了流中按照给定比较器选出的最大元素的Optional,或如果流为空则Optional.empty()
- minxBy() 一个包裹了流中按照给定比较器选出的最x小元素的Optional,或如果流为空则为Optional.empty()
- groupingBy() 根据项目的一个属性的值对流中的项目作分组,并将属性值作为结果Map的键
- partitioningBy() 根据对流中每个项目应用谓词的结果来对项目进行分区
代码案例
public class Dish {
private final String name; // 名字
private final boolean vegetarian;// 是否为素食
private final int calories;//热量
private final Type type;// 类型
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
public enum Type { MEAT, FISH, OTHER }
@Override
public String toString() {
return "Dish{" +
"name='" + name + '\'' +
", vegetarian=" + vegetarian +
", calories=" + calories +
", type=" + type +
'}';
}
}
// 收集器
public class Java8Collectors {
public static final List<Dish> menu =
Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 500, Dish.Type.OTHER),
new Dish("rice", true, 500, Dish.Type.OTHER),
new Dish("season fruit", true, 500, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 400, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH));
public static void main(String[] args) {
// 1、tolist 将流中所有的项目收集到一个List
List<Dish> list = menu.stream().collect(toList());
// 2.toSet 将流中所有项目收集到一个Set,删除重复项
Set<Dish> set = menu.stream().collect(toSet());
// 3.toCollection 将流中所有项目收集到给定的供应源创建的集合
Collection<Dish> dishes = menu.stream().collect(Collectors.toCollection(ArrayList::new));
// 4.counting 计算流中元素个数
long howManyDishes = menu.stream().collect(counting());
// 5.summingInt 对流中项目的一个整数属性求和
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
// 6.averagingInt 计算流中项目Integer属性的平均值
double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
// 7.summarizingInt() 收集关于流中项目Integer 属性的统计值,例如最大、最小、总和与平均值
IntSummaryStatistics intSummaryStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
// maxBy() 一个包裹了流中按照给定比较器选出的最大元素的Optional,或如果流为空则Optional.empty()
Optional<Dish> max = menu.stream().collect(maxBy(comparingInt(Dish::getCalories)));
// minxBy() 一一个包裹了流中按照给定比较器选出的最x小元素的Optional,或如果流为空则为Optional.empty()
Optional<Dish> min = menu.stream().collect(minBy(comparingInt(Dish::getCalories)));
// reducing() 归约操作产生的类型 从一个座位累加器的初始值开始,利用BinaryOperator 与流中元素租个结合,从而将流归约为单个值。
int reducing = menu.stream().collect(reducing(0,Dish::getCalories,Integer::sum));
// groupingBy() 一根据项目的一个属性的值对流中的项目作分组,并将属性值作为结果Map的键
Map<Dish.Type,List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
// partitioningBy() 根据对流中每个项目应用谓词的结果来对项目进行分区
Map<Boolean,List<Dish>> vegetarianDishes = menu.stream().collect(partitioningBy(Dish::isVegetarian));
Comparator<Dish> byLastName = Comparator.comparing(Dish::getCalories);
List<Dish> sorts = menu.stream().sorted(byLastName).collect(toList());
sorts.forEach(s -> System.out.println(s.toString()));
}
}