Java中Optional ifPresent结合orElse调用函数报void错误解决方法
你这段代码不止ifPresent的用法错误,还有两个流API的基础用法错误,修正后完全可以不用显式if-else和for循环实现需求:
核心错误点
forEach是流的终止操作,执行后流会直接关闭,返回值为void,根本无法链式调用后续的filter、findAny方法,中间阶段要对元素做处理应该用中间操作peekifPresent方法本身返回void,不存在后续的orElse链式调用,要实现「匹配到值执行A逻辑、没匹配到执行B逻辑」,Java 9+的Optional提供了直接支持的ifPresentOrElse方法,两个入参都是无返回值的执行动作,刚好适配你的场景- 反射取字段值时没有做判空处理,字段值为null时调用
equals会直接抛空指针,同时需要在流内处理反射的受检异常
正确实现(Java 9+)
try { Field[] fields = oldRow.getClass().getDeclaredFields(); Arrays.stream(fields) // 中间操作设置私有字段访问权限 .peek(field -> field.setAccessible(true)) // 过滤出值不相等的字段,兼容null值判断,处理反射受检异常 .filter(field -> { try { Object oldVal = field.get(oldRow); Object newVal = field.get(newRow); return oldVal == null ? newVal != null : !oldVal.equals(newVal); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }) .findAny() // 存在差异字段调用无参更新方法,无差异调用带参更新方法 .ifPresentOrElse( diffField -> newRow.updateACell(), () -> newRow.udpateACell("new value") ); } catch (Exception e){ System.out.println(e); }
Java 8兼容写法
如果你的环境是Java 8,没有ifPresentOrElse方法,可以把两个更新逻辑包装为Runnable统一触发,依然不需要显式if-else或for循环:
try { Optional<Field> diffFieldOpt = Arrays.stream(oldRow.getClass().getDeclaredFields()) .peek(field -> field.setAccessible(true)) .filter(field -> { try { Object oldVal = field.get(oldRow); Object newVal = field.get(newRow); return oldVal == null ? newVal != null : !oldVal.equals(newVal); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }) .findAny(); diffFieldOpt.<Runnable>map(field -> newRow::updateACell) .orElseGet(() -> () -> newRow.udpateACell("new value")) .run(); } catch (Exception e){ System.out.println(e); }
注意事项
- 不要在流的中间处理阶段调用
forEach,它会直接消费流终止流水线,中间遍历处理元素用peek - 反射对比字段值时必须兼容null场景,避免空指针
- 如果你的
DataRow有父类字段,getDeclaredFields()只能拿到当前类声明的字段,需要额外遍历父类的Field列表才能覆盖所有属性
内容的提问来源于stack exchange,提问作者Liumx31
相关产品推荐
相关产品推荐

