通过 Java 8 个流 API 进行 StringBuilder 操作

StringBuilder manipulation via Java 8 Streams API

我很难从 StringBuilder 中删除一些字符。该方法工作正常。但是,我想通过 Java-8 流 API 实现相同的目的。当前代码冗长。有什么方法可以通过 Java 8 个流 API 重构第二个方法 removeCarryReturnsCharacters() 吗?

private static StringBuilder readEntireFileUsingStream(Path filePath) throws IOException {

    StringBuilder data = new StringBuilder(String.valueOf(Files.readAllLines(filePath, StandardCharsets.ISO_8859_1)));

    return removeCarryReturnsCharacters(data);

}

private static StringBuilder removeCarryReturnsCharacters(StringBuilder fileData){

    int endIndex = 1012;
    String needToRemove = "";
    long totDataChunkCount = fileData.length()/1014;
    long delCounter = 1;
    try{
        while (delCounter < totDataChunkCount) {
            needToRemove = fileData.substring(endIndex, endIndex + 2);
            if (needToRemove.equals("^^")) {
                fileData.delete(endIndex, endIndex + 2);
            }
            endIndex += 1012;
            delCounter++;
        }
    }catch(StringIndexOutOfBoundsException exp){
        throw exp;
    }
    return fileData;
}

由于缺少 Stream API,当前代码并不冗长,但有大量不必要的操作:

  • 初始分配 needToRemove = ""; 已过时
  • 您正在维护两个冗余循环变量,delCounterendIndex
  • 你正在使用 while 循环,尽管你有一个带有初始语句、条件和递增操作的经典计数循环,确切地说,for 循环是为
  • 创建的
  • 您使用的 long 变量绝对不会超过 int 值范围
  • 你有一个过时的 try … catch 块只是重新抛出捕获的异常
  • 您不需要 needToRemove 变量来保存对象以供一次性使用;你可以简单地检查 if(fileData.substring(endIndex, endIndex + 2).equals("^^")) 或者,我更喜欢只检查两个字符,
    if(fileData.charAt(endIndex)=='^' && fileData.charAt(endIndex+1)=='^')

解决所有这些问题将使方法变为

private static StringBuilder removeCarryReturnsCharacters(StringBuilder fileData) {
    for(int endIndex = 1012; endIndex < fileData.length(); endIndex += 1012)
        if(fileData.charAt(endIndex) == '^' && fileData.charAt(endIndex+1) == '^')
            fileData.delete(endIndex, endIndex + 2);
    return fileData;
}

我认为重写循环以使用 Stream 不会有任何额外的好处 API。

private static StringBuilder removeCarryReturnsCharacters(StringBuilder fileData) {
    Stream.iterate(1012, i -> i + 1012)
          .limit(fileData.length() / 1014)
          .sorted(Collections.reverseOrder())
          .forEach(e -> {
                if (fileData.substring(e, e + 2).equals("^^")) {
                    fileData.delete(e, e + 2);
                }
          });
    return fileData;
}

您似乎正试图从原始文件的各个行中删除 ^^。您可以仅使用 File.linesStream.map:

来解决这个问题
List<String> lines = Files.lines(filePath, StandardCharsets.ISO_8859_1)
.map(line -> {
    if (line.charAt(endIndex) == '^' && line.charAt(endIndex + 1) == '^') {
        return new StringBuilder(line).delete(endIndex, endIndex + 2).toString();
    } else {
        return line;
    }
})
.collect(Collectors.toList());

我想这可能比

性能更差
new StringBuilder(String.valueOf(Files.readAllLines(...)))

However readAllLines read all lines into a List, but lines populates lazily as the stream is consumed.

在这种情况下,如果我们使用一个大 StringBuilder - 所有数据都先 读取 稍后 处理。相反 - 在 File.lines 的情况下,数据在 同时被处理和读取 。在文件的最后一行被流管道读取和处理后 - 将有一个删除了 ^^ 个字符的文件行列表。