java if 判空_java如不想么每次都判空 if(o !=null) 怎么做?

本文介绍了一种在工程设计中避免NullPointerException的方法——NullObject模式。通过实现与业务对象相同接口的NullObject,使得客户端调用时能无感知地处理空对象情况。以Jackson框架为例,展示了如何使用path方法替代get方法,从而避免异常并提供了一致的API体验。

这是是工程设计上常见的问题,一般的解决方案就是 @特价萝卜 所说的NullObject模式。本来想投 @特价萝卜 的答案赞成票,但纠结良久还是觉得说得有些复杂了。

简单来说就是有一个NullObject与原有业务对象实现相同的接口(或继承同一个父类),让客户端调用时可以无感知(也不必判定null)。

有一个很好的例子就是著名JSON解析框架Jackson。以下代码是Jackson从一段JSON中获取其一级子节点lv1下的二级子节点lv2的内容:

JsonNode root = ...;

JsonNode child = root.get("lv1").get("lv2");

以上代码很可能遇到lv1不存在的情况,因此第一个get()就会返回null,那么第二个get()执行时自然就抛出NullPointerException了。为了解决这个问题,作者提供了path方法来替代get方法:

JsonNode root = ...;

JsonNode child = root.path("lv1").path("lv2");

当lv1不存在时,path()返回一个JsonNode的子类叫做MissingNode(但客户端暂时无需知道),MissingNode的path方法则继续返回MissingNode,这样无论这个链式调用写多长都不会抛出任何异常。

直到最后客户端调用完成后检查返回结果是否为MissingNode:

if (child.isMissingNode()) { ... }

