0
点赞
收藏
分享

微信扫一扫

Java8 lammda表达式,方法引用,stream Api以及Optional类的使用

冶炼厂小练 2022-04-21 阅读 57
java

一,lammda表达式的使用

函数式接口:就是一个接口中只有一个抽象方法,lammda表达式其实就是创建一个接口实例,并对这个抽象方法进行重写

java8内置四大核心函数式接口
​ java.util.function包下的接口都是“无意义”的,这个“无意义”并不是说它们没有存在的意义,而是说它们都必须放到具体的语境中去才会真正的意义。或者说,它们是“非典型”的Java API就体现在,它们自己是没有语境(Context)的,它们实际上可以说就是为Lambda表达式而存在的——你不需要了解它叫什么(匿名的),它们是作为参数在对象的方法的中传递的。

​ 其实,所有java.util.function包下的接口的方法名,我们都不必关心,因为当我们用它们的时候,压根不会去显式地调用它们,方法名也是“无意义”的,它们只是方便大家去理解他的用途。但是,方法的参数和返回值是需要我们关心和注意的。

function包下总共有43个接口,可分为这四类核心函数式接口:Function、Supplier、Consumer、Predicate。

1.消费型接口
Consumer:消费型接口 单一抽象方法为:void accept(T t);

  • 作用:消费某个对象**(传入一个泛型参数,不返回任何值)**

  • 举例:forEach: Iterable接口的foeEach方法 需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。

2.供给型接口

Supplier:供给型接口 T get();

  • 作用:创建一个对象(工厂类)(不传入参数,返回一个值)
  • 举例:Optional.orElseGet(Supplier<? extends T>):当this对象为null,就通过传入supplier创建一个T返回。(Optional类是一种容器对象,要么包装值,要么为空)

3.函数式接口

Function<T,R>:函数型接口 R apply(T t);

  • 作用:实现一个“一元函数”,即传入一个值经过函数的计算返回另一个值。(传入一个参数,返回一个值)

4.断言型接口
Predicate:断言型接口 单一抽象方法: boolean test(T t);

作用:判断对象是否符合某个条件**(传入一个参数,返回一个布尔值)**
举例:主要用于流的筛选。给定一个包含若干项的流,Stream接口的filter方法传入一个Predicate并返回一个新的流,它仅包含满足给定谓词的项。

 

方法引用:

方法引用就是lammda表达式的简化版,就是说函数式接口中抽象方法已经有类去实现了,咱们就可以直接调用这个方法

主要有三种表现形式:

1)引用特定对象的实例方法:对象::实例方法名(object::instanceMethod)

(x)->System.out.println(x);
简化为:System.out::println

2)引用静态方法:类::静态方法名(Class::staticMethod)

()->Math.random();
简化为:Math::random


3)调用特定类型的任意对象的实例方法: 类::实例方法名(Class::instanceMethod ):这个比较特殊,可能接口中的抽象方法和引用方法格式不同,而是接口中的抽象方法如果可以调用这个方法,那么就可以通过这个方法的类名加实例方法去调用引用方法

x->x.length();
简化为:String::length


注意:如果通过类名引用一个传入多个参数的方法,则上下文提供的第一个元素将作为方法的目标,其他元素作为方法的参数,可以使用ClassName::instanceMethod 。

(o1,o2)->o1.compareTo(o2);
简化为:String::compareTo


注意:需要实现的接口中的抽象方法的 参数列表与返回值类型 要与 当前调用的方法的参数列表、返回值类型保持一致

StreamApi的使用:检索集合或者数组

特点:1.与集合不同,集合是与内存打交道,而Stream Api是与cpu打交道

           2.延迟执行,只有在需要结果的时候才会执行,或者执行了终止操作的时候才会执行

大概步骤就是:

  1.获取stream实例对象

    通过集合获取stream对象:集合实例.stream();

    通过数组获取stream对象:Arrays.stream(数组实例)

    通过Stream类下自带的of方法,of的参数就是任意元素

  2.中间操作

   (1)筛选与切片

    filter(predicate p):对元素进行筛选

   limit(n) :获取前n条数据

   skip(n) : 跳过前n条数据,返回后边的数据

   distinct():元素去重

    (2)映射

     map(Function  f):对元素进行修改或者操作,返回一个新的stream实例

     flatMap(Function f):与map的区别就是,在操作中返回的新的stream实例,里边的元素应该还是stream实例,如果是map的话就会stream里边嵌套stream,如果这flatmap,就会把里边的stream拆解,追加到外边的stream中

    (3)排序

     Sorted():可以是自然排序,如果元组本身就可以直接排序就可以使用自然排序

     Sorted(Comparator<T> c):可以自己进行定制,如果是对象,要根据某个元素排序就需要用到定制排序,一下就是根据对象年龄参数进行升序排序

  3.终止操作

  allMatch(predicate p):检查是否匹配所有元素

  anyMatch(predicate p)检查是否至少匹配一个元素

  noneMatch(predicate p)检查是否没有匹配的元素

  findFirst()返回第一个元素

  findany()返回任意元素

  count()返回元素总个数

   max(Comparator c)返回流中最大值

   min(Comparator c)返回流中最小值

forEach(Consumer c) 内部迭代

归约结束操作:

reduce(T 起始值,BinaryOperator),这里可以设置起始值,将流中的元素反复结合起来

eg:list.stream().reduce(0,Integer::Sum)

reduce(BinaryOperator) 不设置起始值,求元素的和

收集结束操作:

collect(Collector c)

eg:list.stream().collect(Collector.Toset)

list变换map的常用操作:

 //以brand和price属性分别作为key和value创建map,若集合中存在key重复的元素,就取后一个
        Map<String, BigDecimal> collect = cars.stream().collect(Collectors.toMap(Car::getBrand, Car::getPrice, (x, y) -> y));
        //以brand为key,将集合分组,每个brand对应一个Car集合
        Map<String, List<Car>> collect1 = cars.stream().collect(Collectors.groupingBy(Car::getBrand));
        //将集合按是否满足partitioningBy中的断言函数为标准,分成两个集合
        Map<Boolean, List<Car>> bn = cars.stream().collect(Collectors.partitioningBy(k -> "BMW".equals(k.getBrand())));

三,Optional类的使用

 可以防止空指针的发生

获取optional类实例的三种方式:

Optional.of(T f):创建一个Optional实例,t必须为空

Optional.empty():创建一个空的Optional实例

Optional.ofNullable(T t):t可以为null

optional类实例方法的使用:

orElse(T t):调用者如果为空就使用参数中的实例

eg:Optional<Boy>  o=Optional.ofNullable(new Boy());

       Boy b= o.orElse(new BOY);//假如o为null,就使用后边的对象为boy赋值


 

举报

相关推荐

0 条评论