java函数式接口(lambda表达式)

2022-06-14 16:41:17 浏览数 (1)

Java8新特性

Java8的新特性主要是lambda表达式和流,它是推动 Java 8 发布的最重要新特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)使用 Lambda 表达式可以使代码变的更加简洁紧凑

为什么要学函数式编程

面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学

和匿名内部类的比较

设计匿名内部类的目的,就是为了方便 Java 程序员将代码作为数据传递。不过,匿名内部类还是不够简便

入门示例:

代码语言:javascript复制
button.addActionListener(event -> System.out.println("button clicked"));

说明:event 是参数名,-> 将参数和 Lambda 表达式的主体分开,在Lambda 表达式中无需指定参数类型

如何辨别Lambda表达式

简单示例: 1 Lambda 表达式不包含参数,使用空括号 () 表示没有参数。该 Lambda 表达式实现了 Runnable 接口,该接口也只有一个 run 方法,没有参数,且返回类型为 void

代码语言:javascript复制
Runnable noArguments = () -> System.out.println("Hello World");

2 Lambda 表达式包含且只包含一个参数,可省略参数的括号

代码语言:javascript复制
ActionListener oneArgument = event -> System.out.println("button clicked");

3 Lambda 表达式的主体不仅可以是一个表达式,而且也可以是一段代码块,使用大括号({})将代码块括起来,如下所示。该代码块和普通方法遵循的规则别无二致,可以用返回或抛出异常来退出。只有一行代码的 Lambda 表达式也可使用大括号,用以明确 Lambda表达式从何处开始、到哪里结束

代码语言:javascript复制
Runnable multiStatement = () -> {
System.out.print("Hello");
System.out.println(" World");
};

4 Lambda 表达式也可以表示包含多个参数的方法,如下所示。这时就有必要思考怎样去阅读该 Lambda 表达式。这行代码并不是将两个数字相加,而是创建了一个函数,用来计算两个数字相加的结果。变量 add 的类型是BinaryOperator,它不是两个数字的和,而是将两个数字相加的那行代码。

代码语言:javascript复制
BinaryOperator<Long> add = (x, y) -> x   y;

也可指定参数类型: BinaryOperator addExplicit = (Long x, Long y) -> x y;

将 Lambda 表达式赋值给一个局部变量,或传递给一个方法作为参数,局部变量或方法参数的类型就是 Lambda 表达式的目标类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型

java中重要的函数接口:

第二部分:流(Stream API)

什么是流:流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算 作用:流使程序员得以站在更高的抽象层次上对集合进行操作,和 Iterator 类似,Stream 是一种内部迭代方式。将 Lambda 表达式和Stream 上的方法结合起来,可以完成很多常见的集合操作。

Java 程序员在使用集合类时,一个通用的模式是在集合上进行迭代,然后处理返回的每一个元素 List接口中的stream()函数

代码语言:javascript复制
default Stream<E> stream() {
     return StreamSupport.stream(spliterator(), false);
   }

Stream接口当中包含的方法:

  • Stream接口中的方法的参数就是一个函数式接口

测试案例1:

代码语言:javascript复制
 @Test
    public void stream01(){
        List<Integer> list = new ArrayList<>();
        list.add(1232);
        list.add(435345);
        list.add(657868);
        list.stream().forEach(i -> System.out.println(i));
        System.out.println(list.stream().count()); // count函数用 
        于输出集合中元素个数
        
    }
打印结果:
1232
435345
657868

stream.filter一般适用于list集合,从集合中查询想要的数据

代码语言:javascript复制
 list.stream().forEach(System.out::println);
代码语言:javascript复制
@Test
    public void stream02(){
        List<Integer> list = new ArrayList<>();
        list.add(1232);
        list.add(435345);
        list.add(657868);
        list.add(null);
 	list.stream().filter(StringUtils::isNotBlank).forEach(System.out::println);   //将等于null的过滤出来再打印
        list.stream().filter(i -> i>12344).forEach(j -> System.out.println(j));
    
    }

这个意思是指:筛选出list集合中值大于12344的结果,然后将其打印出来
输出结果:
435345
657868

另外一种写法:

代码语言:javascript复制
 @Test
    public void stream02(){
        List<Integer> list = new ArrayList<>();
        list.add(1232);
        list.add(435345);
        list.add(657868);
        List<Integer> li = list.stream().filter(i -> i>12344).collect(Collectors.toList());
        li.forEach(j -> System.out.println(j));
    }

返回结果:
435345
657868

map流映射

map 操作就可以使用该函数,将一个流中的值转换成一个新的流。

代码语言:javascript复制
@Test
    public void map(){
        List<String> list = new ArrayList<>();
        list.add("sssasdf");
        list.add("ahj");
        list.add("kdf");
        list.stream().map(r -> r.toUpperCase()).forEach(j -> System.out.println(j));
}
得到的结果:
SSSASDF
AHJ
KDF

对map的遍历:

代码语言:javascript复制
 @Test
    public void map1(){
        Map<String, String> map = new HashMap<>();
        map.put("name", "啊啊");
        map.put("age", "11");
        map.forEach((k,v) -> {
            if ("name".equals(k)) {
                System.out.println(k);
            }
        });
        
    }
输出结果:name


如果仅需打印的话:
 map.forEach((k,v) -> System.out.println(k)); //打印K值
 map.forEach((k,v) -> System.out.println(v)); //打印V值

方法引用

Java 8 为其提供了一个简写语法,叫作方法引用,帮助程序员重 用已有方法。用方法引用重写上面的 Lambda 表达式,代码如下: Artist::getName 标准语法为 Classname::methodName。需要注意的是,虽然这是一个方法,但不需要在后面加括号,因为这里并不调用该方法。我们只是提供了和 Lambda 表达式等价的一种结构,在需要时才会调用。凡是使用 Lambda 表达式的地方,就可以使用方法引用。

如果你想使用 Lambda 表达式创建一个 Artist 对象,可能会写出如下代码: (name, nationality) -> new Artist(name, nationality) 使用方法引用,上述代码可写为: Artist::new 这段代码不仅比原来的代码短,而且更易阅读。Artist::new 立刻告诉程序员这是在创建一个 Artist 对象,程序员无需看完整行代码就能弄明白代码的意图。另一个要注意的地方是方法引用自动支持多个参数,前提是选对了正确的函数接口。

相关参考文章链接:https://mp.weixin.qq.com/s/7l6FVTti9yKHHVUWIyemtA

0 人点赞