<insert id="insertPpElectroplantingList" parameterType="com.hwitec.shrcs.bi.domain.PpElectroplantingList" useGeneratedKeys="true" keyProperty="id"> insert into pp_electroplanting_list <trim prefix="(" suffix=")" suffixOverrides=","> <if test="area != null">`area`,</if> <if test="orderNo != null">`order_no`,</if> <if test="finishedProductNo != null">`finished_product_no`,</if> <if test="materialDesc != null">`material_desc`,</if> <if test="customer != null">`customer`,</if> <if test="segment != null">`segment`,</if> <if test="line != null">`line`,</if> <if test="status != null">`status`,</if> <if test="deliveryStatus != null">`delivery_status`,</if> <if test="pstartTime != null">`pstart_time`,</if> <if test="pfinishedTime != null">`pfinished_time`,</if> <if test="demandDate != null">`demand_date`,</if> <if test="qty != null">`qty`,</if> <if test="pbatch != null">`pbatch`,</if> <if test="delay != null">`delay`,</if> <if test="oee != null">`oee`,</if> <if test="ct != null">`ct`,</if> <if test="doh != null">`doh`,</if> <if test="createBy != null">`create_by`,</if> <if test="createTime != null">`create_time`,</if> <if test="totalTime != null">`total_time`,</if> <if test="teamNo != null">`team_no`,</if> <if test="assignClassName != null">`assign_class_name`,</if> <if test="className != null">`class_name`,</if> <if test="overflow != null">`overflow`,</if> <if test="safedays != null">`safedays`,</if> <if test="dohdiff2 != null">`dohdiff2`,</if> <if test="dohdiff != null">`dohdiff`,</if> <if test="version != null">`version`,</if> <if test="customerProductNo != null">`customer_product_no`,</if> <if test="project != null">`project`,</if> <if test="maxDays != null">`max_days`,</if> <if test="minDays != null">`min_days`,</if> <if test="stock != null">`stock`,</if> <if test="timeDesc != null">`time_desc`,</if> <if test="actualClassNumber != null">`actual_class_number`,</if> <if test="changeTime != null">`change_time`,</if> <if test="mrpdailyVersion != null">`mrpdaily_version`,</if> <if test="cjpVersion != null">`cjp_version`,</if> <if test="paramsClassInfo != null">`params_class_info`,</if> <if test="lockOrder != null">`lock_order`,</if> <if test="updateTime != null">`update_time`,</if> <if test="updateBy != null">`update_by`,</if> <if test="onlyDaily != null">`only_daily`,</if> <if test="beginDate != null">`begin_date`,</if> <if test="endDate != null">`end_date`,</if> <if test="platingType != null">`plating_type`,</if> <if test="faPart != null">`fa_part`,</if> <if test="productNum != null">`product_num`,</if> <if test="machineDemandDate != null">`machine_demand_date`,</if> <if test="type != null">`type`,</if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="area != null">#{area},</if> <if test="orderNo != null">#{orderNo},</if> <if test="finishedProductNo != null">#{finishedProductNo},</if> <if test="materialDesc != null">#{materialDesc},</if> <if test="customer != null">#{customer},</if> <if test="segment != null">#{segment},</if> <if test="line != null">#{line},</if> <if test="status != null">#{status},</if> <if test="deliveryStatus != null">#{deliveryStatus},</if> <if test="pstartTime != null">#{pstartTime},</if> <if test="pfinishedTime != null">#{pfinishedTime},</if> <if test="demandDate != null">#{demandDate},</if> <if test="qty != null">#{qty},</if> <if test="pbatch != null">#{pbatch},</if> <if test="delay != null">#{delay},</if> <if test="oee != null">#{oee},</if> <if test="ct != null">#{ct},</if> <if test="doh != null">#{doh},</if> <if test="createBy != null">#{createBy},</if> <if test="createTime != null">#{createTime},</if> <if test="totalTime != null">#{totalTime},</if> <if test="teamNo != null">#{teamNo},</if> <if test="assignClassName != null">#{assignClassName},</if> <if test="className != null">#{className},</if> <if test="overflow != null">#{overflow},</if> <if test="safedays != null">#{safedays},</if> <if test="dohdiff2 != null">#{dohdiff2},</if> <if test="dohdiff != null">#{dohdiff},</if> <if test="version != null">#{version},</if> <if test="customerProductNo != null">#{customerProductNo},</if> <if test="project != null">#{project},</if> <if test="maxDays != null">#{maxDays},</if> <if test="minDays != null">#{minDays},</if> <if test="stock != null">#{stock},</if> <if test="timeDesc != null">#{timeDesc},</if> <if test="actualClassNumber != null">#{actualClassNumber},</if> <if test="changeTime != null">#{changeTime},</if> <if test="mrpdailyVersion != null">#{mrpdailyVersion},</if> <if test="cjpVersion != null">#{cjpVersion},</if> <if test="paramsClassInfo != null">#{paramsClassInfo},</if> <if test="lockOrder != null">#{lockOrder},</if> <if test="updateTime != null">#{updateTime},</if> <if test="updateBy != null">#{updateBy},</if> <if test="onlyDaily != null">#{onlyDaily},</if> <if test="beginDate != null">#{beginDate},</if> <if test="endDate != null">#{endDate},</if> <if test="platingType != null">#{platingType},</if> <if test="faPart != null">#{faPart},</if> <if test="productNum != null">#{productNum},</if> <if test="machineDemandDate != null">#{machineDemandDate},</if> <if test="type != null">#{type},</if> </trim> </insert> 这个mybatis语句格式有什么问题
最新发布
12-09
你的 MyBatis `<insert>` 语句整体结构是 **正确的**,使用了动态 SQL 的 `<if>` 和 `<trim>` 来实现“只插入非字段”,并且启用了主键回填(`useGeneratedKeys="true"`),这在实际开发中非常常见。 但这段代码存在 **几个潜在问题和优化间**,下面我将逐一指出并提供改进建议。 --- ## ✅ 正确之处 - 使用了 `useGeneratedKeys="true"` + `keyProperty="id"`:能正确返回数据库生成的自增主键。 - 使用 `<trim prefix="(" suffix=")" suffixOverrides=",">`:自动去除最后一个逗号,防止语法错误。 - 字段与参数一一对应,命名清晰。 - 所有字段都用反引号 `` ` `` 包裹,避免 MySQL 关键字冲突(如 `order`, `status` 等)。 --- ## ⚠️ 存在的问题与改进建议 ### ❌ 1. **当所有字段都为 null 时,SQL 会变成非法语句** #### 问题重现: 如果传入的对象 `PpElectroplantingList` 中 **所有字段都是 `null`**,那么生成的 SQL 将是: ```sql INSERT INTO pp_electroplanting_list () VALUES () ``` 这个语句在大多数 MySQL 版本中 **不合法**(除非表有默认值且允许插入),通常会报错: > `Column count doesn't match value count at row 1` #### ✅ 解决方案:避免插入记录 你应该在 Java 层或 XML 中确保至少有一个字段非。更安全的做法是在 Service 层校验数据有效性。 > 💡 提示:MyBatis 不支持“整个 insert 动态跳过”的逻辑,所以应由业务逻辑控制不要传完全 null 的对象。 --- ### ⚠️ 2. **重复写了很多相同的 `<if>` 判断,维护成本高** 你写了两遍几乎一样的 `<if>` 列表(一个用于字段名,一个用于 `#{}` 值),容易出错(比如漏掉某个字段)。 #### ✅ 改进方案:使用 `<sql>` 片段复用字段列表 定义可重用的 SQL 片段: ```xml <sql id="ppElectroplantingList_fields"> <if test="area != null">`area`,</if> <if test="orderNo != null">`order_no`,</if> <if test="finishedProductNo != null">`finished_product_no`,</if> <!-- 其他字段... --> <if test="type != null">`type`,</if> </sql> <sql id="ppElectroplantingList_values"> <if test="area != null">#{area},</if> <if test="orderNo != null">#{orderNo},</if> <if test="finishedProductNo != null">#{finishedProductNo},</if> <!-- 其他字段... --> <if test="type != null">#{type},</if> </sql> ``` 然后在 insert 中引用: ```xml <insert id="insertPpElectroplantingList" parameterType="com.hwitec.shrcs.bi.domain.PpElectroplantingList" useGeneratedKeys="true" keyProperty="id"> INSERT INTO pp_electroplanting_list <trim prefix="(" suffix=")" suffixOverrides=","> <include refid="ppElectroplantingList_fields"/> </trim> <trim prefix="VALUES (" suffix=")" suffixOverrides=","> <include refid="ppElectroplantingList_values"/> </trim> </insert> ``` ✅ 好处: - 减少重复代码 - 易于维护和比对字段与值是否一致 - 避免遗漏 --- ### ⚠️ 3. **`<if test="xxx != null">` 对 String 类型不够严谨** 对于字符串类型(如 `area`, `orderNo`),仅判断 `!= null` 可能不够,因为可能是字符串 `""`。 #### 示例风险: ```java ppElectroplantingList.setOrderNo(""); // 插入字符串到数据库 ``` 这可能不是你想要的行为。 #### ✅ 建议增强判断(适用于 String 类型): ```xml <if test="orderNo != null and orderNo != ''"> `order_no`, </if> ``` 对应的 value 也一样: ```xml <if test="orderNo != null and orderNo != ''"> #{orderNo}, </if> ``` 或者封装成工具函数(Java 层预处理)。 --- ### ⚠️ 4. **日期时间字段建议设置默认值或由数据库生成** 像 `createTime`, `updateTime` 这类字段,建议不要依赖 Java 传入,而是在数据库设默认值: ```sql `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ``` 这样可以避免时区、系统时间不准等问题。 如果你坚持用 Java 设置,也要确保时间已正确初始化。 --- ### ✅ 5. **性能提示:批量插入时不推荐这种动态方式** 如果你要做 **批量插入**(`List<PpElectroplantingList>`),这种每个对象动态拼字段的方式会导致每条 SQL 都不同,无法使用预编译缓存,性能很差。 #### 推荐方案(批量): - 所有记录必须包含相同字段 → 使用统一字段列表插入 - 或改用 `<foreach>` 批量处理 --- ## ✅ 最终优化版示例(含 sql 片段) ```xml <sql id="ppElectroplantingList_fields"> <if test="area != null and area != ''">`area`,</if> <if test="orderNo != null and orderNo != ''">`order_no`,</if> <if test="finishedProductNo != null">`finished_product_no`,</if> <if test="materialDesc != null">`material_desc`,</if> <if test="customer != null">`customer`,</if> <!-- 其他字段... 继续添加 --> <if test="type != null">`type`,</if> </sql> <sql id="ppElectroplantingList_values"> <if test="area != null and area != ''">#{area},</if> <if test="orderNo != null and orderNo != ''">#{orderNo},</if> <if test="finishedProductNo != null">#{finishedProductNo},</if> <if test="materialDesc != null">#{materialDesc},</if> <if test="customer != null">#{customer},</if> <!-- 其他字段... --> <if test="type != null">#{type},</if> </sql> <insert id="insertPpElectroplantingList" parameterType="com.hwitec.shrcs.bi.domain.PpElectroplantingList" useGeneratedKeys="true" keyProperty="id"> INSERT INTO pp_electroplanting_list <trim prefix="(" suffix=")" suffixOverrides=","> <include refid="ppElectroplantingList_fields"/> </trim> <trim prefix="VALUES (" suffix=")" suffixOverrides=","> <include refid="ppElectroplantingList_values"/> </trim> </insert> ``` --- ## ✅ 总结:问题清单与建议 | 问题 | 是否严重 | 建议 | |------|----------|------| | 所有字段为 null 时生成非法 SQL | ⚠️ 中等 | 在业务层校验,禁止插入对象 | | 字段和值重复写,易出错 | ⚠️ 中等 | 使用 `<sql>` + `<include>` 复用 | | 未过滤字符串 | ⚠️ 中等 | 加 `and str != ''` 判断 | | createTime 等依赖 Java 时间 | ⚠️ 低/中 | 建议数据库设默认值 | | 不适合批量插入 | ⚠️ 高(若用于批量) | 批量时应统一字段 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值