如何使用Java 8统计字符串中连续字符的出现次数?
Java 8实现连续字符计数
要在Java 8中实现连续字符的出现次数统计,核心是利用流式操作结合状态跟踪——因为需要按顺序处理每个字符,记录当前连续字符的计数。以下是两种可行的实现方式:
方法一:用IntStream.collect直接操作StringBuilder
这种方式直接在收集器里维护StringBuilder,每次处理字符时判断是否与前一个字符相同,动态修改或追加内容:
String str = "aabbbccddbb"; String result = IntStream.range(0, str.length()) .collect(StringBuilder::new, (sb, index) -> { char currentChar = str.charAt(index); if (index == 0) { // 第一个字符,直接初始化计数和字符 sb.append(1).append(currentChar); } else { char prevChar = str.charAt(index - 1); if (currentChar == prevChar) { // 字符连续,找到最后面的数字部分并递增 int lastDigitStart = sb.length() - 1; while (lastDigitStart >= 0 && Character.isDigit(sb.charAt(lastDigitStart))) { lastDigitStart--; } String countStr = sb.substring(lastDigitStart + 1); int newCount = Integer.parseInt(countStr) + 1; // 替换原数字为递增后的结果 sb.replace(lastDigitStart + 1, sb.length(), String.valueOf(newCount)); } else { // 字符不连续,追加新的计数和字符 sb.append(1).append(currentChar); } } }, StringBuilder::append) .toString(); System.out.println(result); // 输出:2a3b2c2d2b
方法二:用reduce自定义状态对象
通过自定义状态类保存当前字符、计数和结果缓冲区,利用reduce累积状态,状态管理更清晰:
// 定义状态类,跟踪当前连续字符的计数和结果 static class ContinuousCharCount { char currentChar; int count; StringBuilder resultBuffer = new StringBuilder(); } public static void main(String[] args) { String str = "aabbbccddbb"; if (str.isEmpty()) { System.out.println(""); return; } ContinuousCharCount finalState = IntStream.range(0, str.length()) .reduce(new ContinuousCharCount(), (state, index) -> { char c = str.charAt(index); if (index == 0) { // 初始化第一个字符的状态 state.currentChar = c; state.count = 1; } else { if (c == state.currentChar) { // 字符连续,计数递增 state.count++; } else { // 字符中断,将当前累积结果写入缓冲区 state.resultBuffer.append(state.count).append(state.currentChar); // 更新状态为新字符 state.currentChar = c; state.count = 1; } } return state; }, (state1, state2) -> { // 并行流场景的合并逻辑(串行流可简化,但保留更健壮) if (state1.resultBuffer.length() == 0) { return state2; } if (state2.resultBuffer.length() == 0) { state1.resultBuffer.append(state2.count).append(state2.currentChar); return state1; } // 检查首尾字符是否连续,连续则合并计数 char lastCharOfState1 = state1.currentChar; char firstCharOfState2 = state2.currentChar; if (lastCharOfState1 == firstCharOfState2) { state1.count += state2.count; state1.resultBuffer.append(state2.resultBuffer.substring(state2.resultBuffer.indexOf(String.valueOf(firstCharOfState2)) + 1)); } else { state1.resultBuffer.append(state1.count).append(state1.currentChar); state1.resultBuffer.append(state2.resultBuffer); } return state1; }); // 写入最后一组连续字符的结果 finalState.resultBuffer.append(finalState.count).append(finalState.currentChar); System.out.println(finalState.resultBuffer.toString()); // 输出:2a3b2c2d2b }
注意事项
- 两种方式都处理了空字符串和单个字符的边界情况;
- 方法一代码紧凑,但修改
StringBuilder的操作相对繁琐;方法二状态管理更清晰,适合扩展复杂逻辑; - 若不需要并行处理,可简化
reduce的第三个合并参数,但保留它能让代码更健壮。
内容的提问来源于stack exchange,提问作者Deepak Ram
相关产品推荐
相关产品推荐

