Java8之函数式编程

2022-08-21 11:26:19

Java8之函数式编程

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

1.Lambda表达式

如下案例所示,分别创建三个接口,每个接口中只有一个方法,通过lambda表达式重写接口中的方法,可极大的简化代码。当只有一个入参时,则无需写() 当表达式只有一行时则无需写{}return

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunc1{/**
	 * 相当于接口实现类
	 * 当接口只有一个方法时可用Lambda表达式简写接口实现
	 */staticAa aa=()->System.out.println("打印Aa");staticAb ab=()->"返回Ab";staticAc ac= name-> name+":说话";staticAc ac2= name->{System.out.println("入参:"+ name);return name+": 我是Ac";};publicstaticvoidmain(String[] args){

		aa.testAa();System.out.println(ab.testAb());System.out.println(ac.testAc("kenewstar"));System.out.println(ac2.testAc("k2"));}}interfaceAa{voidtestAa();}interfaceAb{StringtestAb();}interfaceAc{StringtestAc(String name);}

执行结果:

打印Aa
返回Ab
kenewstar:说话
入参:k2
k2: 我是Ac

任何 Lambda 表达式的基本语法是:

  1. 参数。 2. 接着-> ,可视为“产出”。 3. -> 之后的内容都是方法体。

2.方法引用

除了可以使用Lambda表达式重写接口方法外,还可使用方法引用的方式重写接口方法,使用前提也必须是该接口是一个函数式接口,即接口中只有一个方法(抽象方法),因为Java8允许接口中有静态方法和默认方法。

如下案例使用Lambda表达式与方法引用重写同一个方法。

