java8新特性系列之---FlatMap、Optional以及Collectors

一只会飞的鱼儿 1年前 ⋅ 1921 阅读
ad

 

一、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()));
	}
}

 

关于Webfunny

Webfunny专注于前端监控系统,前端埋点系统的研发。 致力于帮助开发者快速定位问题,帮助企业用数据驱动业务,实现业务数据的快速增长。支持H5/Web/PC前端、微信小程序、支付宝小程序、UniApp和Taro等跨平台框架。实时监控前端网页、前端数据分析、错误统计分析监控和BUG预警,第一时间报警,快速修复BUG!支持私有化部署,Docker容器化部署,可支持千万级PV的日活量!

  点赞 0   收藏 0
  • 一只会飞的鱼儿
    共发布53篇文章 获得8个收藏
全部评论: 0