Java8新特性之lambda 表达式与函数式接口

createh52个月前 (02-01)技术教程10


简介

lambda 表达式的类型,也被称为“目标类型(target type)”,lambda 表达式的目标类型必须是“函数式接口(functional interface)”。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但是只能声明一个抽象方法。

从这里可以看到,Java 8 对接口增加了 static 以及 default 关键字,就可以说的通了。为了让 @FunctionalInterface(函数式接口)使用起来更加方便。

Java8 专门为函数式接口提供了 @FunctionalInterface 注解,该注解通常放在接口定义前面,该注解对程序功能没有任何作用,他用于告诉编译器执行更加严格的检查——检查该接口必须是函数式接口,否则编译器就会报错。

代码示例

lambda 表达式的限制

由于 lambda 表达式的结果就是被当成对象,因此程序中完全可以使用 lambda 表达式进行赋值。

// Runnable 接口中只包含一个无参的方法
// lambda 表达式代表的匿名方法实现了 Runnable 接口中的唯一的、无参方法
// 下面的语句创建了一个 Runnable 对象
Runnable r = () -> {
    for( int i=0; i<100; i++ ){
        System.out.println();
    }
}

lambda 表达式实现的是匿名方法——因此它只能实现特定函数式接口中的唯一方法。因此可以看到 lambda 表达式有如下两个限制。

  • lambda 表达式的目标类型必须是明确的函数式接口。
  • lambda 表达式只能为函数式接口创建对象。lambda 表达式只能实现一个方法,因此它只能为只有一个抽象方法的接口(函数式接口)创建对象。

错误的代码

// 这段代码是错误的
// 会报:不兼容的类型: object 不是函数接口
Object obj = () -> {
    for( int i=0; i<100; i++ ){
        System.out.println();
    }
}

Java 8 中的4类内建函数式接口

  • XxxFunction,功能型接口。 语法:public interface Function{public R apply(T t);}。该接口通常用于对指定数据进行转换处理。 apply() 抽象方法,对参数进行处理、转换。然后返回一个新的值。
  • XxxConsumer,消费型接口。语法:public interface Consumer{public void accept(T t);}。该方法与 apply() 方法类似,也负责对参数进行处理,只是该方法不会返回处理结果。
  • XxxSupplier,供给型接口。语法:public interface Supplier{public T get()}。这类接口通常含有 getAsXxx() 接口。该方法不需要输入参数,该方法会按照某种逻辑算法(逻辑算法由 lambda 表达式实现)返回一个数据。
  • XxxPredicate,断言型接口。语法:public interface Predicate{public boolean test(T t);}。该方法通常用来对参数进行某种判断是否满足特定条件,经常用于筛选数据。

功能型接口

import java.util.function.Function;
 
public class Demo {
	public static void main(String[] args) {
		Function fun = "hello world"::startsWith;
		System.out.println(fun.apply("hello"));
	}
}

详细说明

/**
 * Function测试
 */
public static void functionTest() {
    Function f = i -> i + 10;
    Function g = s -> s * 2;

    /**
     * 下面表示在执行F时,先执行G,并且执行F时使用G的输出当作输入。
     * 相当于以下代码:
     * Integer a = g.apply(1);
     * System.out.println(f.apply(a));
     */
    System.out.println(f.compose(g).apply(1));

    /**
     * 表示执行F的Apply后使用其返回的值当作输入再执行G的Apply;
     * 相当于以下代码
     * Integer a = f.apply(1);
     * System.out.println(g.apply(a));
     */
    System.out.println(f.andThen(g).apply(1));

    /**
     * identity方法会返回一个不进行任何处理的Function,即输出与输入值相等; 
     */
    System.out.println(Function.identity().apply("a"));
}

消费型接口

import java.util.function.Consumer;;
 
class MyDemo{
	public void print(String str) {
		System.out.println(str);
	}
}
public class Demo {
	public static void main(String[] args) {
		Consumer con = new MyDemo()::print;
		con.accept("Good!");
		
		Consumer con1 = System.out::println;
		con1.accept("Nice!");
	}
}

详细说明

public static void consumerTest() {
    Consumer f = System.out::println;
    Consumer f2 = n -> System.out.println(n + "-F2");

    //执行完F后再执行F2的Accept方法
    f.andThen(f2).accept("test");

    //连续执行F的Accept方法
    f.andThen(f).andThen(f).andThen(f).accept("test1");
}

供给型接口

import java.util.function.Supplier;
 
public class Demo {
	public static void main(String[] args) {
		Supplier sup = "hello".substring(2, 5)::toUpperCase;
		String str = sup.get();
		System.out.println(str);
	}
}

断言型接口

import java.util.function.Predicate;
 
public class Demo {
	public static void main(String[] args) {
		Predicate pre = "Good"::endsWith;
		System.out.println(pre.test("od"));
	}
}

详细说明

/**
 * Predicate测试
 */
private static void predicateTest() {
    Predicate p = o -> o.equals("test");
    Predicate g = o -> o.startsWith("t");

    /**
     * negate: 用于对原来的Predicate做取反处理;
     * 如当调用p.test("test")为True时,调用p.negate().test("test")就会是False;
     */
    Assert.assertFalse(p.negate().test("test"));

    /**
     * and: 针对同一输入值,多个Predicate均返回True时返回True,否则返回False;
     */
    Assert.assertTrue(p.and(g).test("test"));

    /**
     * or: 针对同一输入值,多个Predicate只要有一个返回True则返回True,否则返回False
     */
    Assert.assertTrue(p.or(g).test("ta"));
}

相关文章

全面理解Java接口(java接口总结)

接口接口概念接口(Interface),在JAVA编程语言中是一个抽象类型,是一系列方法的声明,是一些方法特征的集合。 一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现...

Java 中那些绕不开的内置接口——Comparable 和 Comparator

恰巧今天要介绍的两个Java 内置接口在名字上乍一看也有点让人分不清楚,他们是 Comparable 和 Comparator 接口。如果你英文还可以应该能猜出来两者的区别,这篇我会用一些示例给大家解...

Java基础之浅谈接口(java接口基础知识)

前言前几篇文章我们已经把Java的封装、继承、多态学习完了,现在我们开始比较便于我们实际操作的学习,虽然它也是Java基础部分,但是其实入门容易,精通很难。我认真的给大家整理了一下这些必须学会、了解的...

Java的类与接口(java 接口和类)

Java是一门面向对象的编程语言,主要核心点就是类,Java类具有封装,继承,多态的特性;在Java中,类里面包含了某类事物的基本属性,将这些属性封装起来,只对外部公开别人可以访问的信息,不想让别人访...

抽象类和接口(抽象类和接口的区别和相同点)

抽象类就像这个代码:在这个打印图形的例子当中,可以看到父类的 shape 方法并没有实际作用,主要的工作都由子类完成了,像这些没有实际工作的方法,我们就可以把它设计成一个抽象方法,包含抽象方法的类叫做...

揭秘什么是面向接口编程(面向接口的好处)

先用一个案例来给大家说明一下面向接口编程。案例:有一个电脑类(Computer),电脑除了有基本的开机关机功能外,还有连接任何外接设备的功能,比如能电脑能连接外置键盘(Keyboard),鼠标(Mou...