开发者

Java8新特性-Lambda表达式详解

目录
  • 一、简介
    •  特征
    • 引入
    • Lambda表达式的总结
  • 三、Lambda表达式的使用
    • 无参、无返回值
    • 有参无返回值
    • 无参数有返回值
    • 有参数有返回值
  • 四、Lambda表达式的注意事项
    •  五、函数式接口
      • 内置函数式接口
      • 函数式接口使用场景
    • 六、方法调用
      • 七、Stream流式编程
        • 什么是 Stream?
        •  使用 Stream流的步骤
      • 八、串行流和并行流
        • 九、Optional 类

          一、简介

          Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 javascript 引擎,新的日期 API,新的Stream API 等。

           特征

          • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
          • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
          • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
          • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。

           注意:Lambda表达式适用于只有一个抽象方法的接口!!

          引入

          自定义接口

          interface Fu{
              void add();
          }

          使用匿名内部类实现接口

          Fu fu = new Fu() {
                      @Override
                      public void add() {
                          System.out.println("我是add方法");
                      }
                  };
                  fu.add();

          使用Lambda表达式实现接口

                  Fu fu1 = ()->{
                      System.out.println("我是add1方法");
                  };
          php        fu1.add();

          Lambda表达式的总结

          • Lambda表达式基于数学中的 入 演化得名的,对应Java中的lambda抽象,是一个匿名函数,就是没有函数名的函数。
          • 好处
            • 使代码更加简洁紧凑,且可与Stream API等相结合,Lambda表达式经常代替匿名内部类使用
          • 语法
            • (参数)->表达式或者(参数)->{语句体;}
            • 参数:要重写方法的参数列表
            • ->:Lambda表达式的运算符
            • 表达式或语句体:要实现的方法的方法体
          • 本质
            • 是一种匿名函数(不是匿名内部类),简单说,它没有声明的方法、没有访问修饰符、返回值声明和名字,它是属于函数式编程的概念

           

          三、Lambda表达式的使用

          无参、无返回值

          接口

          interface F{
              void add();
          }

          测试

                  //无参无返回值
                  F f = ()->{
                      System.out.println("我是add方法");
                  };
                  f.add();

          有参无返回值

          接口

          interface F{
              void add(int a);
          }

          测试

                  F f = (int a)->{
                      System.out.println("a="+a);
                  };
                  f.add(12);

          无参数有返回值

          接口

          interface F{
              int add();
          }

          测试

                  F f = ()-编程>{
                      return 12;
                  };
                  int i = f.add();
                  System.out.println(i);

          有参数有返回值

          接口

          interface F{
              int add(int a);
          }

          测试

                  F f = (int a)->{
                      return 12+a;
                  };
                  int i = f.add( 12 );
                  System.out.println(i);

          四、Lambda表达式的注意事项

          • Lambda表达式中 () 的参数类型可以省略 (int a,int b)==>(a,b)
          • 接口中如果只有一个参数,Lambda表达式中 () 可以省略  (int a)==> (a)==>a
          • 如果方法体中只有一条执行语句时 外层的 {} 可以省略
          • 如果方法体中只有一条返回语句,{}和return 都可以省略

           五、函数式接口

          函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,可以有其他普通方法,用@FunctionalInterface检验是否是函数式接口。

           

          @FunctionalInterface
          interface F1{
              void t1();
              
              default void t2(){//不计
                  
              }
              static void t3(){//不计
                  
              }
              public boolean equals(Object object);//不计
          }

          作用:在Java中主要用在Lambda表达式和方法引用。

          内置函数式接口

          • Consumer<T>:消费型接口(void accept(T t))。有参数,无返回值
          • Supplier<T>:供给型接口(T get())。有参数,无返回值
          • Function<T,R>:函数型接口(R apply(T t))。一个输入参数,一个输出参数,两种类型可以一致,也可以不一致
          • Predicate<T>:断言型接口(boolean test(T t))。输入一个参数,输出一个boolean类型的返回值

          函数式接口使用场景

          消费型接口

          //函数式接口的使用场景
          public class Test03 {
              public static void main(String[] args) {
                  List<Integer> list = new ArrayList<>();
                  Collections.addAll(list,1,2,3,6,5,4,8,9);
                  //匿名内部类
                  Consumer<Integer> con = new Consumer<Integer>() {
                      @Override
                      public void accept(Integer integer) {
                          //参数代表集合中的每一个数据
                          System.out.print(integer+" ");
                      }
                  };
                  list.forEach( con );
                  System.out.println();
                  System.out.println("==================");
                  //Lambda表达式1
                  Consumer cons = (y)->{
                      System.out.print(y+" ");
                  };
                  list.forEach( cons );
                  System.out.println();
                  System.out.println("==================");
                  //Lambda表达式2
                  list.forEach( y-> System.out.print(y+" ") );
              }
          }

          断言型接口

          public class Test04 {
              public static void main(String[] args) {
                  List<Integer> list = new ArrayList<>();
                  Collections.addAll(list,1,2,3,6,5,4,8,9);
                  //匿名内部类
                  Predicate<Integer> predicate = new Predicate<Integer>() {
                      @Override
                      public boolean test(Integer integer) {
                          //参数o代表集合中的每一个数
                          if (integer<=6){
                              return true;//删除该数据
                          }
                          return false;//不删除该数据
                      }
                  };
                  list.removeIf(predicate);
                  list.forEach( x-> System.out.println(x) );
                  System.out.println("=================");
           
                  //Lambda表达式
                  list.removeIf( y->{
                      if (y<=6){
                          return true;
                      }
                      return false;
                  } );
                  list.removeIf(predicate);
                  list.forEach( x-> System.out.println(x) );
                  System.out.println("=================");
              }
          }

          六、方法调用

          方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 :: 。

          //方法引用
          public class Test05 {
              public static void main(String[] args) {
                  List<Integer> list = new ArrayList<>();
                  Collections.addAll(list,4,8,9);
           
                  //使用Lambda表达式
                  list.forEach( x-> System.out.println(x) );
                  System.out.println("==================");
                  //方法引用
                  //使用场景,参数传递过来不做任何处理,直接输出的就可以使用方法引用
                  list.forEach(System.out::println);
              }
          }

          构造器引用:它的语法是Class::new,或者更一般的Class< T >::new

          final Car car = Car.create( Car::new ); final List< Car > cars = Arrays.asList( car );

          静态方法引用:它的语法是Class::static_method

          cars.forEach( Car::collide );

          特定类的任意对象的方法引用:它的语法是Class::method

          cars.forEach( Car::repair );

          特定对象的方法引用:它的语法是instance::method

          final Car police = Car.create( Car::new ); cars.forEach( police::follow );

          七、Stream流式编程

          什么是 Stream?

          Stream(流)是一个来自数据源的元素队列并支持聚合操作

          • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
          • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
          • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

          和以前的Collection操作不同, Stream操作还有两个基础的特征:

          • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
          • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

           使用 Stream流的步骤

          • 创建Stream:从一个数据源(集合、数组)中获取
          • 中间操作:一个操作的中间链,对数据源的数据进行处理
          • 终止操作:一个终止操作,执行中间操作链,并产生结果

           排序去重

          //Stream 流式编程
          public class StreamTest01 {
              public static void main(String[] args) {
                  //需求:有一堆数据,且有重复值,要求有序去除重复值
                  List<Integer> list = new ArrayList<>();
                  Collections.addAll(list,56,89,75,64,24,25,24,89,56,75);
           
                  //流式编程处理
                  //获取stream
                  Stream<Integer> stream = list.stream();
                  //中间操作
                  sthttp://www.devze.comream = stream.distinct()//去重操作
                                  .sorted();//排序
                  //终止操作
                  stream.forEach( x->{//输出集合中元素
                      System.out.println(x);
                  } );
              }
          }

          中间操作

                  stream = stream.distinct()//去重操作
                                  .sorted();//排序
                  .limit( 4 );//取前四个元素
                  .skip( 2 );//跳过前几个元素
                  .map( x->x+4 );//每一个元素加上特定的值
                  .filter( x->{//过滤操作,true正常返回,false不返回
                      if (x>=25){
                          return true;
                      }
                      return false;
          php        } );

          八、串行流和并行流

          串行流

                  Stream<Integer> stream = list.stream();//串行流

          并行流

                  Stream<Integer> stream1 = list.paral开发者_Go学习lelStream();//并行流

          九、Optional 类

          • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
          • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
          • Optional 类的引入很好的解决空指针异常。

            Optional 类的方法

          • static <T> Optional<T> empty()        返回空的 Optional 实例。
          • boolean equals(Object obj)        判断其他对象是否等于 Optional。
          • Optional<T> filter(Predicate<? super <T> predicate)        如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
          • <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)     &njsbsp;  如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
          • T get()        如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
          • int hashCode()        返回存在值的哈希码,如果值不存在 返回 0。
          • void ifPresent(Consumer<? super T> consumer)        如果值存在则使用该值调用 consumer , 否则不做任何事情。
          • boolean isPresent()        如果值存在则方法会返回true,否则返回 false
          • <U>Optional<U> map(Function<? super T,? extends U> mapper)        如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
          • static <T> Optional<T> of(T value)        返回一个指定非null值的Optional。
          • static <T> Optional<T> ofNullable(T value)       如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
          • T orElse(T other)       如果存在该值,返回值, 否则返回 other。
          • T orElseGet(Supplier<? extends T> other)       如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
          • <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)       如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
          •   String toString()     返回一个Optional的非空字符串,用来调试

          以上就是Java8新特性-Lambda表达式详解的详细内容,更多关于Java Lambda表达式的资料请关注我们其它相关文章!

          0

          上一篇:

          下一篇:

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          最新开发

          开发排行榜