如何在不使用break或continue语句的情况下遍历所有非空行



我想从Excel文件中获取数据。我使用while循环、迭代器和hasNext()方法来遍历所有行。我的问题是:有时在有数据的行之后会有空的行(可能是单元格类型字符串和值"或null),我不想对其进行迭代。所以我添加了方法isCellEmpty():

public static boolean isCellEmpty(final Cell cell) {
    if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
        return true;
    }
    if (cell.getCellType() == Cell.CELL_TYPE_STRING && cell.getStringCellValue().isEmpty()) {
        return true;
    }
    return false;
}

并在主方法中的主演while循环后添加

while (rowIterator.hasNext()) {
    row = rowIterator.next();
    if (isCellEmpty(row.getCell(2))) {
        break;
    }
    // some code ...
}

但现在我有一个中断声明。如何在不使用break或continue的情况下迭代所有非空行?现在(休息时)我的算法工作正常——我正在获取我需要的数据。我只是想知道是否可以在没有breakcontinue的情况下编写代码。

如果您想保持while循环并避免中断,最简单的可能是状态布尔值,例如

boolean inData = true;
while (rowIterator.hasNext() && inData) {
   row = rowIterator.next();
   if (row == null || isCellEmpty(row.getCell(2))) {
      inData = false;
   } else {
      // Use the row
   }
}

否则,我建议阅读Apache POI关于在行和单元格上迭代的文档,您可以采取其他方法,这些方法可能会更好!

哦,别忘了行可以是null,所以在尝试获取单元格

之前需要检查一下

看起来POI没有任何特性或特性可以在非空行上迭代。

POIS的开发人员发布了关于这个主题的帖子。查看Apache POI HSSF+XSSF部分在行和单元格上迭代单元格上迭代,并控制缺失/空白单元格

请注意,POI与Iterator一起工作,因此我将使用Apache Commons Collections中的Apache IteratorUtils,而不是循环,由于某些传递依赖关系,它可能已经在类路径中了。

为了使您的代码更干净、可读,该解决方案将类似于

    import org.apache.commons.collections.Predicate;
    public class ValidRowPredicate implements Predicate{
        @Override
        public boolean evaluate(Object object) {
           Row row = (Row) object;
           Cell cell = row.getCell(2);
           if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
              return false;
           } else if (cell.getCellType() == Cell.CELL_TYPE_STRING && 
                      cell.getStringCellValue().isEmpty()) {
             return false;
          }
          return true;
        }
    }

消费者看起来像

    Iterator<Row> rawIterator = rowIterator;
    Iterator<Row> cleanIterator = IteratorUtils.filteredIterator(rawIterator , new ValidRowPredicate());
    while(cleanIterator.hasNext()){
       Row row = cleanIterator.next();
       // some code
    } 

您可能认为我们正在迭代book两次,但我们没有。

第一个循环确实如此,但进一步的迭代是在有效行的子集上进行的。此外,我们使可重复使用验证空单元格#2。我们还得到了一个可靠的迭代程序,它只有有效和可计算的条目。

谓词给出了很多可能性。类似于通过继承或组合链接谓词。

它的成本实际上是,第一个循环遍布主迭代程序。但结果是值得的。

IteratorUtils作为CollectionUtils是非常好的utils

不确定我是否答对了问题,你在找这样的东西吗?

Row row;
while (rowIterator.hasNext() 
          && !isCellEmpty((row = rowIterator.next()).getCell(2))) {
    // do something with row
}

这将处理所有行,直到找到一个空单元格并结束循环。

您有几个选项可以在不使用break:的情况下退出循环

  • 使用一些其他控制流,例如returnthrow
  • 为环路保护添加一个额外条件:

    boolean shouldContinue = true;
    while (shouldContinue && rowIterator.hasNext()) {
      row = rowIterator.next();
      if (isCellEmpty(...)) {
        shouldContinue = false;
      }
    }
    
  • 耗尽循环体内的迭代器:

    while (rowIterator.hasNext()) {
      row = rowIterator.next();
      if (isCellEmpty(...)) {
        while (rowIterator.hasNext()) rowIterator.next();
      }
    }
    

或者只使用break。还不错。

将函数isCellEmpty()改为使用switch,而不是使用nested if-else

public static boolean isCellEmpty(final Cell cell) {
   switch(cell.getCellType()){
       case Cell.CELL_TYPE_BLANK :
       case cell.CELL_TYPE_STRING :
          if(StringUtils.isBlank(cell.getCellValue())
               return true;
          else
               return false;
         break;
       default :
               return false;
     break;               
   }

}

现在使用这个代码

boolean hasCellData= true;
while (rowIterator.hasNext() && hasCellData) {
   row = rowIterator.next();  //iterate through each rows.
   if (row == null || isCellEmpty(row.getCell(2))) {
      hasData = false;
   } else {
      //if row contains data then do your stuffs.
   }
}

如果一行包含null值,则此while (rowIterator.hasNext() && hasCellData)循环将在某个时间点停止。它从不检查此行之外是否有一些数据。

示例:-假设在工作表中,数据从第1行填充到第50行,但中间有一个第30行为空,则这不会在第30行之后重复。

谢谢。

可能过于简单,但以下内容还不够吗?

while (rowIterator.hasNext()) {
    row = rowIterator.next();
    if (!isCellEmpty(row.getCell(2))) {
        // some code ...
    }
}

如果我们想在遇到空行/单元格时停止迭代,可以采取以下方法:

for(boolean shouldContinue = true; shouldContinue && rowIterator.hasNext(); ) {
   if (!isCellEmpty(row.getCell(2))) {
        // some code ...
    } else {
        shouldContinue = false;
    }
}

能够根据Laiv的答案删除空行。我已经修改以支持通过Row。这是修改后的答案

import org.apache.commons.collections4.Predicate;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
public class ValidRowPredicate implements Predicate<Row> {
    @Override
    public boolean evaluate(Row row) {
        Cell cell = row.getCell(2);
        if (cell == null || cell.getCellType() == CellType.BLANK) {
            return false;
        } else if (cell.getCellType() == CellType.STRING &&
                cell.getStringCellValue().isEmpty()) {
            return false;
        }
        return true;
    }
}

学分转到Laiv

最新更新