java中的函数式接口
是什么??
有且只有一个抽象方法的接口
场景:
适用于函数式编程场景(使用lambda表达式编程)的接口,函数式接口可以适用于lambda使用的接口。
只有确保接口中有且只有一个抽象方法,java中的lambda才能顺利推到
格式
/**
* 函数式接口:有且之哟一个抽象方法的接口
* 接口中可以包含其他的方法,包括默认方法,静态方法,私有方法
*
* @FunctionalInterface
* 作用:可以检测接口是否是一个函数式接口
* 是:编译成功
* 否:编译失败(接口中没有抽象方法,抽象方法的个数大于1)
*/ @FunctionalInterface
public interface MyInterface {
//定义一个抽象方法
public abstract void method(); // void method2();
}
函数式接口的使用:
/**
* 函数式接口的使用:可以作为方法的参数和返回值类型
*/
Lambda作为参数
例如:
public class Demo {
public static void show(MyInterface myInterface){
myInterface.method();
} public static void main(String[] args) {
//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyInterfaceImp()); //调用show方法,方法的参数是一个接口,所以可以传递接口的匿名内部类
show(new MyInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口的抽象方法");
}
}); //调用show方法,方法的参数是一个函数式接口,所以,我们可以使用lambda表达式
show(()->{
System.out.println("使用lambda表达式重写接口中的抽象方法");
}); //简化lambda表达式
show(()-> System.out.println("简化lambda表达式"));
}
注意:使用匿名内部类回生成.class文件,但是lambda表达式不会,减少JVM的加载
结果:
函数式编程
Lambda的延迟执行减少性能浪费:
例子:
/**
* 日志案例
* 发现下面代码存在性能浪费
*
* 调用showLog方法的过程:
* 先将msg1 msg2 msg3拼接好之后,调用showLog方法。
* 但是如果level不等于1,那就不执行了。
* 所以拼接字符串的过程就浪费了
*/
public class Demo01Logger {
public static void showLog(int level,String msg){
if (level == 1){
System.out.println(msg);
}
} public static void main(String[] args) {
String msg1 = "AAA";
String msg2 = "BBB";
String msg3 = "CCC"; showLog(1,msg1+msg2+msg3);
}
}
利用lambda表达式优化:
1先定义一个函数式接口
@FunctionalInterface
public interface MessageBuilder {
//定义拼接消息的抽象方法,返回拼接完成的消息
public abstract String builderMsg();
}
/**
* lambda优化
*
* lambda延迟加载:
* lambda使用前提:必须存在函数式接口:
*/
public class Demo02Logger {
//显示日志方法,
public static void showLog(int level,MessageBuilder messageBuilder){
if (level == 1){
System.out.println(messageBuilder.builderMsg());
}
} public static void main(String[] args) {
String msg1 = "AAA";
String msg2 = "BBB";
String msg3 = "CCC";
//调用showLog方法,参数MessageBuilder式一个函数式接口,可以传递Lambda表达式
showLog(1,()->{
//返回一个拼接好的字符串
System.out.println("有没有拼接");
return msg1+msg2+msg3;
});
}
}
可以通过改变日志级别,看看输出存不存在"有没有拼接"
/**
*使用lambda表达式作为参数传递,仅仅式吧参数传递到showLog方法中
* 只有满足条件,日志的等级式1
* 才会调用接口MessageBuilder中的方法builderMessage
* 进行字符串拼接
* 如果不满足
* 接口MessageBuilder中的方法builderMessage不会执行
* 不会导致性能浪费
*/
Lambda作为参数和返回值
public class Demo03Runable {
//定义一个方法startThread 方法参数使用函数式接口Runnable
public static void startThread(Runnable runnable){
new Thread(runnable).start();
} public static void main(String[] args) {
//匿名内部类实现
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程启动了");
}
}); //因为Runnable接口是一个函数式接口,里面只有一个抽象方法run方法,可以使用lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"lambda线程启动了");
}); startThread(()->
System.out.println(Thread.currentThread().getName()+"优化lambda线程启动了"));
} }
Lambda作为返回值
public class Demo02Comparator {
//定义一个方法,方法的返回值位函数式接口Comparator
public static Comparator<String> getComparator(){
//方法返回值式一个接口,返回接口的匿名内部类
return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//安装字符串降序排序
return o1.length() - o2.length(); }
}; } public static Comparator<String> getComparator2() {
//方法返回值式一个函数式接口,返回接口的lambda表达式
return (String o1, String o2)->{
return o1.length() - o2.length();
};
} //优化表达式
public static Comparator<String> getComparator3() {
//方法返回值式一个函数式接口,返回接口的lambda表达式
return ( o1, o2)-> o1.length() - o2.length();
} public static void main(String[] args) {
String[] arr = {"AAAAAAA","BBBB","CCCCCCC"};
System.out.println(Arrays.toString(arr));
//对数组进行拍寻
Arrays.sort(arr,getComparator());
System.out.println(Arrays.toString(arr));
} }
常用的函数式接口:
Supplier接口:
java.util.function.Supplier<T> 接口包含一个无参方法:T get()
作用:用来获取一个泛型参数指定类型的对象数据。
对应的lambda表达式需要提供一个符合泛型类型的对象数据
/**
* 常用函数式接口
* java.util.function.Supplier<T> 接口被称为生产型接口。
* Supplier指定什么类型的泛型就返回什么类型的数据
*/
public class Demo01Supplier {
//方法参数传递Supplier接口,泛型String,get返回一个String
public static String getString(Supplier<String> supplier){
return supplier.get();
} public static void main(String[] args) {
//调用getString方法。使用lambda表达大师
String s = getString(()->{
return "生成字符串";
}); //优化表达式
String s1 = getString(()->"优化生成字符串"); System.out.println(s);
System.out.println(s1);
}
}
结果:
生成字符串
优化生成字符串
简单练习
/**
* 求数组最大值
* 使用Supplier接口作为参数类型,通过lambda表达式求出int数组的最大值
*/
答案:
public class Demo02Test {
//获取数组元素的最大值,参数位supplier接口,泛型Integer
public static Integer getMax(Supplier<Integer> supplier){
return supplier.get();
} public static void main(String[] args) {
//定义数组
int[] arrint = {111,222,444,333};
int maxinarr =getMax(()->{
int max = arrint[0];
for (int i : arrint) {
if(i>max){
max = i;
}
}
return max;
}); System.out.println(maxinarr);
} }
Consumer
/**
* java.util.function.Consumer<T> 消费一个数据,数据类型又泛型决定
* 消费型接口,使用型接口
* accept
*
*/
public class Demo03Consumer {
public static void method(String name, Consumer<String> consumer){
consumer.accept(name);
} public static void main(String[] args) {
//因为accept有参数,所以lambda表达式需要加入参数。
method("quanzhiqiang",(String name)->{
System.out.println(name); String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);
}); }
}
结果:
quanzhiqiang
gnaiqihznauq
Consumer中的默认方法 andThen
/**
* Consumer接口默认方法andThen
* 作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,
* 在对数据进行消费
*
* Consumer<String> co1
* Consumer<String> co2
* String str1 = "done"
* co1.accept(str1)
* co2.accept(str1)
* 可以简洁点:
* co1.andThen(con2).accept(s)
*
* 连接两个Consumer接口,再进行消费,谁写前面谁先消费
*/
public class Demo4Consumer {
public static void method(String str , Consumer<String> co1,Consumer<String> co2){
co1.accept(str);
co2.accept(str);
} public static void method1(String str , Consumer<String> co1,Consumer<String> co2){
co1.andThen(co2).accept(str);//执行co1再执行co2,比上面的要简洁一些
} public static void main(String[] args) {
method1("quan",
(t)->{//lambda表达式参数的类型,可以省略
System.out.println(t.toUpperCase());
},
(t)->{
System.out.println(t.toLowerCase());
}); } }
/**
* QUAN
* quan
* 结果
*/
练习:
/**
* 字符串数组中存在多条信息,按照格式姓名:xx 性别:Xx格式打印出来
* 答应名名字位第一个Consumer接口的lambda实例
* 打印性别式第二个
* 然后拼接起来
*/ public class Demo5Consmer { public static void pringinfo(String[] arr , Consumer<String> c1,Consumer<String> c2){
for (String s : arr) {
c1.andThen(c2).accept(s);
}
}
public static void main(String[] args) {
String[] arr = {"AA,N","BB,M","CC,N"};
pringinfo(arr,
( msg)->{
// 对字符串进行分割,取出姓名
String name = msg.split(",")[0];
System.out.print("姓名:"+name);
},
(msg)->{
// 对字符串进行分割,取出性别
String sex = msg.split(",")[1];
System.out.println("性别:"+sex);
}); }
}
Predicate接口
/**
* java.util.function.Predicate<T>接口
* 作用:对某种数据类型的数据进行判断,结果返回一个boolean值
* 接口有一个抽象方法:
* boolean test(T t):用来对指定数据类型数据进行判断
*
*
*/
public class PredicateTest {
//定义方法,参数传递一个字符串,Predicate接口
public static boolean checkString(String s, Predicate<String> pred){
return pred.test(s);
} public static void main(String[] args) {
String s ="ABCD";
System.out.println(checkString(s,(ss)->{
if (ss.length()>5){
return true;
}else {
return false;
}
})
);
}
}
接口中的默认方法,and or negate:
/**
* 判断一个字符串长度大于5 且字符串是否包含a
*/
public class PredicateT {
public static boolean checkString(String s, Predicate<String> p1, Predicate<String> p2){
// return p1.test(s) && p2.test(s);
return p1.and(p2).test(s);//等价于上面
// return p1.or(p2).test(s);//或
// return p1.negate().test(s)//negate非
} public static void main(String[] args) {
String s = "anbced";
boolean re =checkString(s,
(ss)->{
return ss.length()>5;
},
(ss)->{
return ss.contains("a");
});
System.out.println(re);
}
}
练习:
/**
* 将数组里面的名字等于4位的且是女生的用arraylist保存起来
*/
public class PredicateTest2 {
private static void xuanze(String[] arr, Predicate<String> pre1, Predicate<String> pre2){
List<String> stringList =new ArrayList<>();
for (String s : arr) {
if(pre1.and(pre2).test(s)){
stringList.add(s);
}
}
System.out.println(stringList);
} public static void main(String[] args) {
String[] arr = {"1111,N","222,M","44444","N"};
xuanze(arr,
(s)->{
return s.split(",")[0].length()==4;
},
(s)->{
return s.split(",")[1].equals("N");
});
}
}
Function接口
/**
* java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据
* 前者位前置条件,后者位后置条件
* 接口里面的抽象方法: R apply<T t>,根据类型T参数获取类型R参数的结果。
* 了例如:String类型转换位Integer类型
*/
public class FunctionDemo {
public static void exchange(String s, Function<String,Integer> function){
Integer i = function.apply(s);
// int i1 = function.apply(s);自动拆箱,将Integer类型自动拆成Int类型
System.out.println(i);
} public static void main(String[] args) {
String si = "123";
exchange(si,(ss)->{
return Integer.parseInt(ss);
});
//优化
// exchange(si,(ss)-> Integer.parseInt(ss)
// );
}
}
默认方法andThen
/**
* Function接口的默认方法andThen:用来进行组合操作
* 需求:String类型的123 转换为Integer类型,把转换结果加10
* 把增加之后的Integer类型的数据转换为String类型
*
*/
public class FunctionDemo2_andThen { private static void change(String s,Function<String,Integer> f1,Function<Integer,String> f2){
String ss = f1.andThen(f2).apply(s);
System.out.println(ss);
} public static void main(String[] args) {
String s = "123";
change(s,
(s1)->{
//把字符串转整数
return Integer.parseInt(s1)+10;
},
(i)->{
return i+"";
});
}
}
java中的函数式接口的更多相关文章
- 用好JAVA中的函数式接口,轻松从通用代码框架中剥离掉业务定制逻辑
大家好,又见面了. 今天我们一起聊一聊JAVA中的函数式接口.那我们首先要知道啥是函数式接口.它和JAVA中普通的接口有啥区别?其实函数式接口也是一个Interface类,是一种比较特殊的接口类,这个 ...
- Java 中的函数式接口
java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子接口. Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t) ...
- java基础---->java8中的函数式接口
这里面简单的讲一下java8中的函数式接口,Function.Consumer.Predicate和Supplier. 函数式接口例子 一.Function:接受参数,有返回参数 package co ...
- Java中的函数式编程(二)函数式接口Functional Interface
写在前面 前面说过,判断一门语言是否支持函数式编程,一个重要的判断标准就是:它是否将函数看做是"第一等公民(first-class citizens)".函数是"第一等公 ...
- Java 8 特性 —— 函数式接口
函数式接口 概述:接口中只有一个抽象方法. 函数式接口,即适用于函数式编程场景的接口.而 Java 中的函数式编程体现就是 Lambda,所以函数式接口就是可以适用于 Lambda 使用的接口.只有确 ...
- 【Java 8】函数式接口(一)—— Functional Interface简介
什么是函数式接口(Functional Interface) 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法. 这种类型的接 ...
- Java 中的集合接口——List、Set、Map
Java 中的集合接口——List.Set.Map 什么叫集合:集合就是Java API所提供的一系列类的实例,可以用于动态存放多个对象.这跟我们学过的数组差不多,那为什么我们还要学集合,我们看看数组 ...
- 转:二十一、详细解析Java中抽象类和接口的区别
转:二十一.详细解析Java中抽象类和接口的区别 http://blog.csdn.net/liujun13579/article/details/7737670 在Java语言中, abstract ...
- 关于JAVA中抽象类和接口的区别辨析
今天主要整理一下新学习的有关于Java中抽象类和接口的相关知识和个人理解. 1 抽象类 用来描述事物的一般状态和行为,然后在其子类中去实现这些状态和行为.也就是说,抽象类中的方法,需要在子类中进行重写 ...
随机推荐
- [文档]运维故障报告template
RCA的基本概念 根本原因分析技术(root cause analysis,RCA). IOWA州立大学质量管理学院认为,很多公司在设备发生故障后,都能够很快修复, 但难以发现故障的根本原因,所以此故 ...
- ThreadPoolTaskScheduler实现定时任务
public class SchedulingTask { private static ThreadPoolTaskScheduler threadPoolTaskScheduler; static ...
- python3 使用OpenCV计算滑块拼图验证码缺口位置
前言 滑块拼图验证码的失败难度在于每次图片上缺口位置不一样,需识别图片上拼图的缺口位置,使用python的OpenCV库来识别到 环境准备 pip 安装 opencv-python pip insta ...
- 小白文-SpringMVC-解读DispatcherServlet源码
SpringMVC 学习完Spring框架技术之后,差不多会出现两批人: 一批是听得云里雾里,依然不明白这个东西是干嘛的: 还有一批就是差不多理解了核心思想,但是不知道这些东西该如何去发挥它的作用. ...
- Qt:QString
0.说明 区别于QByteArray,QString串是Unicode串,每个元素都是QChar 16-bit UTF-16编码(Unicode) :而QByteArray是8-bit串. 0.1.初 ...
- Qt:打印输出到控制台,类似C++的cout
1. #include<qDebug> 2. qDebug<<"Hello,world!"; 补充,如果不是控制台文件,比如是窗口应用程序,需要在pro文件 ...
- js实现密码输入框对开启键盘大写锁定的提示(IE浏览器下有自动识别提示则不执行(用IE自带效果即可))
代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...
- JZ-029-最小的 K 个数
标题 最小的 K 个数 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 题目链接: 最小的 K 个数 代码 import ja ...
- 【AI】AI学习方向
df
- json web token JWT实现TP5创建和验证
根据博客进行jwt初始化配置 https://blog.csdn.net/weixin_43389208/article/details/117442266?spm=1001.2014.3001.55 ...