/**
 * 方法引用
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunc2{staticStringreturnStr(){return"call2";}staticvoidprintRunnable(){System.out.println("打印Runnable2");}publicstaticvoidmain(String[] args)throwsException{// Callable函数式接口,// Lambda表达式 无入参,有返参Callable<String> c=()->"call";System.out.println(c.call());// 方法引用重写接口// 调用了一个只有返回值的方法Callable<String> c2=TestFunc2::returnStr;System.out.println(c2.call());// Runnable函数式接口Runnable r=()->System.out.println("打印Runnable");
	  r.run();// 方法引用重写接口// 调用了一个无入参,无返参的方法Runnable r2=TestFunc2::printRunnable;
	  r2.run();}}

执行结果:

call
call2
打印Runnable
打印Runnable2

注意 : 方法引用中重写的方法必须与函数式接口的方法类型格式保持一致,入参返参的顺序及类型都必须一致,才可使用该方法引用。

Runnable接口的一个简化示例

匿名内部类 -> lambda表达式 -> 方法引用

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunc3{staticvoidrun(){System.out.println("方法引用");}publicstaticvoidmain(String[] args){// 使用匿名内部类的方式重写接口newThread(newRunnable(){@Overridepublicvoidrun(){System.out.println("匿名内部类");}}).start();// 使用Lambda方式重写接口newThread(()->System.out.println("Lambda表达式")).start();// 使用方法引用的方式newThread(TestFunc3::run).start();}}

执行结果:

匿名内部类
Lambda表达式
方法引用

未绑定的方法引用

未绑定的方法引用是指没有关联对象的普通(非静态)方法。 使用未绑定的引用时,我们必须先提供对象:

我们先来看一个例子:

/**
 * @author @author kenewstar
 * @date 2022/01/23
 */publicclassTestFun4{publicstaticvoidmain(String[] args){// Non-static method cannot be referenced from a static context// TestFa fa = MethodRef::test;TestFb fb=MethodRef::test;MethodRef ref=newMethodRef();System.out.println(fb.tf(ref));// 或者使用 对象::方法的方式TestFa fa= ref::test;System.out.println(fa.tf());}}classMethodRef{publicStringtest(){return"test";}}interfaceTestFa{Stringtf();}interfaceTestFb{Stringtf(MethodRef ref);}

我们看到上面无法将 **MethodRef::test **函数式引用绑定到TestFa 接口上,这是因为实际上还有另一个隐藏的参数:this 。 你不能在没有 MethodRef 对象的前提下调用 test() 。 因此,MethodRef::test 表示未绑定的方法引用,因为它尚未“绑定”到对象,如果使用ref::test 方式则等同于已绑定的方法引用。

使用未绑定的引用时,函数式方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配,因此需要一个额外的MethodRef 参数对象。原因是:你需要一个对象来调用方法。

如果有多个参数,则默认第一个参数传递this 对象

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunc4{publicstaticvoidmain(String[] args){TestFc fc=MethodRef::test;MethodRef ref=newMethodRef();System.out.println(fc.tf(ref,"other"));}}classMethodRef{publicStringtest(String name){return"test + "+ name;}}interfaceTestFc{Stringtf(MethodRef ref,String other);}

构造函数引用

即通过构造方法的引用创建对象

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunc5{publicstaticvoidmain(String[] args){CreatePerson cp=Person::new;Person kenewstar= cp.create("kenewstar",22);System.out.println(kenewstar);}}interfaceCreatePerson{Personcreate(String name,int age);}classPerson{String name;int age;publicPerson(String name,int age){this.name= name;this.age= age;}}

方法引用的三种方式:

类名::方法名

对象名::方法名

构造方法名:: new

3.函数式接口

@FunctionalInterface 一个被该注解标注的接口则表示它是一个函数式接口,该接口中只允许一个抽象方法的存在,存在多个则会编译不通过。例如前面例子中所提到的Runnable,Callable接口都是函数式接口

Java8提供函数式接口

特征函数式方法名示例
无参数; 无返回值Runnable run()Runnable
无参数; 返回类型任意Supplier get()SupplierBooleanSupplierIntSupplierLongSupplierDoubleSupplier
无参数; 返回类型任意Callable call()Callable
1 个参数; 无返回值Consumer accept()ConsumerIntConsumerLongConsumerDoubleConsumer
2 个参数 ;ConsumerBiConsumer accept()BiConsumer<T, U>
2 个参数 Consumer; 1 引用; 1 基本类型Obj类型Consumer accept()ObjIntConsumer ObjLongConsumer ObjDoubleConsumer
1 个参数; 返回类型不同Function apply() To类型 和 类型To类型Function IntFunction LongFunction DoubleFunction ToIntFunction ToLongFunction ToDoubleFunction IntToLongFunction IntToDoubleFunction LongToIntFunction LongToDoubleFunction DoubleToIntFunction DoubleToLongFunction
1个 参数; 返回类型相同UnaryOperator apply()UnaryOperator IntUnaryOperator LongUnaryOperator DoubleUnaryOperator
2 个参数类型相同; 返回类型相同Comparator compare()Comparator
2 个参数; 返回布尔型Predicate test()Predicate BiPredicate IntPredicate LongPredicate DoublePredicate
参数基本类型; 返回基本类型类型To类型Function applyAs类型()IntToLongFunction IntToDoubleFunction LongToIntFunction LongToDoubleFunction DoubleToIntFunction DoubleToLongFunction
2 个参数类型不同Bi操作 (不同方法名)BiFunction BiConsumer BiPredicate ToIntBiFunction ToLongBiFunction ToDoubleBiFunction

3.1 Supplier

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestSupplier{staticSupplier<String> s=()->"我是Supplier型接口";staticBooleanSupplier bs=()->true;staticIntSupplier is=()->100;staticLongSupplier ls=()->100L;staticDoubleSupplier ds=()->100.00;publicstaticvoidmain(String[] args){// Supplier类型System.out.println(s.get());// 我是Supplier型接口System.out.println(bs.getAsBoolean());// trueSystem.out.println(is.getAsInt());// 100System.out.println(ls.getAsLong());// 100System.out.println(ds.getAsDouble());// 100.0}}

3.2 Consumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestConsumer{staticConsumer<String> c= str->System.out.println("consumer "+ str);staticIntConsumer ic= i->System.out.println(i*100);staticLongConsumer lc= l->System.out.println(l*100);staticDoubleConsumer dc= d->System.out.println(d*100);publicstaticvoidmain(String[] args){// Consumer类型
      c.accept("kns");// consumer kns
      ic.accept(2);// 200
      lc.accept(3L);// 300
      dc.accept(4D);// 400.0}}

3.3 BiConsumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestBiConsumer{staticBiConsumer<String,Integer> bc=(str, i)->{Integer result;try{
			result=Integer.parseInt(str);}catch(Exception e){
			result=0;}System.out.println(result+ i);};publicstaticvoidmain(String[] args){
      
        bc.accept("100",200);// 300}}

3.4 ObjConsumer

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestObjConsumer{staticObjIntConsumer<String> oic=(o, i)->System.out.println(o+ i);staticObjLongConsumer<String> olc=(o, l)->System.out.println(o+ l);staticObjDoubleConsumer<String> odc=(o, d)->System.out.println(o+ d);publicstaticvoidmain(String[] args){

      oic.accept("obj",100);// obj100
      olc.accept("obj",100L);// obj100
      odc.accept("obj",100.0);// obj100.0}}

3.5 Function

/**
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestFunction{staticFunction<String,String> func= s-> s;// 将数字转换为字符串staticIntFunction<String> iFunc=String::valueOf;staticLongFunction<String> lFunc=String::valueOf;staticDoubleFunction<String> dFunc=String::valueOf;// 将字段串转换为数字类型staticToIntFunction<String> tif=Integer::parseInt;staticToLongFunction<String> tlf=Long::parseLong;staticToDoubleFunction<String> tdf=Double::parseDouble;// 将类型转换另一个类型staticIntToLongFunction ilf= i-> i;staticIntToDoubleFunction idf= i-> i;staticLongToIntFunction lif= l->(int)l;staticLongToDoubleFunction ldf= l-> l;staticDoubleToIntFunction dif= d->(int)d;staticDoubleToLongFunction dlf= d->(long)d;publicstaticvoidmain(String[] args){System.out.println(func.apply("abc"));System.out.println(iFunc.apply(100));System.out.println(lFunc.apply(200L));System.out.println(dFunc.apply(300.0));System.out.println(tif.applyAsInt("111"));System.out.println(tlf.applyAsLong("222"));System.out.println(tdf.applyAsDouble("333"));System.out.println(ilf.applyAsLong(100));System.out.println(idf.applyAsDouble(100));System.out.println(lif.applyAsInt(200L));System.out.println(ldf.applyAsDouble(200L));System.out.println(dif.applyAsInt(300.0));System.out.println(dlf.applyAsLong(300.0));}}

3.6 UnaryOperator

/**
 * 继承自Function
 * 入参返参相同
 * @author kenewstar
 * @date 2022/01/23
 */publicclassTestUnaryOperator{staticUnaryOperator<String> uo= s-> s;staticIntUnaryOperator iuo= i-> i*2;staticLongUnaryOperator luo= l-> l*2;staticDoubleUnaryOperator duo= d-> d*2;publicstaticvoidmain(
  • 作者:kenewstar
  • 原文链接:https://blog.csdn.net/weixin_45840947/article/details/122656557
    更新时间:2022-08-21 11:26:19