是什么??

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

场景:

适用于函数式编程场景(使用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中的函数式接口的更多相关文章

  1. 用好JAVA中的函数式接口,轻松从通用代码框架中剥离掉业务定制逻辑

    大家好,又见面了. 今天我们一起聊一聊JAVA中的函数式接口.那我们首先要知道啥是函数式接口.它和JAVA中普通的接口有啥区别?其实函数式接口也是一个Interface类,是一种比较特殊的接口类,这个 ...

  2. Java 中的函数式接口

    java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子接口. Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t) ...

  3. java基础---->java8中的函数式接口

    这里面简单的讲一下java8中的函数式接口,Function.Consumer.Predicate和Supplier. 函数式接口例子 一.Function:接受参数,有返回参数 package co ...

  4. Java中的函数式编程(二)函数式接口Functional Interface

    写在前面 前面说过,判断一门语言是否支持函数式编程,一个重要的判断标准就是:它是否将函数看做是"第一等公民(first-class citizens)".函数是"第一等公 ...

  5. Java 8 特性 —— 函数式接口

    函数式接口 概述:接口中只有一个抽象方法. 函数式接口,即适用于函数式编程场景的接口.而 Java 中的函数式编程体现就是 Lambda,所以函数式接口就是可以适用于 Lambda 使用的接口.只有确 ...

  6. 【Java 8】函数式接口(一)—— Functional Interface简介

    什么是函数式接口(Functional Interface) 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法. 这种类型的接 ...

  7. Java 中的集合接口——List、Set、Map

    Java 中的集合接口——List.Set.Map 什么叫集合:集合就是Java API所提供的一系列类的实例,可以用于动态存放多个对象.这跟我们学过的数组差不多,那为什么我们还要学集合,我们看看数组 ...

  8. 转:二十一、详细解析Java中抽象类和接口的区别

    转:二十一.详细解析Java中抽象类和接口的区别 http://blog.csdn.net/liujun13579/article/details/7737670 在Java语言中, abstract ...

  9. 关于JAVA中抽象类和接口的区别辨析

    今天主要整理一下新学习的有关于Java中抽象类和接口的相关知识和个人理解. 1 抽象类 用来描述事物的一般状态和行为,然后在其子类中去实现这些状态和行为.也就是说,抽象类中的方法,需要在子类中进行重写 ...

随机推荐

  1. 数据分析需要学什么?BI工具有速成?

    ​我们都知道,成为一个数据分析师的必经之路,必须要会使用SQL和R语言.假如你想学会数据分析的话,先别着急着学编程技术,先学好excel,把excel真正学会了,操作熟练了,会做常用函数公式,数据透视 ...

  2. strtok()出现segment fault的错误

    在写一个简易的 shell 时,需要将命令行的命令通过空格分割成一个个字符串参数,这里我使用了 strtok() 函数,然后遇到了 segment fault 的错误. 出现问题的代码如下: 终于寻找 ...

  3. 【windows 操作系统】进程控制块(PCB)

    转载地址:https://blog.csdn.net/qq_38499859/article/details/80057427一.目录文章目录    操作系统3 ----进程控制块(PCB)详解    ...

  4. MySQL [ERROR] [MY-013183]

    [ERROR] [MY-013183] [InnoDB] Assertion failure,回顾记录一次因数据库(MySql 8.0)操作不当导致的生产事故顺便记录下正常重启发生的意外和解决方法(关 ...

  5. VirtualBox--修改虚拟硬盘大小

    学习:Oracle VM VirtualBox做好虚拟硬盘后,如何进一步修改虚拟硬盘的大小 修改为50G,修改后在虚拟机中查看:Machine→Settings→Storage VBoxManage ...

  6. Linux swap分区操作

    swap交换分区是系统RAM的补充,swap 分区支持虚拟内存.当没有足够的 RAM 保存系统处理的数据时,会将数据写入 swap 分区,当系统缺乏 swap 空间时,内核会因 RAM 内存耗尽而终止 ...

  7. Vue3中setup语法糖学习

    目录 1,前言 2,基本语法 2,响应式 3,组件使用 3.1,动态组件 3.2,递归组件 4,自定义指令 5,props 5.1,TypeScript支持 6,emit 6.1,TypeScript ...

  8. laravel7 h-ui模板点改

    1:html页面 <td> @if($item->fang_status == 0) <span onclick="changeFangStatus(this,{{$ ...

  9. CentOS 8 关闭 Firewalld 及 SELinux

    检查 SELinux 是否开启 执行 sestatus 指令可以检视目前 SELinux 的状态, 其中一项是是否有开启, 执行以下指令: # sestatus | grep status 如果看到 ...

  10. web自动化之selenium(二)

    selenium自动化测试框架 一.什么是自动化测试 利用软件(或者说机器代替人)实现全部或者部分测试任务的过程 二.为什么要进行自动化测试 ​ 自动化测试可以完成许多手工测试无法实现或难以实现的功能 ...