如何针对防御性编程优化此代码?

时间:2010-09-21 01:39:40

标签: java defensive-programming data-integrity

对于我的数据结构项目,目标是读取一个包含超过10000首歌曲的提供文件,其中清晰标记了艺术家,标题和歌词,每首歌曲用一条双引号分隔。我已经编写了这段代码来解析文本文件,它运行起来,运行时间不到3秒 阅读422K行文字
创建一个Song对象
将所述歌曲添加到ArrayList中

我写的解析代码是:

if (songSource.canRead()) {  //checks to see if file is valid to read
    readIn= new Scanner(songSource);
    while (readIn.hasNextLine()) {
 do {
     readToken= readIn.nextLine();

             if (readToken.startsWith("ARTIST=\"")) {
  artist= readToken.split("\"")[1];
      } 
      if (readToken.startsWith("TITLE=\"")) {
  title= readToken.split("\"")[1];
      } 
      if (readToken.startsWith("LYRICS=\"")) {
  lyrics= readToken.split("\"")[1];
      } else {
  lyrics+= "\n"+readToken;
      }//end individual song if block
 } while (!readToken.startsWith("\"")); //end inner while loop

    songList.add(new Song(artist, title, lyrics));

    }//end while not EOF 
} //end if file can be read 

我正在与我的Intro to Algorithms教授谈论这个项目的代码,他说我应该在我的代码中试图更加防御,以避免其他人提供的数据不一致。最初我在Artist,Title和Lyrics字段之间使用if / else块,并且根据他的建议我改为顺序if语句。虽然我可以看到他的观点,但是使用这个代码示例,我怎样才能更加谨慎地避免输入不一致?

6 个答案:

答案 0 :(得分:4)

我会替换例如:

artist= readToken.split("\"")[1];

String[] parts = readToken.split("\"");
if(parts.length >= 2) artist = parts[1];
else continue;

其他修改包括:

  1. 重置局部变量(因此,如果在第一首歌之后没有为某首歌提供艺术家,则不会意外地为一首歌创作错误的艺术家)
  2. 决定如果缺少某些数据该怎么办 - 你还想把歌曲添加到歌曲列表中吗?

答案 1 :(得分:2)

在现实世界中,对数据完整性有一些保证。在处理用户输入(无论是来自stdin还是文件)的情况下,有一些项目定义的范例用于通知用户需要注意的问题。

例如,当编译器编译代码或执行脚本的shell遇到不一致时,它可能会暂停并打印包含不一致的行,而下面的第二行使用“^”符号来指示问题的位置

所以这里有一些基本问题要问自己:
1.每条线路都保证包含每个区域吗? 2.字段的排序是否有保证?

如果这些是输入合同的条件并且被违反,您应该忽略/报告该行。如果它们不是输入的条件,那么你需要处理它......你目前没有。

答案 2 :(得分:2)

您假设输入是完美的。如果您查看当前设置应用程序的方式,基于对算法的快速读取,数据将如下所示

ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"

但请考虑案例

ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"
ARTIST="Peter"
LYRICS="Sing Song All night long"
"

根据您的算法,您现在有2首歌曲被标记为

songList = { Song("JOHN", "HELLO WORLD", "Sing Song All night long"),
             Song("Peter", "HELLO WORLD", "Sing Song All night long") }

使用当前算法,艺术家和标题将被曝光,即使未定义,也会显示在第二首歌曲中。您需要重置三个变量。

在你的其他地方,你只是将完整的一行倾注到歌词中。如果你已经把歌词拉出来,你现在压倒了怎么办?测试用例

 ARTIST="John"
 LYRICS="Sing Song All night long"
 TILET="HELLO WORLD"
 "

考虑将此记录发送到错误状态。因此,当批量读取完成时,可以生成并修复错误报告。

此外,您只会在阅读艺术家后才考虑EOF。如果在艺术家阅读期间发生EOF,并且该文件未以“。”结束,那将会有一个例外。在你的do / while中添加另一个检查hasNextLine()

答案 3 :(得分:1)

我看到Jason缺少一些东西。

我认为if / else很好,它不会改变逻辑。但是,您应该尽可能地限制变量的范围。通过在while循环中声明艺术家,标题等,它们将被初始化为null(或其他),因此如果一个条目缺少艺术家,那么它将不会获得最后一个条目的值。

此外,如果标题,艺术家等有引号会怎样?怎么处理?看起来多行的歌词怎么样?

如果存在未知字段会发生什么 - 可能是拼写错误?它将被添加到歌词的末尾,这似乎不对。只有在找到LYRICS字段后才能附加它。如果歌词为null,则它将以“null”开头。

答案 4 :(得分:0)

以下是一些可以解决的问题:

  • 您的代码假定之前没有空格(例如)“ARTIST”,“=”符号周围没有空格,依此类推。

  • 您的代码假设关键字为全部大写字母。有人可以使用小写或混合大小写。

  • 您的代码假定不以keyword=\"开头的行是歌曲歌词的延续。但是如果用户输入ARTOST="Sting"怎么办?或者,如果用户尝试使用两行作为艺术家姓名,该怎么办?

最后,我不相信在这种情况下用“if”替换“else if” 会对代码的健壮性产生任何影响。

答案 5 :(得分:0)

处理异常(我猜Scanner可能会因无效字符而抛出InputMismatchException。)

如果文件格式错误,并且文件末尾已到达,do { } while (...)似乎可以无休止地循环。

无法阻止artisttitle为空。