Java 通过文本文件读取货币金额&;计算票据面额

Java 通过文本文件读取货币金额&;计算票据面额,java,bufferedreader,filereader,Java,Bufferedreader,Filereader,我应该将一个文本文件读入java程序,在java文件中添加货币金额,然后确定如何支付每个总金额(读取$20、$10、$5…)。我很难解决如何将文本文件的每一行分开进行单独计算的问题 这是我要导入的文本文件: Class1 9.30 7.44 5.32 3.33 Class2 2.22 Class3 7.33 4.44 3.56 Class4 15.67 12.02 10.33 8.87 Class5 4.44 3.33 2.22

我应该将一个文本文件读入java程序,在java文件中添加货币金额,然后确定如何支付每个总金额(读取$20、$10、$5…)。我很难解决如何将文本文件的每一行分开进行单独计算的问题

这是我要导入的文本文件:

Class1  9.30    7.44    5.32    3.33
Class2  2.22
Class3  7.33    4.44    3.56
Class4  15.67   12.02   10.33   8.87
Class5  4.44    3.33    2.22    1.11
我不仅要展示每个值的解决方案,还要展示每个类的解决方案。我假设某种形式的for循环是必需的,但我无法理解

public static void main(String[] args) throws FileNotFoundException, IOException {

    FileReader file = new FileReader("C:\\Users\\idhit\\Desktop\\amounts.txt");
    BufferedReader bf = new BufferedReader(file);

    String st = bf.readLine();

    double sum = 0;
    double c1total = 0;
    double c2total = 0;
    double c3total = 0;
    double c4total = 0;
    double c5total = 0;

    while ((st = bf.readLine()) != null) {

        StringTokenizer stn = new StringTokenizer(st);
        String rn = stn.nextToken();
        String name = stn.nextToken();
        double c1 = Double.parseDouble(stn.nextToken());
        double c2 = Double.parseDouble(stn.nextToken());
        double c3 = Double.parseDouble(stn.nextToken());
        double c4 = Double.parseDouble(stn.nextToken());
        double c5 = Double.parseDouble(stn.nextToken());

    }

    double value = scan.nextDouble();
    int valueIntegral = (int) value;
    int valueFractional = (int) Math.round(100 * value - 100 * valueIntegral);

    // Integral values

    int hundred = valueIntegral / 100;

    int fifty = (valueIntegral % 100) / 50;

    int twenty = ((valueIntegral % 100) % 50) / 20;

    int ten = (((valueIntegral % 100) % 50) % 20) / 10;

    int five = ((((valueIntegral % 100) % 50) % 20) % 10) / 5;

    int one = (((((valueIntegral % 100) % 50) % 20) % 10) % 5) / 1;

    // Fractional values

    int quarter = valueFractional / 25;

    int dime = (valueFractional % 25) / 10;

    int nickel = ((valueFractional % 25) % 10) / 5;

    int penny = (((valueFractional % 25) % 10) % 5) / 1;

    System.out.println(hundred + " hundred dollar bills\n" + fifty + " fifty dollar bills\n" + twenty
            + " twenty dollar bills\n" + ten + " ten dollar bills\n" + five + " five dollar bills\n" + one
            + " one dollar bills\n" + quarter + " quarters\n" + dime + " dimes\n" + nickel + " nickels\n" + penny
            + " pennies");
}

不过,根据名称为每个类分配总计是正确的,您需要一些条件。假设您的
bufferedReader
读取的第1行是

Class1  9.30    7.44    5.32    3.33
从StringTokenizer可以获得每个类的名称和总金额。 每次调用
.nextToken()
时,它都会读取到下一个分隔符。在您的情况下,它是空白。首先
.nextToken()
将读取
Class1
。第二个将读取
9.30
,依此类推

Class 1: 25.39
从这里开始,您可以像名字是
Class1
一样将总数放入
c1total
。有什么事吗?是的,你猜对了。您可以在这里使用if语句。因为有5个类,所以有5个if语句。你们的每一个while都将处理每一行,并利用if语句将其分配给正确的变量

我建议你尝试我上面写的东西,但是我用不同的方式做了同样的事情,只是为了给你一个感知,以及你如何以不同的方式编程同样的事情,甚至可能更好

编辑:像DawoodibnKareem建议的那样
StringTokenizer
是遗留的,不应使用。我已经更新了密码。它现在使用拆分和,而不是双精度

// Instead of 5 variables I created an array to store data
BigDecimal[] classTotal = new BigDecimal[5];
String line;
while ((line = bufferedReader.readLine()) != null) {
    String[] lineSplit = line.split("\\s+");
    // Class1 9.30 7.44 5.32 3.33 would become
    // [Class1, 9.30, 7.44, 5.32, 3.33]
    String name = lineSplit[0];
    switch (name) {
    case "Class1":
        classTotal[0] = getSum(lineSplit);
        break;
    case "Class2":
        classTotal[1] = getSum(lineSplit);
        break;
    case "Class3":
        classTotal[2] = getSum(lineSplit);
        break;
    case "Class4":
        classTotal[3] = getSum(lineSplit);
        break;
    case "Class5":
        classTotal[4] = getSum(lineSplit);
        break;

    }
}
bufferedReader.close();
for (int i = 0; i < classTotal.length; i++) {
    System.out.println("Class " + (i + 1) + " : " + classTotal[i]);
}

public static BigDecimal getSum(String[] line) {
    BigDecimal sum = new BigDecimal(0);
    // Iterating from index 1 because 0 index contains name
    for (int i = 1; i < line.length; i++) {
        BigDecimal valueBigDecimal = new BigDecimal(line[i]);
        sum = sum.add(valueBigDecimal);
    }
    return sum;
}
输出:(如果我使用double而不是BigDecimal)

请注意某些值是如何关闭的,尤其是对于
Class 4
,它应该是
46.89


这是因为Java中的float和double原语类型是数字,数字存储为分数和指数的二进制表示形式。浮点数有时(可以安全地假设“大部分时间”)无法返回数字的精确表示形式。因此,您得到的是
46.88999999999
,而不是
46.89
。这就是为什么在计算货币时,double/float被认为是可怕的。为了避免这个问题,我们必须使用。特别是在您的情况下,进一步对double执行计算只会使精度恶化

我回答了你的问题吗?请注意,你的
valuefractal
计算可能会出现浮点错误,有时结果会太小。请检查更新答案。是的,我认为这是可行的。刚刚遇到“表达式的非法开始”。谢谢你的帮助!请注意Javadoc对
StringTokenizer
类的说明-“…StringTokenizer是一个遗留类,出于兼容性原因保留了它,尽管新代码中不鼓励使用它。建议寻求此功能的任何人使用String的拆分方法或java.util.regex包……”。在这种情况下,使用
扫描仪
(OP最初使用它的方式)是一个更好的选择。此外,此解决方案中的加法可能会出现浮点舍入错误,并且经常会给出错误的结果。@DawoodibnKareem您是对的。我将更新我的代码以使用更好的类,并将添加有关
浮点舍入错误的信息。
。我理解您对@Goion的看法。我仍在处理输出,但感谢您的帮助!是的,那好多了。
Class 1 : 25.39
Class 2 : 2.22
Class 3 : 15.33
Class 4 : 46.89
Class 5 : 11.10
Class 1 : 25.39
Class 2 : 2.22
Class 3 : 15.33
Class 4 : 46.88999999999999
Class 5 : 11.1