JavaFX绑定场景下isNull()判定为非空后仍触发NullPointerException的问题求助
问题根源:JavaFX Bindings的非短路求值陷阱
这问题我之前调试时也踩过坑!核心原因是你误解了JavaFX Bindings中逻辑表达式的执行逻辑——它不是短路求值的!
你原本以为,当simLeftProperty().isNull()返回true时,or右边的param.getValue().getSimLeft().photoProperty().isNull()就不会执行,但JavaFX的Bindings API并没有实现Java原生||那样的短路逻辑。它会先把左右两个ObservableValue的表达式全部执行一遍,再做逻辑运算。这就导致如果simLeft是null,调用getSimLeft()时直接触发NullPointerException,根本轮不到条件判断生效。
另外补充一点:你在Sim类里保证了photoProperty不会为null,但如果simLeft本身是null,getSimLeft()这一步就已经失败了,根本到不了访问photoProperty的环节。
两种可行的解决方案
方案1:嵌套Bindings.when逐层检查
通过嵌套的when语句,先确保simLeft非空后,再检查photo属性:
this.columnRelationSimLeft.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Relationship, Image>, ObservableValue<Image>>() { @Override public ObservableValue<Image> call(TableColumn.CellDataFeatures<Relationship, Image> param) { if (Objects.isNull(param) || Objects.isNull(param.getValue())) return null; Relationship relationship = param.getValue(); ObjectProperty<Image> image = new SimpleObjectProperty<>(); // 先判断simLeft是否为空,再嵌套判断photo是否为空 image.bind(Bindings.when(relationship.simLeftProperty().isNull()) .then(DefaultImageProvider.INSTANCE.getImageFrom(SimAge.ADULT, SimGender.F)) .otherwise(Bindings.when(relationship.getSimLeft().photoProperty().isNull()) .then(DefaultImageProvider.INSTANCE.getImageFrom(SimAge.ADULT, SimGender.F)) .otherwise(relationship.getSimLeft().photoProperty()))); return image; } });
方案2:用Bindings.select安全访问嵌套属性
JavaFX提供了Bindings.select系列方法,能安全访问嵌套属性,中间任何一步为null都不会抛出异常,直接返回null:
this.columnRelationSimLeft.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Relationship, Image>, ObservableValue<Image>>() { @Override public ObservableValue<Image> call(TableColumn.CellDataFeatures<Relationship, Image> param) { if (Objects.isNull(param) || Objects.isNull(param.getValue())) return null; Relationship relationship = param.getValue(); ObjectProperty<Image> image = new SimpleObjectProperty<>(); // 用Bindings.selectNull检查嵌套属性是否为空 image.bind(Bindings.when( relationship.simLeftProperty().isNull() .or(Bindings.selectNull(relationship.simLeftProperty(), "photo")) ) .then(DefaultImageProvider.INSTANCE.getImageFrom(SimAge.ADULT, SimGender.F)) .otherwise(Bindings.select(relationship.simLeftProperty(), "photo"))); return image; } });
关键提醒
JavaFX Bindings的or()、and()方法都是非短路执行的,所有传入的表达式都会被预先求值。处理嵌套属性的null安全问题时,要么用嵌套when逐层校验,要么用Bindings.select系列方法避免直接调用可能返回null的getter。
内容的提问来源于stack exchange,提问作者VANILKA
相关产品推荐
相关产品推荐

