Function

我们知道Java8的最大特性就是函数式接口。所有标注了@FunctionalInterface注解的接口都是函数式接口,具体来说,所有标注了该注解的接口都将能用在lambda表达式上。

接口介绍

/**
* Represents a function that accepts one argument and produces a result.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
*
* @since 1.8
*/

上述描述可知: Function中传递的两个泛型:T,R分别代表 输入参数类型和返回参数类型。下面将逐个介绍Function中的各个接口:

接口1: 执行具体内容接口

R apply(T t);

实例1:apply使用
    // 匿名类的方式实现
Function<Integer, Integer> version1 = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer integer) {
return integer++;
}
};
int result1 = version1.apply(20); // lamda表达式
Function<Integer, Integer> version2 = integer -> integer++;
int result2 = version1.apply(20);

接口2: compose

该方法是一个默认方法,这个方法接收一个function作为参数,将参数function执行的结果作为参数给调用的function,以此来实现两个function组合的功能。

// compose 方法源码
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
实例2:compose使用
public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.compose(function2).apply(a);
} // 调用上述方法
test.compute(2, value -> value * 3, value -> value * value)
// 执行结果: 12 (有源码可以看出先执行before)

接口3 : andThen

了解了compose方法,我们再来看andThen方法就好理解了,听名字就是“接下来”,andThen方法也是接收一个function作为参数,与compse不同的是,先执行本身的apply方法,将执行的结果作为参数给参数中的function。

public interface Function<T, R> {
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
}
实例3:andThen使用
public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.andThen(function2).apply(a);
} // 调用上述方法
test.compute2(2, value -> value * 3, value -> value * value)
// 执行结果 : 36

反思: 多个参数

Function接口虽然很简洁,但是由Function源码可以看出,他只能传一个参数,实际使用中肯定不能满足需求。下面提供几种思路:

  1. BiFunction可以传递两个参数(Java8中还提供了其它相似Function)
  2. 通过封装类来解决
  3. void函数还是无法解决

因为参数原因“自带的Function”函数必然不能满足业务上复杂多变的需求,那么就自定义Function接口吧

@FunctionalInterface
static interface ThiConsumer<T,U,W>{
void accept(T t, U u, W w); default ThiConsumer<T,U,W> andThen(ThiConsumer<? super T,? super U,? super W> consumer){
return (t, u, w)->{
accept(t, u, w);
consumer.accept(t, u, w);
};
}
}

自此,Function接口介绍完毕。

断言性接口:Predicate

接口介绍:

