如何仅用Java Streams对拼接字符串执行算术运算?
纯Stream操作实现表达式计算方案
嘿,我完全理解你想要只用Stream的filter、reduce这类操作直接计算表达式结果的需求——你之前的尝试用了外部List来存操作符,这不仅不符合"仅用Stream操作"的要求,还会带来线程安全隐患(要是用并行流的话问题更大)。咱们换个思路,用自定义的累积状态来完成这个计算,全程不需要额外的集合存储:
首先,我们需要一个辅助类来跟踪计算过程中的状态:当前的计算结果,以及等待和下一个数字结合的操作符。这个类只用来在Stream的reduce操作里传递状态,不会暴露到外部:
private static class CalcState { int currentResult; String pendingOperator; // 初始化第一个数字的状态 CalcState(int initialResult) { this.currentResult = initialResult; this.pendingOperator = null; } // 带有待执行操作符的状态 CalcState(int result, String op) { this.currentResult = result; this.pendingOperator = op; } }
然后,我们需要一个辅助方法来执行具体的运算,这个你应该已经有了,我这里写个标准版本:
private static int calculate(int a, int b, String operator) { return switch (operator) { case "+" -> a + b; case "-" -> a - b; case "*" -> a * b; case "/" -> a / b; // 注意整数除法的截断问题,按需调整 default -> throw new IllegalArgumentException("不支持的操作符: " + operator); }; }
接下来就是核心的Stream操作了,我们用reduce来累积状态,全程不需要额外的List:
// 假设你的inputStream是拆分好的元素流,比如Stream.of("1", "+", "5", "*", "2", "-", "4") Optional<CalcState> finalState = inputStream.reduce( // 初始状态:默认结果0,没有待执行操作符 new CalcState(0), // 累积器:处理每个流元素,更新状态 (state, element) -> { if (Character.isDigit(element.charAt(0))) { int num = Integer.parseInt(element); if (state.pendingOperator == null) { // 第一个数字,直接初始化结果 return new CalcState(num); } else { // 用上一个保存的操作符计算新结果,清空待执行操作符 int newResult = calculate(state.currentResult, num, state.pendingOperator); return new CalcState(newResult, null); } } else { // 遇到操作符,保存起来等待下一个数字 return new CalcState(state.currentResult, element); } }, // 合并器:并行流场景下合并两个状态,顺序流可以忽略,但加上更健壮 (state1, state2) -> { if (state2.pendingOperator != null) { throw new IllegalStateException("并行流处理时遇到无效的元素结构"); } // 合并两个状态的结果,这里假设state1的待执行操作符是有效的 return new CalcState(calculate(state1.currentResult, state2.currentResult, state1.pendingOperator)); } ); // 提取最终结果 int finalResult = finalState .map(state -> state.currentResult) .orElseThrow(() -> new IllegalArgumentException("输入流为空或结构无效")); System.out.println(finalResult); // 输出8,符合你的示例
核心优势:
- 全程仅使用Stream的
reduce操作,没有构建任何外部集合来存储操作符或数字,完全符合你的要求。 - 状态完全在Stream的累积过程中传递,没有外部可变状态,线程安全(并行流也能正常工作,只要输入结构正确)。
- 严格遵循流的顺序处理逻辑,确保计算顺序和从左到右的手动计算一致。
需要注意的是,这个方案依赖输入Stream的元素结构是数字、操作符、数字、操作符...最后以数字结尾,如果输入结构不符合(比如开头是操作符、末尾是操作符),会抛出异常,你可以根据需求添加额外的校验逻辑。
内容的提问来源于stack exchange,提问作者Tristate
相关产品推荐
相关产品推荐

