Java8 学习笔记

1.Lambda表达式

  可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表,如下所示简单的Lamdda表达式:
在这里插入图片描述

2.函数式接口

     函数式接口定义且只定义了一个抽象方法,需要使用@FunctionalInterface,个标注用于表示该接口会设计成一个函数式接口
     函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符

常用函数式接口

函数式接口 函数描述符 原始类型特化
Predicate T->boolean IntPredicate,LongPredicate, DoublePredicate
Consumer T->void IntConsumer,LongConsumer, DoubleConsumer
Function<T,R> T->R IntFunction,IntToDoubleFunction,IntToLongFunction,
LongFunction,LongToDoubleFunction,
LongToIntFunction,DoubleFunction,
ToIntFunction,ToDoubleFunction,ToLongFunction
Supplier ()->T BooleanSupplier,IntSupplier, LongSupplier,DoubleSupplier
UnaryOperator T->T IntUnaryOperator,LongUnaryOperator,
DoubleUnaryOperator
BinaryOperator (T,T)->T IntBinaryOperator,LongBinaryOperator,
DoubleBinaryOperator
BiPredicate<L,R> (L,R)->boolean
BiConsumer<T,U> (T,U)->void ObjIntConsumer,ObjLongConsumer,
ObjDoubleConsumer
BiFunction<T,U,R> (T,U)->R ToIntBiFunction<T,U>,ToLongBiFunction<T,U>,
ToDoubleBiFunction<T,U>

3.方法引用

先前:
   inventory.sort((Apple a1, Apple a2)-> a1.getWeight().compareTo(a2.getWeight()));
使用方法引用和 java.util.Comparator.comparing:
   inventory.sort(comparing(Apple::getWeight));  //使用“::”这个来调用方法,
   一般没有对原始数据做其他特殊处理,可以用方法引用的更直观简单,如果没办法还是得用Lambda表达式。

4.使用流

4.1.流主要是对集合的操作处理

filter:谓词筛选
foreach:输出每一个元素
distinct:筛选掉相同元素
limit(n):截断流,获取指定的前n个数据
 skip(n):跳过集合前n个元素
 map:表示映射元素,集合中的一个元素映射到一个新的元素
 flatMap:扁平化集合,可以把两个集合合并成一个集合
allMatch:流中是否有一个元素能匹配给定的谓词
anyMatch:流中的元素是否都能匹配给定的谓词
noneMatch:它可以确保流中没有任何元素与给定的谓词匹配
findFirst:将返回当前流中的任意元素
findAny:找到当前流中的第一个元素
reduce:规约数据(对每一个元素做累积值,可以求和,积,求最大值,最小值,可以给定初始值,也可以不给定初始值)
count:计算流中元素的个数
sorted:排序

如下具体的详情描述:
在这里插入图片描述

 flatMap例子一:
  String[]  words = {"Goodbye", "World"}; //如下通过flatMap可以获取这个数组中包含的所有字符(不重复)
  List<String> uniqueCharacters =words.stream()
                      .map(w -> w.split(""))
                      .flatMap(Arrays::stream)
                      .distinct()
                      .collect(Collectors.toList());
                      
flatMap例子二:
  //如下可以让两个数组的数自由的组合
   List<Integer> numbers1 = Arrays.asList(1, 2, 3);
   List<Integer> numbers2 = Arrays.asList(3, 4);
   List<int[]> pairs =numbers1.stream()
                       .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j}))
                       .collect(toList());
                       
reduce带初始值例子三:
int sum = numbers.stream().reduce(0, Integer::sum);

reduce不带初始值例子三:
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

4.2.流转换

1)映射到基本类型流

mapToInt:映射基本类型int的流, IntStream 还支持其他的方便方法,如max 、 min 、 average 等
mapToDouble:映射基本类型double的流
mapToLong:映射基本类型long的流

2)转换回为对象流

boxed:相当于对基本类型的装箱
mapToObject:这个也可以实现

3)数值范围
range,rangeClosed
这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但
range 是不包含结束值的,而 rangeClosed 则包含结束值

例如:
IntStream.rangeClosed(1, 100)  //这个范围是包含100的,结果的数据有50个
            .filter(n -> n % 2 == 0)  
IntStream.range(1, 100)
           .filter(n -> n % 2 == 0)  //这个范围是不包含100的,结果的数据只有49个

