为何替换为方法引用的Map代码抛出TypeNotPresentException异常?
Lambda替换为方法引用后触发TypeNotPresentException的原因与解决
问题场景
将Stream的map操作从lambda表达式t->toDTO(t)替换为方法引用this::toDTO后,程序抛出java.lang.TypeNotPresentException,提示Type com.grupoaev.aevgestion.domain.entities.solicitudes.Tecnico not present,但原lambda写法可正常运行。
报错代码
return findTechnician.findWithUser() .stream() .map(this::toDTO) .collect(Collectors.toSet());
错误信息
Method threw 'java.lang.TypeNotPresentException' exception. Type com.grupoaev.aevgestion.domain.entities.solicitudes.Tecnico not present
相关类代码
private static class TechniciansModel extends LoadableDetachableModel<Collection<TechnicianDatesDTO>> { private static final long serialVersionUID = 1L; @SpringBean private FindTechnician findTechnician; @SpringBean private FindTechnicalUserAbsences findTechnicalUserAbsences; public TechniciansModel() { Injector.get().inject(this); } @Override protected Collection<TechnicianDatesDTO> load() { return findTechnician.findWithUser() .stream() .map(t->toDTO(t)) .collect(Collectors.toSet()); } @NotNull private TechnicianDatesDTO toDTO(Tecnico technician) { String displayingName = technician.getUsuario().getName(); Set<Range<LocalDate>> invalidDates = findTechnicalUserAbsences.findByTecnicoId(technician.getId()) .stream() .map(absence -> new Range<>(toLocalDate(absence.getFechaInicio()), toLocalDate(absence.getFechaFin()))) .collect(Collectors.toSet()); return new TechnicianDatesDTO(displayingName, invalidDates); } private LocalDate toLocalDate(Date date) { return date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() : null; } }
原正常运行代码
return findTechnician.findWithUser() .stream() .map(t->toDTO(t)) .collect(Collectors.toSet());
原因分析
这是Java类型擦除与方法引用的类型解析机制差异导致的:
- Lambda表达式在编译时会延迟类型推断,它的参数类型
t是在运行时根据Stream的元素类型(findWithUser()的返回类型)确定的,不会在编译阶段强制解析Tecnico类的存在性。 - 方法引用
this::toDTO在编译阶段就会直接关联到toDTO(Tecnico technician)方法,此时JVM会尝试解析方法参数中的Tecnico类。如果该类在编译时类路径存在,但运行时因类加载器问题(如Spring类加载机制、模块化隔离)或类被移除,就会抛出TypeNotPresentException。
解决方法
- 保留Lambda写法:Lambda的延迟类型推断避开了类加载时的类型解析问题,直接沿用
t->toDTO(t)即可。 - 显式指定泛型类型:在
map方法中显式指定泛型参数,帮助编译器提前锁定类型,规避方法引用的类型解析异常:return findTechnician.findWithUser() .stream() .<TechnicianDatesDTO>map(this::toDTO) .collect(Collectors.toSet()); - 排查类加载机制:检查
Tecnico类的类加载情况,确保运行时类加载器能正确加载该类。比如核对Spring组件扫描路径,或模块化项目中是否正确导出该类所在模块。 - 校验方法参数类型:确认
findWithUser()返回集合的元素类型与toDTO方法参数类型匹配,检查导入语句确保Tecnico是正确的目标类。
内容的提问来源于stack exchange,提问作者Alejandro Palacios Sanz
相关产品推荐
相关产品推荐