/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {

Predicate是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。跟Function一样,Predicate的具体实现也是根据传入的lambda表达式来决定的。

源码不再具体分析,主要有 test/and/or/negate方法,以及一个静态方法isEqual,具体使用实例如下:

    private static void testPredict() {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
List<Integer> list = new ArrayList<>();
for (int i : numbers) {
list.add(i);
} // 三个判断
Predicate<Integer> p1 = i -> i > 5;
Predicate<Integer> p2 = i -> i < 20;
Predicate<Integer> p3 = i -> i % 2 == 0;
List test = list.stream()
.filter(p1
.and(p2)
// .and(Predicate.isEqual(8))
.and(p3))
.collect(Collectors.toList());
System.out.println(test.toString());
//print:[6, 8, 10, 12, 14]
}

供给性接口:Supplier

接口介绍

/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T>

使用实例:

        Supplier supplier = "Hello"::toLowerCase;
System.out.println(supplier);

消费性:Consumer

接口介绍

/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {

实际使用

    NameInfo info = new NameInfo("abc", 123);
Consumer<NameInfo> consumer = t -> {
String infoString = t.name + t.age;
System.out.println("consumer process:" + infoString);
};
consumer.accept(info);

总结:

本文主要介绍Java8的接口式编程,以及jdk中提供的四种函数接口(FunctionalInterface)。Predict/Supplier/Consumer其实是Function的一种变形,所以没有详细介绍。

疑问: FunctionalInterface注解是如何和lamada表达式联系在一起,函数接口在编译时又是如何处理的?后面再了解下

java8 函数式接口——Function/Predict/Supplier/Consumer的更多相关文章

  1. Java8 函数式接口 @FunctionalInterface以及常用Consumer<T>、Supplier<T>、Function<T, R>、Predicate<T>总结

    首先看看什么是Lambda 表达式 Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递):最简单的Lambda表达式可由逗号分隔的参数列表.-> ...

  2. 详解JAVA8函数式接口{全}

    1: 函数式接口 1.1 概念 1.2 格式 1.3@FunctionalInterface注解 1.4 调用自定义函数接口 2:函数式编程 2.1:lambda的延迟执行 2.2 使用Lambda作 ...

  3. JAVA8 函数式接口

    一.什么是函数式接口 1.只包含一个抽象方法的接口,称为函数式接口. 2.你可以通过Lambda表达式来创建该接口的对象.(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进 ...

  4. java代码之美(14)---Java8 函数式接口

    Java8 函数式接口 之前写了有关JDK8的Lambda表达式:java代码之美(1)---Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加 ...

  5. java代码(14) --Java8函数式接口

    Java8函数式接口 之前有关JDK8的Lambda表达式 Java代码(1)--Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加简洁 一.概 ...

  6. 常用的函数式接口Function接口和常用的函数式接口Function接口默认方法andThen

    常用的函数式接口Function接口 package com.yang.Test.FunctionStudy; import java.util.function.Function; /** * ja ...

  7. Java8 函数式接口-Functional Interface

    目录 函数式接口: JDK 8之前已有的函数式接口: 新定义的函数式接口: 函数式接口中可以额外定义多个Object的public方法一样抽象方法: 声明异常: 静态方法: 默认方法 泛型及继承关系 ...

  8. Java8函数式接口和Lambda表达式

    两者关系: Lambda表达式就是函数式接口(FunctionalInterface)实现的快捷方式,它相当于函数式接口实现的实例,因为在方法中可以使用Object作为参数,所以把Lambda表达式作 ...

  9. java8函数式接口(Functional Interface)

    介绍 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. 函数式接口可以被隐式转换为 lambda 表达式(箭头函数). 函数式接口代 ...

随机推荐

  1. STM32F042开发板学习实践

    之前有粗略地学习过stm32F103的理论知识,但仅GPIO的配置.时钟配置就让人望而却步.现在手头有Nucleo STM32F042的开发板,而且ST已经推出STM32CubeMx图形化的工具软件, ...

  2. Dede技巧

    解决DEDE图集上传图片时跳出302错误   本地上传图集的时候突然提示网页出错,还爆出302错误. 解决办法是在include/userlogin.class.php文件中的第二行session_s ...

  3. Spring XML配置文件无法自动提示 eclipse中XML配置文件open with打开方式选择 XML Editor:注意它的编辑方式也是有两种的design和source

    双击XML配置文件,如果打开方式不正确 则如下图: 都是灰色显示,不会有自动提示,也不会有颜色标注 右击XML配置文件,选择打开方式为XML Editor,则会有颜色标注 如果此时没有自动提示 则要手 ...

  4. Sum All Numbers in a Range-freecodecamp算法题目

    Sum All Numbers in a Range 要求 给你一个包含两个数字的数组.返回这两个数字和它们之间所有数字的和. 最小的数字并非总在最前面. 思路 定义结果变量num 在for循环中,i ...

  5. 控件中添加的成员变量value和control的区别

    control型变量是这个控件所属类的一个实例(对象)可以通过这个变量来对该控件进行一些设置.而value只是用来传递数据,不能对控件进行其它的操作.control型变量可以获得控件的实例,通过这个变 ...

  6. NOIP模拟赛 麻将

    [题目描述] 众所周知,麻将是我们国家的国粹.这段时间,小D也迷上了麻将这个老少皆宜的游戏. 小D觉得这些不同规则的麻将太麻烦了,所以他集合了很多种麻将规则创造出了一套D麻将.下面是D麻将的几个特点: ...

  7. json转换为字典

    str---dict ata_dict=json.loads(data)

  8. 如何解决js跨域问题

    Js跨域问题是web开发人员最常碰到的一个问题之一.所谓js跨域问题,是指在一个域下的页面中通过js访问另一个不同域下的数据对象,出于安全性考 虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些a ...

  9. 使用TensorFlow的卷积神经网络识别手写数字(1)-预处理篇

    功能: 将文件夹下的20*20像素黑白图片,根据重心位置绘制到28*28图片上,然后保存.经过预处理的图片有利于数字的准确识别.参见MNIST对图片的要求. 此处可下载已处理好的图片: https:/ ...

  10. 命令行执行Qt程序

    原文网址 //helloworld.cpp #include <QApplication> #include <QPushButton> int main(int argc,c ...