是什么??

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

场景:

适用于函数式编程场景(使用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. Java诊断神器:Arthas常用功能

    最新原文:https://www.cnblogs.com/uncleyong/p/14944401.html Arthas是Alibaba开源的Java诊断工具,功能很强大,它是通过Agent方式来连 ...

  2. HTTP攻击与防护-函数注入攻击

    实验目的 1.了解eval注入的概念 2.了解eval注入攻击的方式 3.掌握防范攻击的方法 实验原理 1.了解eval注入的概念 2.了解eval注入攻击的方式 3.掌握防范攻击的方法 实验内容 1 ...

  3. RENIX报文字段跳变——网络测试仪实操

    什么是报文字段跳变? 报文字段跳变是指字段的值进行一些列有规则的变化,Renix支持对字段进行递增.递减.列表和随机变化. 如当用户想要仿真大量的源IP变化的数据时,就可以使用Modifier进行规则 ...

  4. FPGA+x86构建高性能国产网络测试仪竞技之道

    众所周知,以太网已经深入我们的生活无处不在,企业.校园.大数据中心和家庭等都离不开网络,否则我们的生活将受到严重的影响. 以太网的接口速率也是迅速发展:10M.100M.GE.10GE.40GE.10 ...

  5. 思迈特软件Smartbi:机器学习高深难懂?本文深入浅出给你讲明白!

    人工智能(Artificial Intelligence,缩写为AI)是对人的意识.思维过程进行模拟的一门新学科.如今,人工智能从虚无缥缈的科学幻想变成了现实.计算机科学家们在人工智能的技术核心--机 ...

  6. 【C# 异常处理】StackTrace 堆栈跟踪

    作用 在使用.NET编写的代码在debug时很容易进行排查和定位问题,一旦项目上线并出现问题的话那么只能依靠系统日志来进行问题排查和定位,但当项目复杂时,即各种方法间相互调用将导致要获取具体的出错方法 ...

  7. WPF中TabControl控件和ListBox控件的简单应用(MVVM)

    本文主要实现下图所示的应用场景: 对于Class1页,会显示用户的age和address属性,对于Class2页,会显示用户的age,address和sex属性.在左边的ListBox中选择对应的用户 ...

  8. java变量的初始化之后的默认值

    对于类的成员变量 不管程序有没有显示的初始化,Java  虚拟机都会先自动给它初始化为默认值. 1.整数类型(byte.short.int.long)的基本类型变量的默认值为0. 2.单精度浮点型(f ...

  9. js根据ClassName来删除元素(有坑误入)

    今天,被一个很简单的问题坑了一下午,基础不扎实.(js根据class名称来删除Dom元素) 但是结果却不是这样的.弄了好久还不知道怎么回事.最后找到了答案. 结果如下:为啥还有test2,4,6呢. ...

  10. Docker入坑系列(二)

    Docker入坑系列(二) 上一篇我们为Docker创造了一个良好的生活环境,这一篇我们就开始让Docker活起来. 安装Docker ok,原文地址在这里. 当然,我只是自己翻译了一下而已- -跟着 ...