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

createh54个月前 (02-01)技术教程20


简介

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的类与接口(java 接口和类)

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

今天就来随便讲讲:Java 接口和抽象类的区别吧。(详解)

在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。下面就来讲讲二者的区别。什么是抽象类和接口? 区别在哪里?不同的编程语...

Java基础-抽象类、接口详解(java实验五抽象类和接口)

1、抽象类1.1 什么是抽象类Java中抽象类是指被abstract修饰的类,何为抽象,抽象指的是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程,所以抽象类主要用来定义类的一些共...

如何理解Java中接口存在的意义(java接口的目的)

0. 前言在我自己早期学习编程的时候,对接口存在的意义实在困惑,我自己乱写代码的时候基本上不可能意识到需要去写接口,不知道接口到底有什么用,为什么要定义接口,感觉定义接口只是 提前做了个多余的工作。这...

Java编程新范式:用枚举实现接口定义的行为

在Java中,枚举(enum)是一种特殊的类,它不仅可以表示一组常量,还可以拥有字段、方法、构造函数等。从Java 8开始,枚举类型可以被实例化,这意味着它们可以拥有状态,并且可以定义行为,这使得枚举...