最近给公司开发业务代码时,碰到一个场景,简单描述是这样的:

  客户要向咱们公司定制一件产品,这个产品呢,有很多属性,那公司得根据这些属性报价呀,怎么报价呢?公司针对某种类型的产品有一个基准价,在同类产品下,某个属性超标了,需要加价,但每一个属性的加价方式都不一样,针对每一家客户加多少价也不一样,每个时间点加价比率也可能不一样,真实情况要比这个复杂不少,这里就不再深入讨论。

  那么应对这种需求,我首先想到的关键点是:要把加价这个公式,暴露给实际能控制它的人员去输入,把公式中需要用到的一些参数,以替代符(或者说变量)的方式提供给他们,比如,用a表示基准价,b表示属性超出数值,然后超出部分需要乘以该属性的单价5块钱,那么最终的值就可以写成公式: a + b * 5 ;实际运算的时候,假设a是100,b是20,把他们代替 a和b,公式就成了 100 + 20 * 5,看起来很简单的公式,口算都能算出来,但是正常来讲,公式录入系统,是以字符串的形式保存的,一直到你把真实的值替换到公式里,也是字符串操作,计算机要如何把你这字符串的里的内容正确的计算出来呢?

  OK,其实对代码逻辑不是非常好的同学,可以用一些简单的方法,比如,将最终的公式用JavaScript的eval()函数执行一下,就可以得到结果了,这个方法也可以用来在前端验证公式录入正确与否,还有一种方法,把最终的公式直接拼接到SQL语句,对上临时表查一下,如:SELECT  100+20*5  AS  result from dual;也可以得到结果,用这两种方法,其实还可能进行更复杂的计算,充分利用JavaScript和sql提供的函数库。

  嗯,回到原点,我们现在呢,要在Java服务端实现字符串的公式正确计算,公式虽然简单,但可能每一次要进行几百条公式的计算,也没必要查询几百次数据库,而且这种和金钱相关联的值,如非必要,还是不要抛给前端来替你计算。虽然,公司这边并没有采用我的方案,但是我个人还是把一个简单的公式计算器写了出来,留个思路,以作备用。

  简单公式计算器能够满足 加减乘除 和 小括号的运算。

  我个人非常建议新手练习一下,基础运用得越扎实,对以后的技术瓶颈突破越好。

  代码图上的注释比较少:

  粘贴出代码图:

