符合 SonarQube 的解决方案,增加单元格值
SonarQube-compliant solution, increment cell value
我正在使用 Apache POI 创建一个 excel 形式的 Java POJO class。
POJO 有 65 个字段需要在创建 POJO 时填充。
我想到的一种方法是 -
int i = 0;
hssfRow.createCell(i++).setCellValue(POJO.getField1());
hssfRow.createCell(i++).setCellValue(POJO.getField2());
hssfRow.createCell(i++).setCellValue(POJO.getField3());
.....
hssfRow.createCell(i++).setCellValue(POJO.getField65());
上述方法的缺点是 SonarQube 说它不符合以下原因
Extract this increment or decrement operator into a dedicated
statement
第一个问题是这里为什么不建议使用i++
?
此外,是否建议在单独的常量 class 中声明从 1 到 65 的常量并使用它代替 i++
(即 hssfRow.createCell(Constant.ONE)
)?
除了这个解决方案之外,还有其他更合规且更好的方法吗?
恕我直言,您可以将其标记为误报。该问题的 stated reasons 是
- 它会严重影响代码的可读性。
- 它在语句中引入了额外的副作用,可能会出现未定义的行为。
- 将这些运算符与任何其他算术运算符分开使用会更安全。
鉴于您当前代码的情况,我认为它们是无效的。代码是完全可读的,没有未定义的行为,我没有看到任何安全问题。
我可以这样:
private static final Map<Integer, Function<POJO, TypeOfCellValue>> cellDataProviders = new HashMap<>();
static{
cellDataProviders.put(1, POJO -> POJO.getField1());
cellDataProviders.put(2, POJO -> POJO.getField2());
...
}
并在代码中使用:
IntStream.range(1, cellDataProviders.size()).foreach( i -> hssfRow.createCell(i).setCellValue(cellDataProviders.get(i).apply(POJO)));
或使用传统的 for 循环:
for(int i = 0; i < cellDataProviders.size(); i++){
hssfRow.createCell(i).setCellValue(cellDataProviders.get(i).apply(POJO));
}
从POJO到cell的映射已经和数据填充代码分离了。
因为它是误报,您可以使用 @SuppressWarnings("squid:S...")
或 //NOSONAR
:
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField1());
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField2());
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField3());
...
然而,将代码从动地更改为更清楚:
hssfRow.createCell(i).setCellValue(POJO.getField1()); ++i;
hssfRow.createCell(i).setCellValue(POJO.getField2()); ++i;
hssfRow.createCell(i).setCellValue(POJO.getField3()); ++i;
...
不疼。
游戏时间
可以使用可变参数方法隐藏索引。
假设POJO对象变量为pojo
及其classPojo
.
fillCells(hssfRow, pojo,
Pojo::getField1,
Pojo::getField2,
p -> createDateCellValue(p.getField2()),
Pojo::getField4,
Pojo::getField5,
p -> f(pojo),
Pojo::getField7):
void fillCells(Row hssfRow, Pojo pojo, Function<Pojo, CellValue>... cellProviders) {
for (int i = 0; i < cellProviders.length; ++i) {
hssfRow.createCell(i).setCellValue(cellProviders[i].apply(pojo));
}
}
这不是那么灵活,但会删除一些重复的内容 hssfRow.createCell
。
我正在使用 Apache POI 创建一个 excel 形式的 Java POJO class。
POJO 有 65 个字段需要在创建 POJO 时填充。
我想到的一种方法是 -
int i = 0;
hssfRow.createCell(i++).setCellValue(POJO.getField1());
hssfRow.createCell(i++).setCellValue(POJO.getField2());
hssfRow.createCell(i++).setCellValue(POJO.getField3());
.....
hssfRow.createCell(i++).setCellValue(POJO.getField65());
上述方法的缺点是 SonarQube 说它不符合以下原因
Extract this increment or decrement operator into a dedicated statement
第一个问题是这里为什么不建议使用i++
?
此外,是否建议在单独的常量 class 中声明从 1 到 65 的常量并使用它代替 i++
(即 hssfRow.createCell(Constant.ONE)
)?
除了这个解决方案之外,还有其他更合规且更好的方法吗?
恕我直言,您可以将其标记为误报。该问题的 stated reasons 是
- 它会严重影响代码的可读性。
- 它在语句中引入了额外的副作用,可能会出现未定义的行为。
- 将这些运算符与任何其他算术运算符分开使用会更安全。
鉴于您当前代码的情况,我认为它们是无效的。代码是完全可读的,没有未定义的行为,我没有看到任何安全问题。
我可以这样:
private static final Map<Integer, Function<POJO, TypeOfCellValue>> cellDataProviders = new HashMap<>();
static{
cellDataProviders.put(1, POJO -> POJO.getField1());
cellDataProviders.put(2, POJO -> POJO.getField2());
...
}
并在代码中使用:
IntStream.range(1, cellDataProviders.size()).foreach( i -> hssfRow.createCell(i).setCellValue(cellDataProviders.get(i).apply(POJO)));
或使用传统的 for 循环:
for(int i = 0; i < cellDataProviders.size(); i++){
hssfRow.createCell(i).setCellValue(cellDataProviders.get(i).apply(POJO));
}
从POJO到cell的映射已经和数据填充代码分离了。
因为它是误报,您可以使用 @SuppressWarnings("squid:S...")
或 //NOSONAR
:
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField1());
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField2());
//NOSONAR
hssfRow.createCell(i++).setCellValue(POJO.getField3());
...
然而,将代码从动地更改为更清楚:
hssfRow.createCell(i).setCellValue(POJO.getField1()); ++i;
hssfRow.createCell(i).setCellValue(POJO.getField2()); ++i;
hssfRow.createCell(i).setCellValue(POJO.getField3()); ++i;
...
不疼。
游戏时间
可以使用可变参数方法隐藏索引。
假设POJO对象变量为pojo
及其classPojo
.
fillCells(hssfRow, pojo,
Pojo::getField1,
Pojo::getField2,
p -> createDateCellValue(p.getField2()),
Pojo::getField4,
Pojo::getField5,
p -> f(pojo),
Pojo::getField7):
void fillCells(Row hssfRow, Pojo pojo, Function<Pojo, CellValue>... cellProviders) {
for (int i = 0; i < cellProviders.length; ++i) {
hssfRow.createCell(i).setCellValue(cellProviders[i].apply(pojo));
}
}
这不是那么灵活,但会删除一些重复的内容 hssfRow.createCell
。