参考:https://blog.csdn.net/jmj18756235518/article/details/81490966

函数式接口

定义:有且只有一个抽象方法的接口

Function<T, R>: y = f(x) T: x 输入参数, R: 返回结果,y

所有标注了@FunctionalInterface注解的接口都是函数式接口,所有标注了该注解的接口都将能用在lambda表达式上

特点:通过传入不同的Function,实现了在同一个方法中实现不同的操作,在实际开发中可以大大减少很多重复的代码。

例如:新增用户的功能,用户分为VIP和普通用户,且有两种不同的新增逻辑。那么此时我们就可以先写两种不同的逻辑。除此之外,这样还让逻辑与数据分离开来,我们可以实现逻辑的复用。

函数式编程与非函数式编程的区别

函数式编程: 先考虑传入的参数,再考虑方法的实现

非函数式编程:先定义好方法,再传入指定的参数

/**
* 需求
* 1.定义一个函数式接口CurrentTimePrinter,其中抽象方法void printCurrentTime(),使用注解@FunctionalInterface
* 2.在测试类中定义static void showLongTime(CurrentTimePrinter timePrinter),该方法的预期行为是使用timePrinter打印系统当前毫秒值
* 3.测试showLongTime(),通过lambda表达式完成需求
*/
@FunctionalInterface
public interface CurrentTimePrinter {
void printCurrentTime();
} 测试类
public class FunctionalInterfaceTest {
/**
* 打印当前系统的毫秒值
* @param timePrinter
*/
public static void showLongTime(CurrentTimePrinter timePrinter){
timePrinter.printCurrentTime();
} public static void main(String[] args) {
showLongTime(() -> System.out.println(System.currentTimeMillis()));
}
} /**
* 需求
* 1.定义一个函数式接口IntCalc,其中抽象方法int calc(int a , int b),使用注解@FunctionalInterface
* 2.在测试类中定义static void getProduct(int a , int b ,IntCalc calc), 该方法的预期行为是使用calc得到a和b的乘积并打印结果
* 3.测试getProduct(),通过lambda表达式完成需求
*/
@FunctionalInterface
public interface IntCalc {
int calc(int a , int b);
} 测试类:
/**
* 需求
* 定义static void getProduct(int a , int b ,IntCalc calc), 该方法的预期行为是使用calc得到a和b的乘积并打印结果
*/
public class FunctionalInterfaceTest02 {
static void getProduct(int a , int b ,IntCalc calc){
int result = calc.calc(a, b);
System.out.println(result);
} public static void main(String[] args) {
getProduct(2,3, (a, b) -> a*b);
}
}

静态方法的引用

/**
* 1.定义一个函数式接口NumberToString,其中抽象方法String convert(int num),使用注解@FunctionalInterface
* 2.在测试类中定义static void decToHex(int num ,NumberToString nts),
* 该方法的预期行为是使用nts将一个十进制整数转换成十六进制表示的字符串,tips:已知该行为与Integer类中的toHexString方法一致
* 3.测试decToHex (),使用方法引用完成需求
*/
@FunctionalInterface
public interface NumberToString {
String convert(int num);
}

测试类

public class FunctionalInterfaceTest03 {
/**
* 需求:
* 在测试类中定义static void decToHex(int num ,NumberToString nts),
* 该方法的预期行为是使用nts将一个十进制整数转换成十六进制表示的字符串,tips:已知该行为与Integer类中的toHexString方法一致
*/
public static void main(String[] args) {
//NumberToString类的方法的实现使用了Integer 类的toHexString 方法
decToHex(999, Integer::toHexString);
}
public static void decToHex(int num ,NumberToString nts){
String convert = nts.convert(num);
System.out.println(convert);
}
}

使用函数式编程来实现延迟加载

Predicate的使用(构造断言式):

简介:predicate是一个接口,含有一个抽象方法test(),含有4个由default修饰的具体实现方法and()、or()、negate()、isEquals()

and()对应java的连接符 &&;

or()对应java的连接符 || ;

negate()对应java的连接符 ! ;

isEquals对应java的连接符 == ;

package com.test.stream;

