Lambda学习总结(一)--函数式接口
Lambda 表达式是
JDK1.8 里面的一个重要更新,这意味着 Java 也开始承认了函数式编程,并且尝试引入其中,我们今天就来了解下它的使用。
一、函数式接口
1.1 概念
函数式接口在 Java 中是指:有且仅有一个抽象方法的接口。
1.2 格式
修饰符 interface 接口名称 {
返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}
例如:
public interface MyFunctionalInterface {
void myMethod();
}
1.3 @FunctionalInterface 注解
与 @Override 注解的作用类似,为了保证接口 有且仅有一个抽象方法,Java 8 中专门为其引入了一个新的注解: @FunctionalInterface。
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
注意:即使不使用该注解,只要满足函数式接口的定义也认为该接口是一个函数式接口不影响其使用。
1.4 自定义函数式接口的使用
自定义函数式接口的典型使用场景就是作为方法的参数,例如:
public class DemoFunctionalInterface {
// 使用自定义的函数式接口作为方法参数
private static void print(MyFunctionalInterface inter) {
// 使用自定义的函数式接口方法
inter.myMethod();
}
public static void main(String[] args) {
// 调用方法
print(() -> System.out.println("执行 Lambda 函数方法"));
}
}
二、函数式编程
2.1 Lambda 延迟执行
在讲 Lambda 延迟执行 之前,我们先来看一个日志打印的案例:
public class DemoLogger {
private static void log(int lever,String msg) {
if(lever == 1){
System.out.println(msg);
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(1,msgA + msgB + msgC);
}
}
上面的案例存在一个问题,无论日志级别是否满足要求,作为 log 方法的第二个参数,三个字符串一定会先被拼接然后传入方法内。如果级别不满足条件的话,字符串的拼接操作就白做了,存在着性能上的浪费。而 Lambda 表达式是延迟执行的,正好可以作为解决方案,用以提升性能。
@FunctionalInterface
public interface MessageBuilder {
String builderMessage();
}
public class DemoLogger {
private static void log(int lever,MessageBuilder builder) {
if(lever == 1){
System.out.println(builder.builderMessage());
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(1,() -> {
System.out.println("级别为1时执行");
return msgA+msgB+msgC;
});
log(2,() -> {
System.out.println("级别不为1时执行");
return msgA+msgB+msgC;
});
}
}
运行程序,我们来看下控制台的输出结果:
级别为1时执行
HelloWorldJava
从输出结果上可以看出,如果不符合日志级别要求的话,Lambda 将不会被执行,进而达到节省性能的效果。
2.2 使用 Lambda 作为参数
向上面的日志打印案例实际上就是将 Lambda 当作一个参数来使用,只要方法的参数是一个函数式接口类型,那么就可以使用 Lambda 表达式进行替代。例如 Runnable 接口就是一个函数式接口:
public class DemoParameter {
private static void startRunnable(Runnable task) {
new Thread(task).start();
}
public static void main(String[] args) {
startRunnable(() -> System.out.println("线程执行中"));
}
}
2.3使用 Lambda 作为返回值
同理,如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个 Lambda 表达式:
public class DemoResult {
private static Comparator<Integer> newComparator() {
return (a, b) -> b - a;
}
public static void main(String[] args) {
Integer[] array = new Integer[]{0, -5, 33, 100, 88, -40};
// 排序前
System.out.println(Arrays.toString(array));
Arrays.sort(array,newComparator());
// 排序后
System.out.println(Arrays.toString(array));
}
}
三、Lambda 四大核心函数式接口
除了我们自己定义函数式接口外,JDK 也提供了大量的常用函数式接口用以丰富 Lambda 的使用场景,它们主要在 java.util.function 包中被提供。
3.1 Supplier 接口
java.util.function.Supplier<T> 接口仅包含一个无参方法: T get()。用来获取一个泛型参数指定类型的对象数据。
public class DemoSupplier {
private static String getString(Supplier<String> supplier) {
return supplier.get();
}
public static void main(String[] args) {
String msgA = "Hello ";
String msgB = "World ";
System.out.println(getString(() -> msgA + msgB));
}
}
3.2 Consumer 接口
java.util.function.Consumer<T> 接口与 Supplier 接口正好相反,它不是用于生产一个数据,而是消费一个数据,它的数据类型由泛型决定。
Consumer 接口有两个方法:
| 方法名称 | 方法类型 | 方法含义 |
|---|---|---|
| accept | 抽象方法 | 用于消费一个数据 |
| andThen | 默认方法 | 组合消费一个数据 |
3.2.1 accept 方法
public class DemoConsumer {
private static void consumerString(Consumer<String> one){
one.accept("Hello");
}
public static void main(String[] args) {
consumerString((s)->System.out.println(s));
}
}
3.2.2 andThen 方法
public class DemoConsumer {
private static void consumerString(Consumer<String> one,Consumer<String> two){
one.andThen(two).accept("Hello");
}
public static void main(String[] args) {
consumerString(
(s)->System.out.println(s.toUpperCase()),
(s)->System.out.println(s.toLowerCase())
);
}
}
3.3 Predicate 接口
当我们需要对某种类型的数据进行判断,从而得到一个布尔值类型的结果的时候,可以使用java.util.function.Predicate 接口。
Predicate 接口有如下方法:
| 方法名称 | 方法类型 | 方法含义 |
|---|---|---|
| test | 抽象方法 | 用于条件判断 |
| and | 默认方法 | 组合条件判断,表示 与 关系 |
| or | 默认方法 | 组合条件判断,表示 或 关系 |
| negate | 默认方法 | 组合条件判断,表示 非 关系 |
3.3.1 test 方法
条件判断的条件是根据传入的 Lambda 表达式逻辑 ,下面的示例的判断逻辑是传入的值是否大于0。
public class DemoTest {
private static void method(Predicate<Integer> predicate) {
boolean result = predicate.test(5);
System.out.println(result);
}
public static void main(String[] args) {
method((s) -> s > 0);
}
}
3.3.2 and 方法
如果要判断字符串既包含字母 a 又要包含字母 e,那么可以使用 and 方法:
public class DemoAnd {
private static void method(Predicate<String> one,Predicate<String> two) {
boolean result = one.and(two).test("abcd");
System.out.println(result);
}
public static void main(String[] args) {
method((s) -> s.contains("a"),(s) -> s.contains("e"));
}
}
3.3.3 or 方法
如果只需要满足一个条件即可,那就可以使用 or 方法:
public class DemoOr {
private static void method(Predicate<String> one,Predicate<String> two) {
boolean result = one.or(two).test("abcd");
System.out.println(result);
}
public static void main(String[] args) {
method((s) -> s.contains("a"),(s) -> s.contains("e"));
}
}
3.3.4 negate 方法
剩下的就只有取反的逻辑了,判断值不能大于0:
public class DemoNegate {
private static void method(Predicate<Integer> predicate) {
boolean result = predicate.negate().test(5);
System.out.println(result);
}
public static void main(String[] args) {
method((s) -> s > 0);
}
}
3.4 Function 接口
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
| 方法名称 | 方法类型 | 方法含义 |
|---|---|---|
| apply(T t) | 抽象方法 | 根据类型 T 参数获取类型 R 的结果 |
| andThen | 默认方法 | 用来进行组合操作 |
3.4.1 apply 方法
使用场景如:将 String 类型转换为 Integer 类型:
public class DemoFunctionApply {
private static void method(Function<String,Integer> function){
Integer apply = function.apply("10");
System.out.println(apply + 0);
}
public static void main(String[] args) {
method(s -> Integer.parseInt(s));
}
}
3.4.2 andThen 方法
public class DemoFunctionAndThen {
private static void method(Function<String,Integer> one,
Function<Integer,Integer> two){
Integer apply = one.andThen(two).apply("10");
System.out.println(apply + 0);
}
public static void main(String[] args) {
method(s -> Integer.parseInt(s),i -> i *= 10);
}
}
Lambda学习总结(一)--函数式接口的更多相关文章
- java8学习之Lambda表达式初步与函数式接口
对于Java8其实相比之前的的版本增加的内容是相当多的,其中有相当一大块的内容是关于Lambda表达式与Stream API,而这两部分是紧密结合而不能将其拆开来对待的,但是是可以单独使用的,所以从学 ...
- java8学习之深入函数式接口与方法引用
函数式接口: 函数式接口[FunctionalInterface]是整个Lambda表达式的一个根源,换句话来说java8中的Lambda表达式要想彻底掌握,前提是要彻底理解好函数式接口,所以这次继续 ...
- (四)jdk8学习心得之函数式接口
四.函数式接口 1. 格式 注:抽象方法就是通过lambda表达式或者方法引用实现. 2. Jdk提供的函数式接口(这里提供五个最为常用的) 3. 技巧 通过函数式接口,就可以把一个函数作为一个参数进 ...
- Java8(1)之Lambda表达式初步与函数式接口
Lambda表达式初步 介绍 什么是Lambda表达式? 在如 Lisp.Python.Ruby 编程语言中,Lambda 是一个用于表示匿名函数或闭包的运算符 为何需要lambda表达式? 在 Ja ...
- java8学习之BiFunction函数式接口实例演示&Predicate函数式接口详解
BiFunction函数式接口: 在上次中已经对BiFunction接口进行了初步的认识,这里对它进一步学习,这里打算新建一个Person实体,然后新建若干个Person的实例存放在集合中,最后再根据 ...
- java 基本语法(十六)Lambda (三)函数式接口
方法引用1.理解:方法引用可以看做是Lambda表达式深层次的表达.换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法. 2.使用情境:当要传递给Lam ...
- java 基本语法(十五)Lambda (二)函数式接口
1.函数式接口的使用说明> 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口.> 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是 ...
- 黑马Lambda表达式学习 Stream流 函数式接口 Lambda表达式 方法引用
- 黑马方法引用学习 Stream流 函数式接口 Lambda表达式 方法引用
随机推荐
- pandas分组运算(groupby)
1. groupby() import pandas as pd df = pd.DataFrame([[1, 1, 2], [1, 2, 3], [2, 3, 4]], columns=[" ...
- 汇编语言——用DOSBox的debug查看CPU和内存 & 用机器指令和汇编指令编程
实验一 查看CPU和内存,用机器指令和汇编指令编程 实验目的 了解什么是Debug,以及Debug中需要用的一些功能 R:查看.改变CPU寄存器的内容 D:查看内存中的内容 E:改写内存中的内容 ...
- python--006
一.函数的作用域 1.作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变 例一: name='alex' def foo(): name='lhf' def bar(): print(na ...
- 如何理解springcloud微服务项目中,eureka,provider,consumer它们之间的关系?
eureka负责注册provider和consumer的服务信息 provider负责与数据库进行交互,实现数据持久化,并给consumer提供服务 consumer与前端交互,通过与Eureka同源 ...
- 贪心+dp
贪心+dp 好多题都是这个思想, 可以说是非常重要了 思想一: 在不确定序列无法dp的情况下, 我们不妨先假设序列已经选定, 而利用贪心使序列达到最优解, 从而先进行贪心排序, 在进行dp选出序列 思 ...
- 《Python编程从0到1》笔记3——欧几里得算法
本节以欧几里得算法(这是人类历史上最早记载的算法)为示例,向读者展示注释.文档字符串(docstring).变量.循环.递归.缩进以及函数定义等Python语法要素. 欧几里得算法:“在数学中, ...
- 【VS开发】使用 NuGet 管理项目库
NuGet 使用 NuGet 管理项目库 Phil Haack 无论多么努力,Microsoft 也没办法提供开发人员所需要的每一个库. 虽然 Microsoft 在全球的员工人数接近 90,000, ...
- java中抽象类、接口及区别
转自:http://www.cnblogs.com/dolphin0520/p/3811437.html 一.抽象类 在了解抽象类之前,先来了解一下抽象方法.抽象方法是一种特殊的方法:它只有声明,而没 ...
- 【7.9校内test】T1挖地雷
(土气的名字万里挑一丫丫) 然后这个题是个递推,lz的考场想法: 3个的最好确定,先把3个的确定下来,然后从这个点往前推,从这个点往后推这么算吧qwq 然后码长:也是很nice,最关键的是,我都写的这 ...
- qt使用QWT注意事项
当继承某个QWT类时,有是使用O_OBJECT弘会出现问题 切记在工程文件里别忘了添加这一句 DEFINES+=QWT_DLL