引言Java 8 引入的 Lambda 表达式和函数式接口让 Java 具备了函数式编程的能力。函数式编程不是要替代面向对象而是提供了一种更简洁、更具表达力的编程范式特别适合集合操作、事件处理和异步编程。一、Lambda 表达式1.1 语法// 完整语法(Type1param1,Type2param2)-{expression;returnvalue;}// 简化规则// 1. 类型推断参数类型可省略(a,b)-ab// 2. 单参数括号可省略name-System.out.println(name)// 3. 单表达式花括号和 return 可省略(a,b)-ab// 4. 多行语句需要花括号和 return(a,b)-{intsumab;returnsum;}1.2 常见用法// 替代匿名内部类// BeforeRunnabler1newRunnable(){Overridepublicvoidrun(){System.out.println(hello);}};// AfterRunnabler2()-System.out.println(hello);// ComparatorComparatorStringc1(a,b)-a.length()-b.length();// 自定义接口FunctionalInterfaceinterfaceStringProcessor{Stringprocess(Stringinput);}StringProcessortoUppers-s.toUpperCase();1.3 变量捕获// Lambda 可以捕获 effectively final 的局部变量StringprefixHello, ;// effectively finalFunctionString,Stringgreetername-prefixname;greeter.apply(Alice);// Hello, Alice// Lambda 内部不能修改捕获的变量// prefix Hi, ; // 编译错误二、函数式接口2.1 FunctionalInterface// 函数式接口只包含一个抽象方法的接口FunctionalInterfacepublicinterfaceConverterT,R{Rconvert(Tinput);}// 默认方法和静态方法不影响FunctionalInterfacepublicinterfaceSmartConverterT,R{Rconvert(Tinput);defaultRconvertOrDefault(Tinput,RdefaultValue){returninputnull?defaultValue:convert(input);}staticTSmartConverterT,Tidentity(){returnt-t;}}2.2 JDK 内置函数式接口接口参数返回用途示例SupplierT无T提供值() - new Config()ConsumerTTvoid消费值s - log.info(s)BiConsumerT,UT,Uvoid消费两个值(k,v) - map.put(k,v)FunctionT,RTR转换s - s.length()BiFunctionT,U,RT,UR双参数转换(a,b) - a bUnaryOperatorTTT一元操作s - s.trim()BinaryOperatorTT,TT二元操作(a,b) - a bPredicateTTboolean判断s - s.isEmpty()BiPredicateT,UT,Uboolean双参数判断(a,b) - a.equals(b)基本类型特化避免装箱拆箱IntSuppliersupplier()-42;// int - intIntFunctionStringfunci-Ni;// int - StringIntPredicatepredi-i0;// int - booleanIntConsumerconsumeri-log(i);// int - voidIntUnaryOperatoropi-i*2;// int - intIntBinaryOperatorbinOp(a,b)-ab;// int,int - int三、方法引用3.1 四种形式形式语法等价 Lambda静态方法引用ClassName::staticMethoda - ClassName.staticMethod(a)实例方法引用instance::methoda - instance.method(a)类型方法引用ClassName::method(obj, a) - obj.method(a)构造器引用ClassName::new() - new ClassName()3.2 示例// 1. 静态方法引用FunctionString,IntegerparserInteger::parseInt;// 2. 实例方法引用StringprefixHello, ;FunctionString,Stringgreeterprefix::concat;// 3. 类型方法引用最常用FunctionString,IntegerlengthFnString::length;BiPredicateString,StringequalsFnString::equals;// 4. 构造器引用SupplierListStringlistFactoryArrayList::new;FunctionInteger,int[]arrayFactoryint[]::new;3.3 方法引用 vs Lambda// 优先使用方法引用更简洁list.forEach(System.out::println);// 方法引用list.forEach(s-System.out.println(s));// Lambda稍冗长// 方法引用无法表达时使用 Lambdalist.stream().map(s-s!);// Lambda四、函数组合4.1 Function 组合FunctionString,StringtrimString::trim;FunctionString,StringtoUpperString::toUpperCase;FunctionString,StringaddPrefixs-Hello, s;// andThen先执行当前再执行参数FunctionString,Stringpipelinetrim.andThen(toUpper).andThen(addPrefix);Stringresultpipeline.apply( alice );// Hello, ALICE// compose先执行参数再执行当前FunctionString,Stringpipeline2addPrefix.compose(toUpper).compose(trim);Stringresult2pipeline2.apply( alice );// Hello, ALICE4.2 Predicate 组合PredicateStringnonEmptys-!s.isEmpty();PredicateStringshortStrs-s.length()10;PredicateStringstartsWithAs-s.startsWith(A);// and / or / negatePredicateStringcombinednonEmpty.and(shortStr).and(startsWithA.negate());combined.test(Hello);// truecombined.test(ABCDEF);// false4.3 Consumer 组合ConsumerStringlogs-System.out.println(LOG: s);ConsumerStringaudits-System.out.println(AUDIT: s);ConsumerStringlogAndAuditlog.andThen(audit);logAndAudit.accept(user login);// LOG: user login// AUDIT: user login五、高阶函数实战5.1 策略模式// 传统策略模式需要多个类// 函数式策略模式用 Map Lambda 替代MapString,FunctionDouble,DoublestrategiesMap.of(regular,p-p*0.95,vip,p-p*0.8,svip,p-p*0.7);doublediscountedstrategies.getOrDefault(userLevel,p-p).apply(originalPrice);5.2 装饰器模式// 函数式装饰器FunctionString,Stringbases-s;FunctionFunctionString,String,FunctionString,StringtrimDecoratorfn-s-fn.apply(s.trim());FunctionFunctionString,String,FunctionString,StringupperDecoratorfn-s-fn.apply(s.toUpperCase());FunctionFunctionString,String,FunctionString,StringprefixDecoratorfn-s-fn.apply( s);FunctionString,StringdecoratedtrimDecorator.andThen(upperDecorator).andThen(prefixDecorator).apply(base);decorated.apply( hello );// HELLO5.3 惰性求值publicclassLazyT{privateSupplierTsupplier;privateTvalue;privatebooleancomputedfalse;publicLazy(SupplierTsupplier){this.suppliersupplier;}publicTget(){if(!computed){valuesupplier.get();computedtrue;suppliernull;}returnvalue;}publicRLazyRmap(FunctionT,Rfn){returnnewLazy(()-fn.apply(this.get()));}publicRLazyRflatMap(FunctionT,LazyRfn){returnnewLazy(()-fn.apply(this.get()).get());}}// 使用LazyStringlazynewLazy(()-{System.out.println(Computing...);returnhello;});// 此时未计算Stringresultlazy.get();// Computing... - helloStringagainlazy.get();// 直接返回缓存值不再计算5.4 回调模式publicTvoidexecuteAsync(SupplierTtask,ConsumerTonSuccess,ConsumerExceptiononError){newThread(()-{try{Tresulttask.get();onSuccess.accept(result);}catch(Exceptione){onError.accept(e);}}).start();}// 使用executeAsync(()-fetchData(),result-System.out.println(Success: result),error-System.err.println(Error: error.getMessage()));六、常见陷阱6.1 Lambda 中的 thispublicclassDemo{privateStringnameOuter;publicvoidtest(){// Lambda 中的 this 指向外部类实例Runnabler()-System.out.println(this.name);// Outer// 匿名内部类中的 this 指向匿名类实例Runnabler2newRunnable(){privateStringnameInner;publicvoidrun(){System.out.println(this.name);// Inner}};}}6.2 Lambda 与受检异常// Lambda 中受检异常必须处理list.forEach(s-{try{Files.readString(Path.of(s));}catch(IOExceptione){thrownewUncheckedIOException(e);}});// 封装工具方法privatestaticTSupplierTunchecked(CallableTcallable){return()-{try{returncallable.call();}catch(Exceptione){thrownewRuntimeException(e);}};}6.3 Lambda 与重载歧义// 编译错误Lambda 类型推断歧义execute(()-{});// 是 Runnable 还是 CallableVoid?// 显式指定类型execute((Runnable)()-{});execute((CallableVoid)()-null);总结要点建议Lambda优先替代匿名内部类方法引用比 Lambda 更简洁时使用函数式接口优先使用 JDK 内置接口函数组合andThen/compose 构建处理管道变量捕获effectively final不要 hack受检异常Lambda 中必须 try-catch 或包装