/**
* @program: basic-java
* @Author:chenxuebing
* @Date:2019-09-16 9:25
* @Description:(描述)
*/ import java.util.function.Predicate; /**
* 需求:1.请在测试类main方法中完成以下需求
* 已知有Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213}
* a)使用lambda表达式创建Predicate对象p1,p1能判断整数是否是自然数(大于等于0)
* b)使用lambda表达式创建Predicate对象p2,p2能判断整数的绝对值是否大于100
* c)使用lambda表达式创建Predicate对象p3,p3能判断整数是否是偶数
*
* 遍历arr,仅利用已创建的Predicate对象(不使用任何逻辑运算符),完成以下需求
* i.打印自然数的个数
* ii.打印负整数的个数
* iii.打印绝对值大于100的偶数的个数
* iv.打印是负整数或偶数的数的个数
*/
public class Test01 {
public static void main(String[] args) {
Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213};
Predicate<Integer> p1 = (t) -> t >= 0;
Predicate<Integer> p2 = (t) -> Math.abs(t) > 100;
Predicate<Integer> p3 = (t) -> t % 2 == 0;
int count1 = 0;
int count2 = 0;
int count3 = 0;
int count4 = 0;
for(int a : arr){
//自然数个数
if(p1.test(a)){
count1++;
}
//绝对值大于100的偶数的个数
if(p2.and(p3).test(a)){
count2++;
}
//负整数的个数
if(p1.negate().test(a)){
count3++;
}
//负整数或偶数的数的个数
//先找满足条件的负整数,再找满足条件的偶数,然后取交集,p1.negate(),!p1.test(),p3.test()取交集
if(p1.negate().or(p3).test(a)){
count4++;
}
}
System.out.println("自然数"+ count1);
System.out.println("绝对值大于100的偶数的个数"+ count2);
System.out.println("负整数的个数"+ count3);
System.out.println("负整数或偶数的数的个数"+ count4);
}
}

Function接口的使用

简介:含有一个抽象方法R apply(T t), 两个default修饰的实现了的方法compose(), andThen()

特点:

f1.compose(f2).apply(T) : 先执行f2.apply(T), 再执行f1.apply(f2.apply(T))

compose接收一个Function参数,返回时先用传入的逻辑执行apply,然后使用当前Function的apply

f1.andThen(f2).apply(T): 先执行f1.apply(T) , 再执行分f2.apply(f1.apply(T))

andThen跟compose正相反,先执行当前的逻辑,再执行传入的逻辑。

/**
* 需求
* 1.使用lambda表达式分别将以下功能封装到Function对象中
* a)求Integer类型ArrayList中所有元素的平均数
* b)将Map<String,Integer>中value存到ArrayList<Integer>中
* 2.已知学生成绩如下
* 姓名 成绩
* 岑小村 59
* 谷天洛 82
* 渣渣辉 98
* 蓝小月 65
* 皮几万 70
* 3.以学生姓名为key成绩为value创建集合并存储数据,使用刚刚创建的Function对象求学生的平均成绩
*/
public class FunctionTest {
public static void main(String[] args) {
//使用Lambda表达式求Integer类型ArrayList中所有元素的平均数
Function<ArrayList<Integer>, Integer> f1 = (list) -> {
int sum = 0;
int count = 0;
for(Integer score : list){
sum += score;
count++;
}
return sum/count;
};
//使用Lambda表达式将Map<String,Integer>中value存到ArrayList<Integer>中
Function<Map<String, Integer>, ArrayList<Integer>> f2 = (map) -> {
ArrayList<Integer> scoreList = new ArrayList<>();
Collection<Integer> values = map.values();
for(Integer score : values){
scoreList.add(score);
}
return scoreList;
}; //以学生姓名为key成绩为value创建集合并存储数据
Map<String,Integer> map = new HashMap<String, Integer>();
map.put("岑小村", 59);
map.put("谷天洛", 82);
map.put("渣渣辉", 98);
map.put("蓝小月", 65);
map.put("皮几万", 70);
//使用刚刚创建的Function对象求学生的平均成绩
//f1.compose(f2).apply(map),先求f2.apply(map),再求 f1.apply(f2.apply(map)),f2.apply(map)的返回值作为f1的apply的参数值
int averge = f1.compose(f2).apply(map);
System.out.println(averge);
} }

Supplier接口(生产者)

简介:Supplier函数式接口

        T get()抽象方法,返回一个T类型的对象

import java.util.function.Supplier;

/**
* Supplier函数式接口
* 抽象方法 T get(): 返回一个T类型的对象
*/
public class SupplierTest {
//Supplier<String> supplier 的泛型为String,那么它的get 方法返回对象也是一个String类型
public static String getString(Supplier<String> supplier){
return supplier.get();
} public static void main(String[] args) {
//若方法体只有一条语句可以省略{} 和 return
String result = getString(() -> "胡歌");
System.out.println(result);
}
}

Consumer接口(消费者)

import java.util.function.Consumer;

/**
* Consumer函数式编程接口
* void accept(T t)方法, 用来做消费
*/
public class ConsumerTest {
//对String类型的对象进行消费
public static void method(String name, Consumer<String> consumer){
consumer.accept(name);
} public static void main(String[] args) {
//对name,进行消费,反转打印姓名
method("赵丽颖", name -> {
StringBuilder builder = new StringBuilder();
builder.append(name);
System.out.println(builder.reverse().toString());
});
}
}

andThen()方法

/**
* andThen(Consumer)
* consumer1.andThen(consumer2).accept(T)
* 先执行consumer1.accept(T),再执行consumer2.accept(T),因为T是对象,consumer1对对象进行消费后对象发生变化
* 随着consumer2消费的对象是consumer1消费后的对象
*/
public class ConsumerAndThenTest {
public static void method (int[] arr, Consumer<int[]> consumer1, Consumer<int[]> consumer2){
consumer1.andThen(consumer2).accept(arr);
} public static void main(String[] args) {
method(new int[]{1, 3, 5, 6},
//将数组的第一个元素改为0
arr -> {
System.out.println( arr[1] = 0);
System.out.println(arr.toString());
},// 0, 3, 5, 6
//将数组的第一个元素改为1
arr -> {
System.out.println(arr[2] = 2); // 2, 3, 5, 6
System.out.println(arr[1]);
}
);
}
}