代码来了:

  1. package com.supalle.test;
  2.  
  3. import java.math.BigDecimal;
  4. import java.math.MathContext;
  5.  
  6. /**
  7. * @作者: Supalle
  8. * @时间: 2019/3/8
  9. * @描述: 简单公式计算器
  10. */
  11. public class Calc {
  12.  
  13. private char[] val;
  14.  
  15. private int len;
  16.  
  17. private int inx;
  18.  
  19. // 构造器,把公式传进去,比如: 100 + 20 * 5 + (1 + 2)
  20. public Calc(String val) {
  21. this.val = val.toCharArray();
  22. len = this.val.length;
  23. inx = 0;
  24. }
  25.  
  26. // 获取计算结果,使用方法其实就是 new Calc("100 + 20 * 5 + (1 + 2)").getResult();就可以得到结果了
  27. public BigDecimal getResult() {
  28. return nextValue(BigDecimal.ZERO, '+');
  29. }

  30.    // OK,接下来的两个方法,必须要弄明白,下一个值和下一个参数的区别
       // 为什么要获取下一个值,加法、减法、和左小阔号,都需要获取下一个值,因为加法、减法如果碰到乘法、除法,那么运算优先权在右侧,如果碰到左侧小括号,优先权也在右侧,所以要先把右边的值算出来
       // 为什么要获取下一个参数,乘法、除法,他们下一个运算符如果不是左侧小括号,那么应该从左往右顺序计算,因此需要直接取到下一个参数进行计算
       // 还有一点要值得注意,那就是:在运算时,减法一律替换成加上一个负数,以此来消除实际对一个负数进行运算产生异常,比如 1 * -3,总不能检测到 - 的时候,又去做减法运算吧
       // 就讲这么多了,不能理解的同学,再反复推敲几遍
  31. // 获取下一个值,传入第一个参数和第一个参数后的运算符
  32. private BigDecimal nextValue(BigDecimal param1, char operator) {
  33. if (inx < len) {
  34. if (operator == ')') {
  35. return param1;
  36. }
  37.  
  38. if (operator == '+') {
  39. return param1.add(nextValue(nextParam(), inx < len ? val[inx++] : ')'));
  40. } else if (operator == '*') {
  41. return nextValue(param1.multiply(nextParam(), MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
  42. } else if (operator == '/') {
  43. return nextValue(param1.divide(nextParam(), MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
  44. }
  45. }
  46. return param1;
  47. }
  48.  
  49. // 获取下一个参数
  50. private BigDecimal nextParam() {
  51.  
  52. char[] param = new char[len - inx + 1];
  53.  
  54. int paramInx = 0;
  55.  
  56. while (inx < len) {
  57.  
  58. if (val[inx] == '-') {
  59. if (paramInx == 0) {
  60. param[paramInx++] = val[inx];
  61. param[paramInx++] = '0';
  62. } else {
  63. val[--inx] = '+';
  64. break;
  65. }
  66. } else if (val[inx] == '.' || ((int) val[inx] >= 48 && (int) val[inx] <= 57)) {// 如果是 . 或 0 ~ 9
  67. param[paramInx++] = val[inx];
  68. } else if (val[inx] == '(') {
  69. inx++;
  70. return nextValue(BigDecimal.ZERO, '+');
  71. } else if (((int) val[inx] >= 41 && (int) val[inx] <= 43) || (int) val[inx] == 47) {
  72. break;
  73. }
  74.  
  75. inx++;
  76. }
  77.  
  78. return paramInx > 0 ? new BigDecimal(param, 0, paramInx) : BigDecimal.ZERO;
  79. }
  80.  
  81. }

Java简单公式计算器的更多相关文章

  1. Java使用BigDecimal精确计算的简单公式计算器

    由于工作需要,写了一个使用BigDecimal运算的精确计算的计算器(然后发现其实比不用BigDecimal的并好不到哪里去) 只能做加减乘除 double类型的数字在千万级别的时候会转成科学计数法, ...

  2. jsp学习---使用jsp和JavaBean实现超简单网页计算器

    一.需求 如题,用jsp实现一个超简单的网页计算器. 二.实现 1.效果图 1)初始界面: 2)随便输入两个数进行相乘: 3)当除数为零时提示报错: 2.代码 Calculator.java pack ...

  3. 教学项目之-通过Python实现简单的计算器

    教学项目之-通过Python实现简单的计算器   计算器开发需求 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/ ...

  4. HDU1237 简单的计算器 【堆】+【逆波兰式】

    简单的计算器 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  5. 多元线性回归----Java简单实现

    http://www.cnblogs.com/wzm-xu/p/4062266.html 多元线性回归----Java简单实现   学习Andrew N.g的机器学习课程之后的简单实现. 课程地址:h ...

  6. 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器

    从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器 之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Calibu ...

  7. js制作简单的计算器

    学着做了一个简单的计算器!记录记录!哈哈 <!DOCTYPE html> <html> <head> <title>简单的计算器</title&g ...

  8. java简单词法分析器(源码下载)

    java简单词法分析器 : http://files.cnblogs.com/files/hujunzheng/%E7%AE%80%E5%8D%95%E8%AF%8D%E6%B3%95%E5%88%8 ...

  9. 留念 C语言第一课简单的计算器制作

    留念 C语言第一课简单的计算器制作 学C语言这么久了.  /* 留念 C语言第一课简单的计算器制作 */   #include<stdio.h>  #include<stdlib.h ...

随机推荐

  1. 【数据结构】30、hashmap=》hash 计算方式

    前提知识 写在前面,为什么num&(length - 1) 在length是2的n次幂的时候等价于num%length n - 1意味着比n最高位小的位都为1,而高的位都为0,因此通过与可以剔 ...

  2. SYN012型B码时统

       SYN012型B码时统 产品概述 SYN012型B码时统是由西安同步电子科技有限公司精心设计.自行研发生产的一款通用性时统终端,内置高精度恒温晶振,接收GPS北斗双模卫星信号,10MHz外部参考 ...

  3. Python自学day-1

    一.Python介绍 1.python擅长领域:     WEB开发:Django. pyramid. Tornado. Bottle. Flask. WebPy     网络编程:Twisted(牛 ...

  4. javaWeb 概念介绍

    一.javaWeb 1.概念:利用java语言进行基于互联网的开发 2.软件架构 (1)C/S   Client/Server  客户端/服务器端 在用户本地有一个客户端程序,在远程有一个服务器程序 ...

  5. wireshark数据包分析实战 第三、四章

    1,wireshark支持的协议上千种,开源的. 2,wireshark需要winpcap驱动支持.winpcap驱动的作用通过操作系统捕捉原始数据包.应用过滤器.将网卡切换为混杂模式. 3,捕获文件 ...

  6. 消息驱动式微服务:Spring Cloud Stream & RabbitMQ

    1. 概述 在本文中,我们将向您介绍Spring Cloud Stream,这是一个用于构建消息驱动的微服务应用程序的框架,这些应用程序由一个常见的消息传递代理(如RabbitMQ.Apache Ka ...

  7. c#基础三

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  8. 5分钟快速部署ownCloud私有云盘存储系统

    ownCloud 是一个开源免费专业的私有云存储项目,它能帮你快速在个人电脑或服务器上架设一套专属的私有云文件同步网盘,可以像 Dropbox 那样实现文件跨平台同步.共享.版本控制.团队协作等等.o ...

  9. redis 发布和订阅实现

    参考文献 15天玩转redis -- 第九篇 发布/订阅模式 <Redis设计与实现> 命令简介 在redis用户手册中,跟发布订阅相关的命令有如下的六个: PSUBSCRIBE PUBL ...

  10. vue的基本用法和指令

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...