Java实现类似Python的默认值:优化地址更新函数冗余判断
你提到的这种用大量if语句判断参数是否为空、然后回退到原有数据库值的场景,确实可以用更简洁的方式优化,不用写一堆重复的条件判断。下面几个方案都能帮你实现类似Python默认参数的效果,而且更符合Java的编码风格:
方案1:用Optional简化空值判断(快速改造现有代码)
Java 8引入的Optional类可以完美简化这种空值/空字符串的判断逻辑,不仅能去掉重复的if,还能解决原代码中参数为null时会抛出NullPointerException的隐患。
修改你的代码如下:
public static void update(Connection conn, int id, String number, String name, String city, String state, String zip) { Address address = Address.getBy(conn, "id", Integer.toString(id)); // 用Optional链式调用处理空值,自动回退到原有地址值 String finalNumber = Optional.ofNullable(number) .filter(s -> !s.isEmpty()) .orElse(address.getNumber()); String finalName = Optional.ofNullable(name) .filter(s -> !s.isEmpty()) .orElse(address.getName()); String finalCity = Optional.ofNullable(city) .filter(s -> !s.isEmpty()) .orElse(address.getCity()); String finalState = Optional.ofNullable(state) .filter(s -> !s.isEmpty()) .orElse(address.getState()); String finalZip = Optional.ofNullable(zip) .filter(s -> !s.isEmpty()) .orElse(address.getZip()); try { PreparedStatement ps = conn.prepareStatement("UPDATE address SET number=?, name=?, city=?, state=?, zip=? WHERE id =?"); ps.setString(1, finalNumber); ps.setString(2, finalName); ps.setString(3, finalCity); ps.setString(4, finalState); ps.setString(5, finalZip); ps.setInt(6, id); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } }
这段代码逻辑清晰,一眼就能看出每个参数的 fallback 规则,比一堆if可读性高很多。
方案2:建造者模式(推荐,扩展性最佳)
如果这个更新方法经常需要只修改部分字段,建造者模式会是最优雅的选择——调用方可以只设置需要更新的字段,不用传一堆空字符串,从根源上避免空值判断。
先创建一个建造者类:
public class AddressUpdateBuilder { private final Connection conn; private final int id; private String number; private String name; private String city; private String state; private String zip; // 必传参数在构造器中初始化 public AddressUpdateBuilder(Connection conn, int id) { this.conn = conn; this.id = id; } // 可选参数的setter,返回this支持链式调用 public AddressUpdateBuilder number(String number) { this.number = number; return this; } public AddressUpdateBuilder name(String name) { this.name = name; return this; } public AddressUpdateBuilder city(String city) { this.city = city; return this; } public AddressUpdateBuilder state(String state) { this.state = state; return this; } public AddressUpdateBuilder zip(String zip) { this.zip = zip; return this; } // 执行更新的核心方法 public void update() { Address address = Address.getBy(conn, "id", Integer.toString(id)); // 仅对非空参数使用传入值,否则复用原有数据 String finalNumber = (number != null && !number.isEmpty()) ? number : address.getNumber(); String finalName = (name != null && !name.isEmpty()) ? name : address.getName(); String finalCity = (city != null && !city.isEmpty()) ? city : address.getCity(); String finalState = (state != null && !state.isEmpty()) ? state : address.getState(); String finalZip = (zip != null && !zip.isEmpty()) ? zip : address.getZip(); try { PreparedStatement ps = conn.prepareStatement("UPDATE address SET number=?, name=?, city=?, state=?, zip=? WHERE id =?"); ps.setString(1, finalNumber); ps.setString(2, finalName); ps.setString(3, finalCity); ps.setString(4, finalState); ps.setString(5, finalZip); ps.setInt(6, id); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } } }
调用时会非常简洁,比如只更新街道名称和邮编:
new AddressUpdateBuilder(conn, 123) .name("Main Street") .zip("10001") .update();
这个方案的优势在于调用方代码可读性极强,后续如果要新增地址字段,只需要在建造者里加对应的setter即可,扩展性拉满。
方案3:方法重载(适合参数组合固定的场景)
如果你的更新操作参数组合比较固定,比如经常只更新number+name或者city+zip,可以创建多个重载的update方法,每个方法对应不同的参数组合,内部调用完整参数的方法并自动填充原有值。
示例:
// 完整参数的核心方法(可结合Optional优化空值判断) public static void update(Connection conn, int id, String number, String name, String city, String state, String zip) { // 这里放处理后的更新逻辑 } // 仅更新门牌号和街道名的重载方法 public static void update(Connection conn, int id, String number, String name) { Address address = Address.getBy(conn, "id", Integer.toString(id)); update(conn, id, number, name, address.getCity(), address.getState(), address.getZip()); } // 仅更新城市和邮编的重载方法 public static void update(Connection conn, int id, String city, String zip) { Address address = Address.getBy(conn, "id", Integer.toString(id)); update(conn, id, address.getNumber(), address.getName(), city, address.getState(), zip); }
不过这个方案的缺点是如果参数组合太多,会产生大量重载方法,代码冗余度上升,所以只适合参数组合固定且较少的场景。
总结一下:如果追求调用简洁和长远扩展性,建造者模式是最优选择;如果只是想快速改造现有代码,Optional是最便捷的方式;参数组合固定的话可以考虑方法重载。
内容的提问来源于stack exchange,提问作者Jack Stockley