函数式接口的使用 (Function、Predicate、Supplier、Consumer)的更多相关文章

  1. Java8常用的内置函数式接口(一)Predicate、Consumer、Supplier、Function

    Java8常用的内置函数式接口(一) 简介 JDK 1.8 API中包含了很多内置的函数式接口.有些是在以前版本的Java中大家耳熟能详的,例如Comparator接口,或者Runnable接口.对这 ...

  2. 函数式接口java.util.function

    什么是函数式接口 为什么要用函数式接口 java.util.function和其他的函数式接口 lamdba表达式 方法引用 流 Stream 1 什么是函数式接口 用@FunctionInterfa ...

  3. java8 函数式接口——Function/Predict/Supplier/Consumer

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

  4. JAVA 8 函数式接口--Consumer

    从JDK8开始java支持函数式编程,JDK也提供了几个常用的函数式接口,这篇主要介绍Consumer接口.文本介绍的顺序依次为: 源码介绍 使用实例 jdk内对Consumer的典型使用 扩展类介绍 ...

  5. 常用的函数式接口_Supplier和常用的函数式接口Supplier接口练习_求数组中元素最大值

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

  6. Java 8 中常用的函数式接口

    函数式接口 函数描述符 Predicate<T> T->boolean Consumer<T> T->void Function<T, R> T-> ...

  7. JAVA 8 主要新特性 ----------------(四)Lambda函数式接口

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

  8. Java8 函数式接口-Functional Interface

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

  9. Java 8函数式接口functional interface的秘密

    Java 8函数式接口functional interface的秘密 2014年10月29日 17:52:55 西瓜可乐520 阅读数:3729   目录 [−] JDK 8之前已有的函数式接口 新定 ...

随机推荐

  1. python学习-变量和简单类型(二)

    学习笔记中的源码:传送门 1.注释: 单行注释(#):多行注释("""或者''') 2.python标准数据类型:数字(numbers).字符串(string).列表(l ...

  2. 【教程】基于Ubuntu系统的PyTorch虚拟环境配置

    目录 一.PyTorch虚拟环境配置 二.PyTorch虚拟环境使用 三.常用命令 Editor: Veagau Time: 2019/10/17 一.PyTorch虚拟环境配置 该部分操作均在终端( ...

  3. Django之CBV视图源码分析(工作原理)

    1.首先我们先在urls.py定义CBV的路由匹配. FBV的路由匹配: 2.然后,在views.py创建一名为MyReg的类: 注意:该类必须继续View类,且方法名必须与请求方式相同(后面会详解) ...

  4. MyBatis 示例-简介

    简介 为了全面熟悉 MyBatis 的使用,整理一个 MyBatis 的例子,案例中包含了映射器.动态 SQL 的使用.本章先介绍项目结构和配置. 项目地址:链接 数据库表的模型关系:链接 项目结构 ...

  5. 第3次作业-MOOC学习笔记:Python网络爬虫与信息提取

    1.注册中国大学MOOC 2.选择北京理工大学嵩天老师的<Python网络爬虫与信息提取>MOOC课程 3.学习完成第0周至第4周的课程内容,并完成各周作业 4.提供图片或网站显示的学习进 ...

  6. 150行代码搭建异步非阻塞Web框架

    最近看Tornado源码给了我不少启发,心血来潮决定自己试着只用python标准库来实现一个异步非阻塞web框架.花了点时间感觉还可以,一百多行的代码已经可以撑起一个极简框架了. 一.准备工作 需要的 ...

  7. Spring MVC(1)Spring MVC的初始化和流程以及SSM的实现

    一.Spring MVC概述 1.Spring MVC 的架构 对于持久层而言,随着软件的发展,迁移数据库的可能性很小,所以在大部分情况下都用不到Hibernate的HQL来满足迁移数据库的要求.与此 ...

  8. URL百分号编码

    百分号编码是什么! 百分号编码(Percent-Encoding)也被称为 URL 编码,是一种编码机制.该机制主要应用于 URI 编码中,URI 包含 URL 和 URN,所以它们也同样适用.除此之 ...

  9. SpringBoot配置文件之Yml语法

    一 使用 YAML 而不是 Properties YAML是 JSON 的超集,因此,它是用于指定分层配置数据的便捷格式.只要 class 路径上有SnakeYAML library,SpringAp ...

  10. 这一次,彻底理解Promise源码思想

    关于Promise的源码实现,网上有太多答案,我也看过很多资料,但都不是很明白.直到有一天我学完函数式编程之函子的概念,才对Promise源码有了更深刻的认识.今天,就让我们来重新认识一下Promis ...