Java 8 函数式编程用法
概览
jdk 8中新增了lambda和接口默认实现方式,简化了编程,让我们可以转换为新的函数式编程,更多关注于业务逻辑.
对于提供的所有function功能在package java.util.function下可以找到,这里列举其中一些常用用法
@FunctionalInterface
编译时期检验了接口只有唯一方法合法性,可以有多个默认实现方法
@FunctionalInterface
interface INumberFunction{
int doubleNum(int num);
default void printNum(int num){
System.out.println("print info:"+num);
}
}
测试代码:
INumberFunction numberFunction= x->x*2;
System.out.println(numberFunction.doubleNum(20));
//---------------output
//40
当接口继承多个接口时,有相同默认实现方法时会编译期指示要求override实现采用哪个接口的默认方法实现
@FunctionalInterface
interface INumberFunction2{
int doubleNum(int num);
default void printNum(int num){
System.out.println("print info2:"+num);
}
}
@FunctionalInterface
interface INumberFunction3 extends INumberFunction,INumberFunction2{
//必须要覆写继承的多个接口中相同的默认实现方法
@Override
default void printNum(int num) {
INumberFunction2.super.printNum(num);
}
}
Predicate
断言,输入为T类型的数据,输出boolean
T->boolean(true/false)
Predicate<String> predicate=x->x.startsWith("Class");
System.out.println(predicate.test("Abcd"));
//----------------output
//false
对基本数据类型的包装了IntPredicate
BiPredicate<T,U>
二元断言,输入T类型和U类型的数据,返回boolean
(T, U) -> boolean(true/false)
BiPredicate<String,Double> biPredicate=(x,y)->x.startsWith("Alisa")&&y.intValue()>=8000;
System.out.println("Alisa salary is over average:"+biPredicate.test("Alisa",8100.02));
//----------------output
//Alisa salary is over average:true
Function<T,S>
T 代表输入类型,S代表函数执行完返回结果类型
T->S
case 1:
Function<Integer,String> formatFunc=x->new DecimalFormat("#,###").format(x);
System.out.println("format result:"+formatFunc.apply(10000));
//----------------output
//format result:10,000
case 2:
函数链式编程
Function<Integer,Integer> func = x->x*2;
System.out.println(func.andThen(x->"result:"+x).apply(20));
//--------------output
//result:40
case 3:
多个链式时,从左到右顺序执行
Function<String,Integer> func = x->Integer.valueOf(x);
System.out.println(func.andThen(/*y is Integer*/y->Double.valueOf(y)).apply("1000"));
//-----------------output
//1000.0
System.out.println(func.andThen(y->y+200).andThen(z->Double.valueOf(z)).apply("1000"));
//---------------------output
//1200.0
System.out.println(func.andThen(/*y is Integer*/y->Long.valueOf(y+100+"")/*return Long to next andThen or as final result*/)
.andThen(/*z is Long*/z->Double.valueOf(z)/*return Double to next andThen or as final result*/).apply("1000"));
//---------------------output
//1100.0
对于有参构造函数时,Function接口也适用
Function<String,String> strFunc=String::new;
System.out.println("construct str:"+strFunc.apply("Message"));
//---------------------output
//Message
对于输入数据为一些基本类型的情况,有封装了对应的Function如IntFunction,DoubleFunction…
对于输入和输出的数据都为一些基本类型的情况,封装了有DoubleToIntFunction,IntToLongFunction…
BiFunction<T, U, R>
二元功能函数,输入T类型和U类型的实例,返回R类型的实例
(T, U) -> R
BiFunction<Integer,Double,String> biFunction=(x,y)->"string value:"+x.intValue()+y.intValue();
System.out.println(biFunction.apply(100,200.01));
//-----------------output
//string value:100200
对返回结果为一些基本类型的封装了更简洁的BiFunction,如ToDoubleBiFunction<T,U> 返回double类型的结果,ToLongBiFunction
如果入参和返回结果的类型都与方法引用匹配时,可以直接用方法引用,参考Consumer.
Consumer
输入T类型的实例,没有返回,只是消费输入
case 1:
Consumer<String> consumer = x -> System.out.println("if contains AI:" + x.contains("AI"));
consumer.accept("AI message");
//---------------------output
//if contains AI:true
如果输入与调用的方法参数类型一致,可以直接用方法引用,如下
case 2:
简单方法引用
Consumer<String> consumer1 = System.out::println;
consumer1.accept("New message");
//---------------------output
//New message
case 3:
静态方法引用
public class FunctionMain {
public static void main(String[] args) {
Consumer<Double> consumer2= FunctionMain::floorDouble;
consumer2.accept(234.5);
}
public static void floorDouble(Double num){
double floor = Math.floor(num);
System.out.println("floor double:"+floor);
}
}
//---------------------output
//floor double:234.0
case 4:
非静态方法引用
public class FunctionMain {
public static void main(String[] args) {
FunctionMain functionMain=new FunctionMain();
Consumer<Date> dateConsumer=functionMain::formatDate;
dateConsumer.accept(new Date());
//另外一种情况,采用方法隐式this对象的性质一样可以使用类方法调用,但调用时需要传入实例对象
BiConsumer<FunctionMain,Date> dateBiConsumer =FunctionMain::formatDate;
dateBiConsumer.accept(functionMain,new Date());
}
//private void formatDate(FunctionMain this,Date date){
// String newDate = new SimpleDateFormat("yyyy.MM.dd").format(date);
// System.out.println("formatDate: "+newDate);
//}
private void formatDate(/*隐藏了this参数,与上述方法等价*/Date date){
String newDate = new SimpleDateFormat("yyyy.MM.dd").format(date);
System.out.println("formatDate: "+newDate);
}
}
//---------------------output
//formatDate: 2020.08.15
BiConsumer<T,U>
二元消费函数,输入T类型和U类型的实例,无输出
BiConsumer<String,Double> biConsumer=(x, y)-> System.out.println("weight result:"+Integer.valueOf(x)*3+y.intValue()*7);
biConsumer.accept("20",12.32);
//---------------------output
//weight result:6084
Supplier
没有输入,返回T类型的实例
Supplier<List<String>> supplier= ArrayList::new; //or Arrays::asList
System.out.println(supplier.get());
//---------------------output
//[]
基本类型封装了一些对应的Supplier,比如IntSupplier, LongSupplier, DoubleSupplier, BooleanSupplier
UnaryOperator
一元函数,输入为T类型的实例,输出也为T类型的实例
T->T
UnaryOperator<String> ua=x->x.concat(" end");
System.out.println(ua.apply("hello"));
//-------------------------output
//hello end
封装了基本类型的一元函数,IntUnaryOperator, DoubleUnaryOperator…
BinaryOperator
二元函数,输入类型为T的两个参数,输出类型为T的结果
(T, T)-> T
BinaryOperator<Boolean> bo=(x, y)->x&&y;
System.out.println(bo.apply(true,false));
//--------------------output
//false
IntBinaryOperator ibo = (x,y)->x*5+y*10;
System.out.println(ibo.applyAsInt(2,3));
//--------------------output
//40
*参数,输出类型为T的结果
(T, T)-> T
BinaryOperator<Boolean> bo=(x, y)->x&&y;
System.out.println(bo.apply(true,false));
//--------------------output
//false
IntBinaryOperator ibo = (x,y)->x*5+y*10;
System.out.println(ibo.applyAsInt(2,3));
//--------------------output
//40
对一些基本类型封装了对应的BinaryOperator, 如IntBinaryOperator, LongUnaryOperator