第17章-4-函数式编程
概述
- 从Java 8中引入
- 能大大提高编程效率
- 针对集合类,应用广泛
函数式接口
函数式接口要求
- 一个接口有且只有一个抽象方法
- 建议在类上加上@FunctionalInterface注解,但不是必需
定义实例,定义了一个算术运算的函数式接口
package com.bjpowernode.demo;
/**
* 运算类
*/
@FunctionalInterface
public interface IOperation {
/**
* 算术运算
* @param first
* @param second
* @return
*/
Integer operate(Integer first,Integer second);
}
Lambda表达式
针对函数式接口进行应用
是匿名类的一个语法糖,效果一样,但代码更加简洁
通过箭头语法(->)实现,更直观
规则如下
- 语法一:标准版,格式为:(参数列表)->{代码片断}
- 语法二:简版,一般用于只有一行代码的场景,格式为:(参数列表)->简单表达式;另外,如果参数列表只有一个参数,可省略括号
应用实例,多种函数式编程方式
实例1,匿名类方式
实例代码
package com.bjpowernode.demo;
/**
* 算术运算实例,使用IOperation的匿名类方式
*/
public class OperationDemo {
public static void main(String[] args) {
//定义匿名类,进行加法运算
IOperation operation = new IOperation() {
@Override
public Integer operate(Integer first, Integer second) {
return first + second;
}
};
//使用匿名类的加法运算
System.out.println(operation.operate(33,44));
}
}输出结果:77
实例2,Lambda普通方式
实例代码
package com.bjpowernode.demo;
/**
* 算术运算实例,使用IOperation的Lambda方式
*/
public class OperationDemo {
public static void main(String[] args) {
//定义Lambda,进行加法运算
IOperation operation = (Integer first, Integer second) -> {
return first + second;
};
//使用匿名类的加法运算
System.out.println(operation.operate(33, 44));
}
}输出结果:77
实例3,Lambda简写方式
实例代码
package com.bjpowernode.demo;
/**
* 算术运算实例,使用IOperation的Lambda简写方式,将进行类型推断
*/
public class OperationDemo {
public static void main(String[] args) {
//定义Lambda简写方式,进行加法运算,会进行【类型推断】,只接收IOperation.operate定义的形式参数必须为Integer
IOperation operation = (first, second) -> first + second;
//使用匿名类的加法运算
System.out.println(operation.operate(33, 44));
// System.out.println(operation.operate(33.00,44.00)); //错误,类型不匹配
}
}输出结果:77
类型推断,上述的方式3中,形式参数first、second和返回值之所以能不定义数据类型,因因为这Lambda表达式赋值给了IOperation接口引用,此接口有唯一的抽象方法operation,此时的Lambda表达式签名可以直接推断first、second的为Integer类型;此即类型推断
【练习】
- 练习应用实例内容,完成代码编写
- 编写程序,针对Long类型数据进行操作,可以是找最大值、最小值、平均值等,要求如下:
- 定义函数式接口,参数为Long类型的数组,返回值为Long类型数据
- 使用Lambda,利用函数式接口进行操作,分别返回一组测试数据的最大值、最小值、平均值和随机值
Lambda常见使用方式
概述
- 在实际的开发过程中,会有一些常用的方法模式
- 针对这些常见的方法模式,都可以定义函数式接口进行简化使用
有参无返回值-->Consumer<T>
应用实例
应用实例1
函数式接口
package com.bjpoernode.demo;
/**
* 【函数式接口】有参无返回值
*/
@FunctionalInterface
public interface IConsumer<T> {
/**
* 抽象方法
* @param t 参数
*/
void accept(T t);
}函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Consumer;
/**
* 【函数式接口】有参无返回值测试
*/
public class ConsumerTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
IConsumer <Integer> consumer = new IConsumer <Integer>() {
@Override
public void accept(Integer data) {
System.out.println("参数是:" + data);
}
};
consumer.accept(5);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
IConsumer <Integer> lambda = data -> System.out.println("参数是:" + data);
lambda.accept(5);
}
}
无参有返回值-->Supplier<T>
应用实例
应用实例1
函数式接口
package com.bjpoernode.demo;
/**
* 【函数式接口】无参有返回值
*/
@FunctionalInterface
public interface ISupplier<T> {
/**
* 抽象方法
*
* @return 返回值
*/
T get();
}函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 【函数式接口】无参有返回值测试
*/
public class SupplierTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
ISupplier <String> supplier = new ISupplier <String>() {
@Override
public String get() {
return "我是最棒的!";
}
};
String supplierResult = supplier.get();
System.out.println(supplierResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
ISupplier <String> lambda = () -> "我是最棒的!";
String lambdaResult = lambda.get();
System.out.println(lambdaResult);
}
}
有参有返回值-->Function<T,R>
应用实例
应用实例1
函数式接口
package com.bjpoernode.demo;
/**
* 【函数式接口】有参有返回值
*/
@FunctionalInterface
public interface IFunction<T, R> {
/**
* 抽象方法
*
* @param t 参数
* @return 返回值
*/
R apply(T t);
}函数式接口使用
package com.bjpoernode.demo;
/**
* 【函数式接口】有参有返回值测试
*/
public class FunctionTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
IFunction <Long, String> function = new IFunction <Long, String>() {
@Override
public String apply(Long data) {
return data.toString();
}
};
String functionResult = function.apply(1024l);
System.out.println(functionResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
IFunction <Long, String> lambda = data -> data.toString();
String lambdaResult = lambda.apply(1024l);
System.out.println(lambdaResult);
}
}
有参有布尔型返回值-->Predicate<T>
应用实例
应用实例1
函数式接口
package com.bjpoernode.demo;
/**
* 【函数式接口】有参有布尔型返回值
*/
public interface IPredicate<T> {
/**
* 抽象方法
*
* @param t 参数
* @return 返回值
*/
boolean test(T t);
}函数式接口使用
package com.bjpoernode.demo;
/**
* 【函数式接口】有参有布尔型返回值测试
*/
public class PredicateTest {
public static void main(String[] args) {
System.out.println("-------------------匿名类使用方式-------------------");
IPredicate <Integer> predicate = new IPredicate <Integer>() {
@Override
public boolean test(Integer data) {
return data > 1024;
}
};
boolean predicateResult = predicate.test(1025);
System.out.println("是否大于1024?" + predicateResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
IPredicate <Integer> lambda = data -> data >= 1024;
boolean lambdaResult = lambda.test(1025);
System.out.println("是否大于1024?" + lambdaResult);
}
}
【练习】
- 练习应用实例内容,完成代码编写
常用的函数式接口
概述
针对上一节Lambda常见使用方式的几个接口,由于在Java中经常使用,Java类库中已经提供了这些常用的函数式接口
这些函数式接口多位于java.util.function.*包下
具体见下表
名字 接口名 对应的抽象方法 消费型接口 Consumer<T>
void accept(T t);
供给型接口 Supplier<T>
T get();
函数式接口 Function<T, R>
R apply(T t);
判断型接口 Predicate<T>
boolean test(T t);
有参无返回值-->Consumer<T>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Consumer;
/**
* 【函数式接口】有参无返回值测试
*/
public class ConsumerTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Consumer <Integer> consumer = new Consumer <Integer>() {
@Override
public void accept(Integer data) {
System.out.println("参数是:" + data);
}
};
consumer.accept(5);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Consumer <Integer> lambda = data -> System.out.println("参数是:" + data);
lambda.accept(5);
}
}
无参有返回值-->Supplier<T>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Supplier;
/**
* 【函数式接口】无参有返回值测试
*/
public class SupplierTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Supplier <String> supplier = new Supplier <String>() {
@Override
public String get() {
return "我是最棒的!";
}
};
String supplierResult = supplier.get();
System.out.println(supplierResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Supplier <String> lambda = () -> "我是最棒的!";
String lambdaResult = lambda.get();
System.out.println(lambdaResult);
}
}
有参有返回值-->Function<T,R>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Function;
/**
* 【函数式接口】有参有返回值测试
*/
public class FunctionTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Function <Long, String> function = new Function <Long, String>() {
@Override
public String apply(Long data) {
return data.toString();
}
};
String functionResult = function.apply(1024l);
System.out.println(functionResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Function <Long, String> lambda = data -> data.toString();
String lambdaResult = lambda.apply(1024l);
System.out.println(lambdaResult);
}
}
有参有布尔型返回值-->Predicate<T>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Predicate;
/**
* 【函数式接口】有参有布尔型返回值测试
*/
public class PredicateTest {
public static void main(String[] args) {
System.out.println("-------------------匿名类使用方式-------------------");
Predicate <Integer> predicate = new Predicate <Integer>() {
@Override
public boolean test(Integer data) {
return data > 1024;
}
};
boolean predicateResult = predicate.test(1025);
System.out.println("是否大于1024?" + predicateResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Predicate <Integer> lambda = data -> data >= 1024;
boolean lambdaResult = lambda.test(1025);
System.out.println("是否大于1024?" + lambdaResult);
}
}
【练习】
- 练习应用实例内容,完成代码编写
方法引用【扩展】
概述
- 让简版Lambda更简单
- 常见的针对构造方法、普通方法和静态方法,语法规则如下
- 普通方法:对象::普通方法
- 静态方法:类::静态方法
- 构造方法:类::new
- 数组:数组::new
- 具体逻辑是:任意类的方法签名,与函数式接口的方法签名**相同或一致**,就可以将该任意类的方法赋值给函数式接口的引用,并使用该类方法的逻辑;其他事情JVM会处理
针对常用的函数式接口的简化
有参无返回值-->Consumer<T>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Consumer;
/**
* 【函数式接口】有参无返回值测试
*/
public class ConsumerTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Consumer <Integer> consumer = new Consumer <Integer>() {
@Override
public void accept(Integer data) {
System.out.println("参数是:" + data);
}
};
consumer.accept(5);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Consumer <Integer> lambda = data -> System.out.println("参数是:" + data);
lambda.accept(5);
//3、方法引用使用方式
System.out.println("-------------------方法引用使用方式-------------------");
Consumer <Integer> methodReference = ConsumerTest::accept;
methodReference.accept(5);
}
/**
* 有参无返回值方法
*
* @param data
*/
public static void accept(Integer data) {
System.out.println("参数是:" + data);
}
}
无参有返回值-->Supplier<T>
应用实例
应用实例1
函数接口使用
package com.bjpoernode.demo;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 【函数式接口】无参有返回值测试
*/
public class SupplierTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Supplier <String> supplier = new Supplier <String>() {
@Override
public String get() {
return "我是最棒的!";
}
};
String supplierResult = supplier.get();
System.out.println(supplierResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Supplier <String> lambda = () -> "我是最棒的!";
String lambdaResult = lambda.get();
System.out.println(lambdaResult);
//3、方法引用使用方式
System.out.println("-------------------方法引用使用方式-------------------");
Supplier <String> methodReference = SupplierTest::get;
String methodReferenceResult = methodReference.get();
System.out.println(methodReferenceResult);
}
/**
* 无参有返回值方法
*
* @return
*/
public static String get() {
return "我是最棒的!";
}
}
有参有返回值-->Function<T,R>
应用实例
应用实例1
函数函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Function;
/**
* 【函数式接口】有参有返回值测试
*/
public class FunctionTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Function <Long, String> function = new Function <Long, String>() {
@Override
public String apply(Long data) {
return data.toString();
}
};
String functionResult = function.apply(1024l);
System.out.println(functionResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Function <Long, String> lambda = data -> data.toString();
String lambdaResult = lambda.apply(1024l);
System.out.println(lambdaResult);
//3、方法引用使用方式
System.out.println("-------------------方法引用使用方式-------------------");
Function <Long, String> methodReference = FunctionTest::apply;
String methodReferenceResult = methodReference.apply(1024l);
System.out.println(methodReferenceResult);
}
/**
* 有参有返回值
*
* @param data 参数
* @return 返回值
*/
public static String apply(Long data) {
return data.toString();
}
}
有参有布尔型返回值-->Predicate<T>
应用实例
应用实例1
函数式接口使用
package com.bjpoernode.demo;
import java.util.function.Predicate;
/**
* 【函数式接口】有参有布尔型返回值测试
*/
public class PredicateTest {
public static void main(String[] args) {
System.out.println("-------------------匿名类使用方式-------------------");
Predicate <Integer> predicate = new Predicate <Integer>() {
@Override
public boolean test(Integer data) {
return data > 1024;
}
};
boolean predicateResult = predicate.test(1025);
System.out.println("是否大于1024?" + predicateResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Predicate <Integer> lambda = data -> data >= 1024;
boolean lambdaResult = lambda.test(1025);
System.out.println("是否大于1024?" + lambdaResult);
//3、方法引用使用方式
System.out.println("-------------------方法引用使用方式-------------------");
Predicate <Integer> methodReference = PredicateTest::test;
boolean methodReferenceResult = methodReference.test(1025);
System.out.println("是否大于1024?" + methodReferenceResult);
}
/**
* 有参有布尔型返回值测试
*
* @param data 参数
* @return 返回值
*/
public static boolean test(Integer data) {
return data > 1024;
}
}
【练习】
- 练习应用实例内容,完成代码编写
应用实例
应用实例1
目标类
package com.bjpoernode.demo;
/**
* 方法引用目标类
*/
public class Target {
private String name;
/**
* 普通方法(实例方法)
*
* @param data 参数
* @return 返回值
*/
public String normalMethod(Long data) {
String result = "【普通方法】" + data.toString();
return result;
}
/**
* 静态方法
*
* @param data 参数
* @return 返回值
*/
public static String staticMethod(Long data) {
String result = "【静态方法】" + data.toString();
return result;
}
/**
* 无参构造
*/
public Target() {
}
/**
* 有参构造
*
* @param name 参数
*/
public Target(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Target{" + "name='" + name + '\'' + '}';
}
}方法引用使用
package com.bjpoernode.demo;
import java.util.function.Function;
/**
* 【方法引用】使用
*/
public class FunctionTest {
public static void main(String[] args) {
//1、匿名类使用方式
System.out.println("-------------------匿名类使用方式-------------------");
Function <Long, String> function = new Function <Long, String>() {
@Override
public String apply(Long data) {
return data.toString();
}
};
String functionResult = function.apply(1024l);
System.out.println(functionResult);
//2、Lambda使用方式
System.out.println("-------------------Lambda使用方式-------------------");
Function <Long, String> lambda = data -> data.toString();
String lambdaResult = lambda.apply(1024l);
System.out.println(lambdaResult);
//3.1、方法引用使用方式-->【普通方法】
System.out.println("-------------------方法引用使用方式-->【普通方法】-------------------");
Target target = new Target();
//函数式接口引用指向【具有相同签名的普通方法】,就能使用其逻辑
Function <Long, String> methodReference1 = target::normalMethod;
String methodReference1Result = methodReference1.apply(1024l);
System.out.println(methodReference1Result);
//3.2、方法引用使用方式-->【静态方法】
System.out.println("-------------------方法引用使用方式-->【静态方法】-------------------");
//函数式接口引用指向【具有相同签名的静态方法】,就能使用其逻辑
Function <Long, String> methodReference2 = Target::staticMethod;
String methodReference2Result = methodReference2.apply(1024l);
System.out.println(methodReference2Result);
//3.3、方法引用使用方式-->【构造方法】
System.out.println("-------------------方法引用使用方式-->【构造方法】-------------------");
//函数式接口引用指向【具有一致签名的构造方法】,就能使用其逻辑,返回一个通过构造方法创建的对象
Function <String, Target> methodReference3 = Target::new;
Target targetResult = methodReference3.apply("张三");
System.out.println(targetResult);
//3.4、方法引用使用方式-->【数组】
System.out.println("-------------------方法引用使用方式-->【数组】-------------------");
Function <Integer, int[]> methodReference4 = int[]::new;
int[] arrayResults = methodReference4.apply(5);
System.out.println("数组长度为:" + arrayResults.length);
}
}
【练习】
- 练习应用实例内容,完成代码编写