Java - 将字符串转换为double的最有效方法

时间:2013-03-02 16:36:53

标签: java arrays string parsing double

您好我正在从文本文件中读取并将每行(用逗号分隔)保存到数组中。唯一的问题是数组中的大多数元素都是double值,其中两个元素是字符串。因此,我必须使数组成为String []数组。因此,每当我想对数组中的double值执行一些方程时,我必须首先将它们解析为double值。我实际上运行了这些方程式的1000多次迭代,因此我的代码不断地将字符串解析为double。这是一种耗费昂贵的方式,这会减慢我的计划。有没有更好的方法可以将字符串数组中的值转换为double值,还是在保存文本文件中的行时应该采取更好的方法?感谢

以下是我从文本文件中读取后的一个数组:

String[] details = {"24.9", "100.0", "19.2" , "82.0", "Harry", "Smith", "45.0"};

我现在需要将前两个元素相乘,并将其添加到第3,第4和第7个元素的总和。换句话说,我只使用数字元素(当然是保存为字符串)

double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);

我必须为文本文件中的每一行(1000多行)执行此操作。因此,我的程序运行速度非常慢。有没有更好的方法可以将字符串值转换为double?还是有一个更好的方法我应该首先存储它们?

编辑:我使用分析器来检查代码的哪一部分是最慢的,而且确实是我上面显示的代码

2 个答案:

答案 0 :(得分:4)

这是一个生成输入文件的示例,例如您描述的10000行长的输入文件,然后将其读回并执行您发布的计算并将结果打印到stdout。我在读取文件时专门禁用任何缓冲,以获得最差的读取性能。正如其他人所说,我也没有做任何缓存。整个过程(包括生成文件,进行计算和打印结果)始终需要大约520-550 ms。除非你为数百或数千个文件重复同样的过程,否则这几乎不会“慢”。如果你看到与此截然不同的性能,那么可能是硬件问题。丢失的硬盘可能会使读取性能几乎为零。

import java.io.*;
import java.util.Random;

public class ReadingDoublesFromFileEfficiency {
    private static Random random = new Random();

    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        String filePath = createInputFile();
        BufferedReader reader = new BufferedReader(new FileReader(filePath), 1);
        String line;
        while ((line = reader.readLine()) != null) {
            String[] details = line.split(",");
            double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);
            System.out.println(score);
        }
        reader.close();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("Took " + elapsed + " ms");
    }

    private static String createInputFile() throws IOException {
        File file = File.createTempFile("testbed", null);
        PrintWriter writer = new PrintWriter(new FileWriter(file));
        for (int i = 0; i < 10000; i++) {
            writer.println(randomLine());
        }
        writer.close();
        return file.getAbsolutePath();
    }

    private static String randomLine() {
        return String.format("%f,%f,%f,%f,%s,%s,%f",
                score(), score(), score(), score(), name(), name(), score());
    }

    private static String name() {
        String name = "";
        for (int i = 0; i < 10; i++) {
            name += (char) (random.nextInt(26) + 97);
        }
        return name;
    }

    private static double score() {
        return random.nextDouble() * 100;
    }
}

答案 1 :(得分:2)

你最好创建一个合适的对象并将值存储在其中 - 这给你带来两大好处:1)你的代码会更快,因为你可以避免不必要的重新计算双值和2)你的代码会更清晰,因为字段将被命名而不是像details[0]这样调用,而[0]指的是public class PersonScore { private double[] multipliers = new double[2]; private double[] summers = new double[3]; private String first; private String last; // expects a parsed CSV String public PersonScore(String[] arr) { if(arr.length != 7) throw new InvalidArgumentException("Must pass exactly 7 fields"); multipliers[0] = Double.parseDouble(arr[0]); multipliers[1] = Double.parseDouble(arr[1]); summers[0] = Double.parseDouble(arr[2]); summers[0] = Double.parseDouble(arr[3]); summers[0] = Double.parseDouble(arr[6]); first = arr[4]; last = arr[5]; } public double score() { double ret = 1; for(double mult : multipliers) ret *= mult; for(double sum : summers) ret += sum; return ret; } public String toString() { return first+" "+last+": "+score(); } }

由于2)我不知道这些字段应该是什么,所以显然你的课程看起来会有所不同,但这个想法是一样的:

{{1}}

请注意,还有一个额外的好处,即分数方法现在更加强大。您的实现上面对我们想要使用的字段进行了硬编码,但通过将字段解析并存储为结构内容,我们能够实现更易读,更具伸缩性的分数计算方法。