Java中TGS_Coronator调用Lambda时出现类型不兼容错误如何解决
问题描述
日常开发中优先使用Java Stream编码时,Lambda表达式仅允许引用effectively final的局部变量,无法直接对变量做多次赋值。
原有非effectively final的业务逻辑代码如下:
var yetkiliAdı = TS_SQLSelectUtils.select(cp.sqlAnc, "hamsiparis").columns( "STR254_YETKILI" ).whereFirstColumnAsId(so.selectedId).getStr(); if (TGS_StringUtils.isNullOrEmpty(yetkiliAdı)) { yetkiliAdı = TS_SQLSelectUtils.select(cp.sqlAnc, "firma").columns( "STR254_YETADI" ).whereFirstColumnAsId(tedFirmId).getStr(); } yetkiliAdı = TGS_StringUtils.toNullIfEmpty(yetkiliAdı);
为了适配effectively final要求,自定义了链式值处理工具类TGS_Coronator<T>,尝试将上述逻辑改写为链式调用形式:
var yetkiliAdı = TGS_Coronator.of("") .anoint( val -> TS_SQLSelectUtils.select(cp.sqlAnc, "hamsiparis") .columns("STR254_YETKILI") .whereFirstColumnAsId(so.selectedId) .getStr() ).anointIf(val -> TGS_StringUtils.isNullOrEmpty(val), val -> TS_SQLSelectUtils.select(cp.sqlAnc, "firma") .columns("STR254_YETADI") .whereFirstColumnAsId(tedFirmId) .getStr() ).anoint( val -> TGS_StringUtils.toNullIfEmpty(val) ).coronate();
编译时抛出错误:incompatible types: Object cannot be converted to CharSequence,无法定位泛型类型丢失的原因。
自定义TGS_Coronator<T>的完整实现代码如下:
package com.tugalsan.api.coronator.client; import com.tugalsan.api.compiler.client.*; import com.tugalsan.api.pack.client.*; import com.tugalsan.api.validator.client.*; import java.util.*; public class TGS_Coronator<T> { //CONSTRUCTOR private T bufferedValue; public TGS_Coronator(T initVal) { bufferedValue = initVal; } public static <T> TGS_Coronator of(T initialValue) { return new TGS_Coronator(initialValue); } //LOADERS private List<TGS_Pack3<TGS_CompilerType1<T, T>, TGS_ValidatorType1<T>, /*is it stopper*/ Boolean>> pack = new ArrayList(); public TGS_Coronator<T> anoint(TGS_CompilerType1<T, T> val) { pack.add(new TGS_Pack3(val, null, null)); return this; } public TGS_Coronator<T> coronateIf(TGS_ValidatorType1<T> validate, TGS_CompilerType1<T, T> val) { if (validate.validate(bufferedValue)) { pack.add(new TGS_Pack3(null, validate, true)); } return this; } public TGS_Coronator<T> anointIf(TGS_ValidatorType1<T> validate, TGS_CompilerType1<T, T> val) { if (validate.validate(bufferedValue)) { pack.add(new TGS_Pack3(val, validate, false)); } return this; } public TGS_Coronator<T> anointAndCoronateIf(TGS_ValidatorType1<T> validate, TGS_CompilerType1<T, T> val) { if (validate.validate(bufferedValue)) { pack.add(new TGS_Pack3(val, validate, true)); } return this; } //FETCHER public T coronate() { for (var comp : pack) { var setter = comp.value0; var validator = comp.value1; var validatorIsStopper = comp.value2; if (validator == null) { bufferedValue = setter.compile(bufferedValue); continue; } if (!validator.validate(bufferedValue)) { continue; } if (setter != null) { bufferedValue = setter.compile(bufferedValue); } if (validatorIsStopper) { return bufferedValue; } } return bufferedValue; } }
泛型丢失根因
核心问题是静态工厂方法of使用了*原始类型(Raw Type)*作为返回值:
// 错误写法:返回值是没有泛型参数的原始类型TGS_Coronator public static <T> TGS_Coronator of(T initialValue) { return new TGS_Coronator(initialValue); }
原始类型会触发Java的泛型擦除回退机制,后续所有链式调用的泛型参数都会被丢失,类型参数T被替换为Object,最终coronate()方法返回值类型也退化为Object,自然无法赋值给CharSequence类型的变量。
此外代码中new ArrayList()、new TGS_Coronator(initialValue)也都使用了原始类型,会进一步加剧泛型推断异常的风险。
修复方案
- 修正
of方法的返回值为泛型类型,同时构造实例时使用钻石运算符让编译器自动推断泛型:public static <T> TGS_Coronator<T> of(T initialValue) { return new TGS_Coronator<>(initialValue); } - 所有泛型类实例化时不要使用原始类型,统一添加钻石运算符,比如
pack字段的初始化改为:private List<TGS_Pack3<TGS_CompilerType1<T, T>, TGS_ValidatorType1<T>, Boolean>> pack = new ArrayList<>(); - 修复条件判断的执行时机问题:当前
anointIf、coronateIf、anointAndCoronateIf方法中,validate.validate(bufferedValue)是在添加规则的当下执行的,此时bufferedValue还是初始值,等前面的anoint逻辑执行完值变化后,条件不会重新判断,会导致分支逻辑完全失效。需要把这层校验移到coronate()的遍历执行流程中,添加规则时无论条件是否满足都将规则存入pack,执行到对应规则节点时再做校验。
内容的提问来源于stack exchange,提问作者Tugalsan Karabacak
相关产品推荐
相关产品推荐

