文章目录
JDK8新特性笔记(四):函数式编程
- Java8 内置的四大核心函数式接口
Consumer : 消费型接口:有入参,无返回值
void accept(T t); - Supplier : 供给型接口:无入参,有返回值
T get(); - Function<T, R> : 函数型接口:有入参,有返回值
R apply(T t); - Predicate : 断言型接口:有入参,有返回值,返回值类型确定是boolean
boolean test(T t);
1.Function接口的使用
先写一个function接口的实现类,重写apply方法
public class FunctionObj implements Function {
@Override
public Object apply(Object o) {
return o+"经过apply()处理拼接上了";
}
}
再写一个调用这个实现方法的类
public static void test(String input,FunctionObj func){
// 加了一个转大写的功能
String upperCase = input.toUpperCase();
System.out.println(func.apply(upperCase));
}
使用:
public static void main(String[] args) {
// 直接调用自己写的实现方法
test("aBc",new FunctionObj());
// lambda方式重写apply方法,再调用
Function<Integer,Integer> func = p->p*100;
System.out.println(func.apply(3));
}
运行结果:
ABC经过apply()处理拼接上了
300
2.BiFunction :Function只能接受一个参数,如果要传递两个参数,则用BiFunction
截取部分BiFunction源码及注释,传入两个参数返回一个结果,使用接口去自定义功能实现
/**
* Represents a function that accepts two arguments and produces a result.
* This is the two-arity specialization of {@link Function}.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object, Object)}.
*
* @param <T> the type of the first argument to the function
* @param <U> the type of the second argument to the function
* @param <R> the type of the result of the function
*
* @see Function
* @since 1.8
*/
@FunctionalInterface
public interface BiFunction<T, U, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
使用例子:
public static void main(String[] args) {
System.out.println(CaculateFunction(6,3,(a,b)->a+b));
System.out.println(CaculateFunction(6,3,(a,b)->a-b));
System.out.println(CaculateFunction(6,3,(a,b)->a*b));
System.out.println(CaculateFunction(6,3,(a,b)->a/b));
}
// 实现类 应用入口
public static Integer CaculateFunction(Integer numA, Integer numB, BiFunction<Integer,Integer,Integer> biFunction ){
return biFunction.apply(numA,numB);
}
运行结果:
9
3
18
2
3.Consumer:消费型接口 ;有入参 无返回值
截取部分Consumer源码及注释
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
用途: 因为没有返回值,常用于打印、发送短信、遍历等消费动作
使用例子:
public static void main(String[] args) {
sendMsg("发送信息测试",obj->{
System.out.println(obj);
System.out.println("消息发送完成");
});
}
public static void sendMsg (String msg, Consumer<String> consumer){
consumer.accept(msg);
}
运行结果:
发送信息测试
消息发送完成
遍历例子:
List<String> stringList = Arrays.asList("aaa", "bbb", "ccc");
stringList.forEach(obj->{
System.out.println(obj);
});
运行结果:
aaa
bbb
ccc
4.Supplier :供给型接口 ; 无入参,有返回值
源码及注释
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
用途:泛型一定跟方法的返回值类型是一种类型,如果需要获得一个数据,并且不需要传入参数,可以使用Supplier接口,例如 无参的工厂方法,即工厂设计模式创建对象,简单来说就是 提供者
写一个新建默认对象的例子:
public class SupplierDemo01 {
public static void main(String[] args) {
// 调用创建默认对象的方法去创建对象
Person person = newPerson();
System.out.println(person.getName());
}
/**
* 创建一个创建默认对象的方法
* @return
*/
public static Person newPerson(){
Supplier<Person> personSupplier = ()->{
Person person = new Person();
person.setName("god");
person.setAge(99999);
return person;
};
return personSupplier.get();
}
}
/**
* 创建一个Person类
*/
class Person {
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
5.Predicate : 断言型接口:有入参,有返回值,返回值类型确定是boolean
部分源码及注释
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
用途: 接收一个参数,用于判断是否满足一定的条件,过滤数据
**例子:**做一个过滤字符串数组中所有非a开头的字符串,只留下以a开头的字符串放到数组中返回
public class PredicateDemo01 {
public static void main(String[] args) {
List<String> strings = Arrays.asList("abc", "bcd", "cde", "def", "ace");
System.out.println(strings);
// 第二个参数把过滤策略传入
List<String> results = startWithAFilter(strings, obj -> obj.startsWith("a"));
System.out.println(results);
}
/**
* 做一个过滤器
* @param list
* @param predicate
* @return
*/
public static List<String> startWithAFilter (List<String> list , Predicate<String> predicate){
ArrayList<String> result = new ArrayList<>();
for (String str : list){
if (predicate.test(str)) {
result.add(str);
}
}
return result;
}
}
6.方法引用与构造函数的引用
以前方法调用 对象.方法名 或者 类名.方法名
jdk8提供了一个 :: 双冒号
说明:方法引用是一种更更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已经存在的方法或构造方法
通过方法引用,可以将方法的引用赋值给一个变量
语法:左边是容器(可以是类名,实例名),中间是" :: ",右边是相应的方法名
静态方法,则是ClassName::methodName。如 Object ::equals
实例例方法,则是Instance::methodName
构造函数,则是 类名::new;
public class ConstructDemo01 {
public static void main(String[] args) {
// 用双冒号来构造 静态函数引用 字符串转integer
Function<String,Integer> fun = Integer::parseInt;
Integer value = fun.apply("2048");
System.out.println(value);
// 用双冒号来构造 非静态函数引用 字符串剪切
String str1 = "123测试字符串";
Function<Integer,String> fun2 = str1::substring;
String result1 = fun2.apply(2);
System.out.println(result1);
// 构造函数引用多个参数 这个每次调用apply就相当于new了一个User对象,如果要做一个User的list方便创建插入
BiFunction<String,Integer,User> biFunction1 = User::new;
User user1 = biFunction1.apply("kakaka1", 15);
System.out.println(user1);
// 构造函数引用单个参数
Function<String,User> addFunction = User::new;
User user2 = addFunction.apply("zouzouzou");
System.out.println(user2);
// 函数引用也是一种函数式接口,可以将函数引用作为方法的参数
sayHello("大家好,我是sayHello",String::toUpperCase);
}
private static void sayHello(String param , Function<String,String> function){
String result = function.apply(param);
System.out.println(result);
}
}
class User{
private String name;
private Integer age;
public User() {
}
public User(String name) {
this.name = name;
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}