4.3 创建流

1)使用Stream.of创建

Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");

2)由数组创建流

int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();

3)文件流

 如下通过Files.lines创建流
long uniqueWords = 0;
try(Stream<String> lines =Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){
     uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                    .distinct()
                    .count();
}
catch(IOException e){
}

4)创建无限流
  Stream API提供了两个静态方法来从函数生成流: Stream.iterate 和Stream.generate 。 这两个操作可以创建所谓的无限流:不像从固定集合创建的流那样有固定大小的流。由 iterate
和 generate 产生的流会用给定的函数按需创建值,因此可以无穷无尽地计算下去!一般来说,应该使用 limit(n) 来对这种流加以限制,以避免打印无穷多个值。

i) iterate 方法要接受一个 UnaryOperator 作为参数,表示不停的迭代上一个数

 例子一:
  //Stream.iterate  如下是生成2,4,6,8...总共10个偶数,都是前一个数加2所得
		Stream.iterate(0, n -> n + 2)
              .limit(10)
             .forEach(System.out::println);
 例子二:
//Stream.iterate  可以用来生成斐波那契函数
   Stream.iterate(new int[]{0, 1},t -> new int[]{t[1],t[0] + t[1]})
         .limit(10)
         .map(t -> t[0])
         .forEach(System.out::println);
//这段代码将生成斐波纳契数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34…

ii) generate 方法也可让你按需生成一个无限流。但 generate 不是依次对每个新生成的值应用函数的。它接受一个 Supplier 类型的Lambda提供新的值。

 例子一:
  Stream.generate(Math::random)
	    .limit(5)
        .forEach(System.out::println);//生成新的5个函数
例子二:
 //同样生成斐波那契函数,不过这个存在有中间状态,在并行条件下是不安全的,不建议这样用
 IntSupplier fib = new IntSupplier(){
	 private int previous = 0;
	 private int current = 1;
	 public int getAsInt(){
 		 int oldPrevious = this.previous;
		 int nextValue = this.previous + this.current;
		 this.previous = this.current;
		 this.current = nextValue;
		return oldPrevious;
	  }
 };
IntStream.generate(fib).limit(10).forEach(System.out::println);

5.收集流

  收集流可以对流使用collect方法,然后使用Collector类提供的方法进行收集。

它们主要提供了三大功能:
a.   将流元素归约和汇总为一个值
b.   元素分组
c.   元素分区
方法 说明
Collector.toList() 将流转换为一个List集合
Collector.toSet 将流转换为一个Set集合,不包含重复元素
Collector.toSet 将流收集起来成为集合
Collectors.counting() 可以返回流中有多少个元素
Collectors.maxBy(Comparator) 可以返回流里最大的元素(某个条件)
Collectors.minBy(Comparator) 可以返回流里最小的元素(某个条件)
Collectors.summingInt(Function) 对于流中的元素求和,返回int,同样summingDouble则是返回double类型
Collectors.averagingDouble(Function) 对流中的元素求平均值返回double类型,同样有averagingInt,averagingLong
Collectors.joining() 对CharSequence的元素流进行组合,可以使用带参数做分割,以及前后添加元素
Collectors.reducing (U identity,Function<? super T, ? extends U> mapper,BinaryOperator op) 上面所有的都是这个reducing的特殊情况,都可以通过这个方法实现,这个有三个重载方法。
Collectors.groupingBy(Function) 对于流通过某一个元素进行分组,这个也支持嵌套分组,返回Map集合,第二个参数可以对生成的集合进行求和,数量计算,最大,最小等
Collectors.collectingAndThen 把结果集转换为另外一个结果,一般可以对包装的Optional进行get提取元素
Collectors.partitioningBy(Predicate) 对流进行分区,和GroupBy相似,不过只分为true和false两组;他和可以和groupingBy嵌套使用

6.流中插入动作peek

  peek 的设计初衷就是在流的每个元素恢复运行之前,插入执行一个动作。但是它不像 forEach 那样恢复整个流的运行,而是在一个元素上完成操作之后,它只会将操作顺承到流水线中的下一个操作。

7.新的日期API

这个可以参考 https://www.cnblogs.com/comeboo/p/5378922.html

猜你喜欢

转载自blog.csdn.net/weixin_40792878/article/details/83627343