首页 / JAVA / Java 代码精简之道 (中)
Java 代码精简之道 (中)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java 代码精简之道 (中),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9167字,纯文字阅读大概需要14分钟。
内容图文
1.利用自身方法
1.1.利用构造方法
构造方法,可以简化对象的初始化和设置属性操作。对于属性字段较少的类,可以自定义构造方法。
普通:
@Getter
@Setter
@ToString
public?class?PageDataVO<T>?{
????private?Long?totalCount;
????private?List<T>?dataList;
}
PageDataVO<UserVO>?pageData?=?new?PageDataVO<>();
pageData.setTotalCount(totalCount);
pageData.setDataList(userList);
return?pageData;
精简:
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public?class?PageDataVO<T>?{
????private?Long?totalCount;
????private?List<T>?dataList;
}
return?new?PageDataVO<>(totalCount,?userList);
注意:如果属性字段被替换时,存在构造函数初始化赋值问题。比如把属性字段title替换为 nickname ,由于构造函数的参数个数和类型不变,原有构造函数初始化语句不会报错,导致把原title值赋值给 nickname 。如果采用 Setter 方法赋值,编译器会提示错误并要求修复。
1.2.利用 Set 的 add 方法
利用 Set 的 add 方法的返回值,可以直接知道该值是否已经存在,可以避免调用 contains 方法判断存在。
普通:
以下案例是进行用户去重转化操作,需要先调用 contains 方法判断存在,后调用add方法进行添加。
Set<Long>?userIdSet?=?new?HashSet<>();
List<UserVO>?userVOList?=?new?ArrayList<>();
for?(UserDO?userDO?:?userDOList)?{
????if?(!userIdSet.contains(userDO.getId()))?{
????????userIdSet.add(userDO.getId());
????????userVOList.add(transUser(userDO));
????}
}
精简:
Set<Long>?userIdSet?=?new?HashSet<>();
List<UserVO>?userVOList?=?new?ArrayList<>();
for?(UserDO?userDO?:?userDOList)?{
????if?(userIdSet.add(userDO.getId()))?{
????????userVOList.add(transUser(userDO));
????}
}
1.3.利用 Map 的 computeIfAbsent 方法
利用 Map 的 computeIfAbsent 方法,可以保证获取到的对象非空,从而避免了不必要的空判断和重新设置值。
普通:
Map<Long,?List<UserDO>>?roleUserMap?=?new?HashMap<>();
for?(UserDO?userDO?:?userDOList)?{
????Long?roleId?=?userDO.getRoleId();
????List<UserDO>?userList?=?roleUserMap.get(roleId);
????if?(Objects.isNull(userList))?{
????????userList?=?new?ArrayList<>();
????????roleUserMap.put(roleId,?userList);
????}
????userList.add(userDO);
}
精简:
Map<Long,?List<UserDO>>?roleUserMap?=?new?HashMap<>();
for?(UserDO?userDO?:?userDOList)?{
????roleUserMap.computeIfAbsent(userDO.getRoleId(),?key?->?new?ArrayList<>())
????????.add(userDO);
}
1.4.利用链式编程
链式编程,也叫级联式编程,调用对象的函数时返回一个this对象指向对象本身,达到链式效果,可以级联调用。链式编程的优点是:编程性强、可读性强、代码简洁。
普通
StringBuilder?builder?=?new?StringBuilder(96);
builder.append("select?id,?name?from?");
builder.append(T_USER);
builder.append("?where?id?=?");
builder.append(userId);
builder.append(";");
精简:
StringBuilder?builder?=?new?StringBuilder(96);
builder.append("select?id,?name?from?")
????.append(T_USER)
????.append("?where?id?=?")
????.append(userId)
????.append(";");
2.利用工具方法
2.1.避免空值判断
普通:
if?(userList?!=?null?&&?!userList.isEmpty())?{
????//?TODO:?处理代码
}
精简:
if?(CollectionUtils.isNotEmpty(userList))?{
????//?TODO:?处理代码
}
2.2.避免条件判断
普通:
double?result;
if?(value?<=?MIN_LIMIT)?{
????result?=?MIN_LIMIT;
}?else?{
????result?=?value;
}
精简:
double?result?=?Math.max(MIN_LIMIT,?value);
3.3.简化赋值语句
普通:
public?static?final?List<String>?ANIMAL_LIST;
static?{
????List<String>?animalList?=?new?ArrayList<>();
????animalList.add("dog");
????animalList.add("cat");
????animalList.add("tiger");
????ANIMAL_LIST?=?Collections.unmodifiableList(animalList);
}
精简:
//?JDK流派
public?static?final?List<String>?ANIMAL_LIST?=?Arrays.asList("dog",?"cat",?"tiger");
//?Guava流派
public?static?final?List<String>?ANIMAL_LIST?=?ImmutableList.of("dog",?"cat",?"tiger");
注意:Arrays.asList 返回的 List 并不是 ArrayList ,不支持 add 等变更操作。
2.4.简化数据拷贝
普通:
UserVO?userVO?=?new?UserVO();
userVO.setId(userDO.getId());
userVO.setName(userDO.getName());
...
userVO.setDescription(userDO.getDescription());
userVOList.add(userVO);
精简:
UserVO?userVO?=?new?UserVO();
BeanUtils.copyProperties(userDO,?userVO);
userVOList.add(userVO);
2.5.简化异常断言
普通:
if?(Objects.isNull(userId))?{
????throw?new?IllegalArgumentException("用户标识不能为空");
}
精简:
Assert.notNull(userId, "用户标识不能为空");
注意:可能有些插件不认同这种判断,导致使用该对象时会有空指针警告。
2.6.简化测试用例
把测试用例数据以 JSON 格式存入文件中,通过 JSON 的 parseObject 和 parseArray 方法解析成对象。虽然执行效率上有所下降,但可以减少大量的赋值语句,从而精简了测试代码。
普通:
@Test
public?void?testCreateUser()?{
????UserCreateVO?userCreate?=?new?UserCreateVO();
????userCreate.setName("Changyi");
????userCreate.setTitle("Developer");
????userCreate.setCompany("AMAP");
????...
????Long?userId??=?userService.createUser(OPERATOR,?userCreate);
????Assert.assertNotNull(userId,?"创建用户失败");
}
精简:
@Test
public?void?testCreateUser()?{
????String?jsonText?=?ResourceHelper.getResourceAsString(getClass(),?"createUser.json");
????UserCreateVO?userCreate?=?JSON.parseObject(jsonText,?UserCreateVO.class);
????Long?userId??=?userService.createUser(OPERATOR,?userCreate);
????Assert.assertNotNull(userId,?"创建用户失败");
}
建议:JSON 文件名最好以被测试的方法命名,如果有多个版本可以用数字后缀表示。
3.利用数据结构
3.1.利用数组简化
对于固定上下限范围的 if-else 语句,可以用数组+循环来简化。
普通:
public?static?int?getGrade(double?score)?{
????if?(score?>=?90.0D)?{
????????return?1;
????}
????if?(score?>=?80.0D)?{
????????return?2;
????}
????if?(score?>=?60.0D)?{
????????return?3;
????}
????if?(score?>=?30.0D)?{
????????return?4;
????}
????return?5;
}
精简:
private?static?final?double[]?SCORE_RANGES?=?new?double[]?{90.0D,?80.0D,?60.0D,?30.0D};
public?static?int?getGrade(double?score)?{
????for?(int?i?=?0;?i?<?SCORE_RANGES.length;?i++)?{
????????if?(score?>=?SCORE_RANGES[i])?{
????????????return?i?+?1;
????????}
????}
????return?SCORE_RANGES.length?+?1;
}
思考:上面的案例返回值是递增的,所以用数组简化是没有问题的。但是,如果返回值不是递增的,能否用数组进行简化呢?答案是可以的,请自行思考解决。
3.2.利用 Map 简化
对于映射关系的 if-else 语句,可以用Map来简化。此外,此规则同样适用于简化映射关系的 switch 语句。
普通:
public?static?String?getBiologyClass(String?name)?{
????switch?(name)?{
????????case?"dog"?:
????????????return?"animal";
????????case?"cat"?:
????????????return?"animal";
????????case?"lavender"?:
????????????return?"plant";
????????...
????????default?:
????????????return?null;
????}
}
精简:
private?static?final?Map<String,?String>?BIOLOGY_CLASS_MAP
????=?ImmutableMap.<String,?String>builder()
????????.put("dog",?"animal")
????????.put("cat",?"animal")
????????.put("lavender",?"plant")
????????...
????????.build();
public?static?String?getBiologyClass(String?name)?{
????return?BIOLOGY_CLASS_MAP.get(name);
}
已经把方法简化为一行代码,其实都没有封装方法的必要了。
3.3.利用容器类简化
Java 不像 Python 和 Go ,方法不支持返回多个对象。如果需要返回多个对象,就必须自定义类,或者利用容器类。常见的容器类有 Apache 的 Pair 类和 Triple 类, Pair 类支持返回 2 个对象, Triple 类支持返回 3 个对象
普通:
@Setter
@Getter
@ToString
@AllArgsConstructor
public?static?class?PointAndDistance?{
????private?Point?point;
????private?Double?distance;
}
public?static?PointAndDistance?getNearest(Point?point,?Point[]?points)?{
????//?计算最近点和距离
????...
????//?返回最近点和距离
????return?new?PointAndDistance(nearestPoint,?nearestDistance);
}
精简:
public?static?Pair<Point,?Double>?getNearest(Point?point,?Point[]?points)?{
????//?计算最近点和距离
????...
????//?返回最近点和距离
????return?ImmutablePair.of(nearestPoint,?nearestDistance);
}
3.4.利用 ThreadLocal 简化
ThreadLocal 提供了线程专有对象,可以在整个线程生命周期中随时取用,极大地方便了一些逻辑的实现。用 ThreadLocal 保存线程上下文对象,可以避免不必要的参数传递。
普通:
由于 DateFormat 的 format 方法线程非安全(建议使用替代方法),在线程中频繁初始化 DateFormat 性能太低,如果考虑重用只能用参数传入 DateFormat 。例子如下:
public?static?String?formatDate(Date?date,?DateFormat?format)?{
????return?format.format(date);
}
public?static?List<String>?getDateList(Date?minDate,?Date?maxDate,?DateFormat?format)?{
????List<String>?dateList?=?new?ArrayList<>();
????Calendar?calendar?=?Calendar.getInstance();
????calendar.setTime(minDate);
????String?currDate?=?formatDate(calendar.getTime(),?format);
????String?maxsDate?=?formatDate(maxDate,?format);
????while?(currDate.compareTo(maxsDate)?<=?0)?{
????????dateList.add(currDate);
????????calendar.add(Calendar.DATE,?1);
????????currDate?=?formatDate(calendar.getTime(),?format);
????}
????return?dateList;
}
精简:可能你会觉得以下的代码量反而多了,如果调用工具方法的地方比较多,就可以省下一大堆 DateFormat 初始化和传入参数的代码。
private?static?final?ThreadLocal<DateFormat>?LOCAL_DATE_FORMAT?=?new?ThreadLocal<DateFormat>()?{
????@Override
????protected?DateFormat?initialValue()?{
????????return?new?SimpleDateFormat("yyyyMMdd");
????}
};
public?static?String?formatDate(Date?date)?{
????return?LOCAL_DATE_FORMAT.get().format(date);
}
public?static?List<String>?getDateList(Date?minDate,?Date?maxDate)?{
????List<String>?dateList?=?new?ArrayList<>();
????Calendar?calendar?=?Calendar.getInstance();
????calendar.setTime(minDate);
????String?currDate?=?formatDate(calendar.getTime());
????String?maxsDate?=?formatDate(maxDate);
????while?(currDate.compareTo(maxsDate)?<=?0)?{
????????dateList.add(currDate);
????????calendar.add(Calendar.DATE,?1);
????????currDate?=?formatDate(calendar.getTime());
????}
????return?dateList;
}
注意:ThreadLocal 有一定的内存泄露的风险,尽量在业务代码结束前调用 remove 方法进行数据清除。
内容总结
以上是互联网集市为您收集整理的Java 代码精简之道 (中)全部内容,希望文章能够帮你解决Java 代码精简之道 (中)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。