关于业务中Java Stream流的使用
时间:2020-09-07
问题
今天要写的业务逻辑大概是这样:
第一、前端传入一个或一些查询条件,根据这些条件查询plan
表,得到一个planList
。
第二、再根据每个plan
对象里的planID
查询planDetails
表,又得到n个planDetailsList
。
第三、从每个planDetailsList
中取出planDetails
里的详细数据,处理后得到想要的数据返回给planDetailsList
对应的plan
对象
第四、将处理完成的planList
导出到Excel表格中
为了便于理解,我画了个图,如下
解决方案
V1.0
一开始我想的是查询出planList
后,在第二次查询时直接带上处理数据的条件,这样就可以跳过筛选planDetails
这一步,交由数据库帮我筛选数据。画个图大概是这样:
但是这样一来就需要拼接sql语句,还需要写mapper层接口和对应的xml实现,想想就头大,直接Pass
V2.0
换个思路我想那我就还是查询出所有planDetails
后在Java层面处理数据,正好用一下还没实战用过的Stream
流。
既然要用流处理数据的话,只要写个对应的Filter
过滤器就OK 了。
于是我写了如下代码
planDetailsDTOList.stream()
.filter(planDetails -> (过滤条件) )
.forEach(planDetails -> {数据处理} );
然后发现如果这样写就需要进行多次内部迭代才能完成数据的处理,因为我不是只有一种过滤条件,每进行一次过滤就必须重新遍历planDetailsList
这个集合。效率太低,代码也会随着过滤条件的增多而变得过长。
Pass
V3.0
我还是没有改变大体方向,依然将数据放进Java中处理,这次我使用简单粗暴的if-else
判断来进行数据过滤和处理,这样的话就只需要遍历一次集合便可以对所有数据进行分类。
public List<ContainerPlanDTO> dataHandle(List<ContainerPlanDTO> planDTOList){
final Integer[] sum = {0,0,0,0,0};
planDTOList.forEach(planDTO -> {
List<ContainerPlanDetails> planDetailsList = containerPlanDetailsMapper.selectByPlanId(planDTO.getId());
if (ObjectUtils.isEmpty(planDetailsList) || planDetailsList.size() == 0) {
throw new BusinessException("此计划下未查询到详细信息!");
}
planDetailsList.forEach(planDetails -> {
if (ObjectUtils.isEmpty(planDetails.getApplyNum() ) ) {
throw new BusinessException("申请数量为null!");
} else if ("20GP".equals(planDetails.getContainerTypeCode() ) && "24T".equals(planDetails.getCarryWeightCode() ) ) {
sum[0] += planDetails.getApplyNum();
} else if ("20GP".equals(planDetails.getContainerTypeCode() ) && "30T".equals(planDetails.getCarryWeightCode() ) ) {
sum[1] += planDetails.getApplyNum();
} else if ("40GP".equals(planDetails.getContainerTypeCode() ) ) {
sum[2] += planDetails.getApplyNum();
} else if ("40HC".equals(planDetails.getContainerTypeCode() ) ) {
sum[3] += planDetails.getApplyNum();
} else {
sum[4] += planDetails.getApplyNum();
}
});
planDTO.setTypePlan2024(sum[0]);
planDTO.setTypePlan2030(sum[1]);
planDTO.setTypePlan40GP(sum[2]);
planDTO.setTypePlan40HC(sum[3]);
planDTO.setTypePlanOther(sum[4]);
});
return planDTOList;
}
果然,有时候最好的方法不一定是最复杂的。
其他
1、在lambda表达式中无法传入非Final
的值,我们就可以在外部声明一个Final的数组
进行值的传递
2、单例模式下不要声明类中非Final
的全局变量,非常容易
出现并发问题
!
3、还有就是一个多条件查询的实现,也非常简单,在mapper.xml中使用动态Sql进行拼接就可以实现
代码如下:
mapper接口
@Repository
public interface ContainerPlanMapper {
List<ContainerPlan> selectBySimple(ContainerPlan containerPlan);
}
mapper.xml
<select id="selectBySimple" parameterType="com.wisdom.domain.container.ContainerPlan" resultType="com.wisdom.domain.container.ContainerPlan">
select * from container_plan where 1 = 1
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="planMonth != null and planMonth != ''">
and plan_month = #{planMonth}
</if>
<if test="usedPlaceId != null and usedPlaceId != ''">
and used_place_id = #{usedPlaceId}
</if>
<if test="returnPlaceId != null and returnPlaceId != ''">
and return_place_id = #{returnPlaceId}
</if>
<if test="businessTypeCode != null and businessTypeCode != ''">
and business_type_code = #{businessTypeCode}
</if>
<if test="carriageTypeCode != null and carriageTypeCode != ''">
and carriage_type_code = #{carriageTypeCode}
</if>
<if test="customerId != null and customerId != ''">
and customer_id = #{customerId}
</if>
<if test="varietiesCode != null and varietiesCode != ''">
and varieties_code = #{varietiesCode}
</if>
<if test="varietiesName != null and varietiesName != ''">
and varieties_name LIKE '%'#{varietiesName}'%'
</if>
<if test="containerBelongCode != null and containerBelongCode != ''">
and container_belong_code = #{containerBelongCode}
</if>
<if test="companyId != null and companyId != ''">
and company_id = #{companyId}
</if>
</select>
这里只写了部分条件,确定的条件可以使用=
,模糊条件就使用like
,where = 1
是保证在所有的if
判断都不成立时,sql语句不会因为出现语法错误而不能执行。
3.1、还有就是关键字查询,实现原理和这个高级查询非常相似,只不过是将SearchKey
和所有字段进行like
判断。
大概就是这样:hhhh
<select id="selectPage" resultMap="ResultMapWithBLOBs">
select
<include refid="Page_Column_List"/>,
<include refid="Blob_Column_List"/>
from oper_sale_ship oss
left join oper_sale_ship_fee_status ossfs on ossfs.order_no = oss.order_no
where 1=1 AND oss.delete_flag = 0
<if test="searchKey != null and searchKey != ''">
and (
oss.order_no LIKE CONCAT('%',#{searchKey},'%') or
cust_name LIKE CONCAT('%',#{searchKey},'%') or
contract_no LIKE CONCAT('%',#{searchKey},'%') or
shipper LIKE CONCAT('%',#{searchKey},'%') or
consignee LIKE CONCAT('%',#{searchKey},'%') or
notify_party LIKE CONCAT('%',#{searchKey},'%') or
route_way LIKE CONCAT('%',#{searchKey},'%') or
ssl_code LIKE CONCAT('%',#{searchKey},'%') or
creator_name LIKE CONCAT('%',#{searchKey},'%') or
canvasser_name LIKE CONCAT('%',#{searchKey},'%') or
business_man_name LIKE CONCAT('%',#{searchKey},'%') or
oper_name LIKE CONCAT('%',#{searchKey},'%') or
service_man_name LIKE CONCAT('%',#{searchKey},'%') or
load_port_name LIKE CONCAT('%',#{searchKey},'%') or
pod_name LIKE CONCAT('%',#{searchKey},'%') or
finl_dest_name LIKE CONCAT('%',#{searchKey},'%') or
chinese_name LIKE CONCAT('%',#{searchKey},'%') or
source_name LIKE CONCAT('%',#{searchKey},'%') or
oss.main_business_type_name LIKE CONCAT('%',#{searchKey},'%') or
oss.bl_no LIKE CONCAT('%',#{searchKey},'%') or
oss.bgbl_no LIKE CONCAT('%',#{searchKey},'%') or
oss.ref_no_a LIKE CONCAT('%',#{searchKey},'%') or
oss.ship_vessel LIKE CONCAT('%',#{searchKey},'%') or
oss.ship_voyage LIKE CONCAT('%',#{searchKey},'%')
)
</if>
Q.E.D.