Java 如何为防御编程优化此代码?

Java 如何为防御编程优化此代码?,java,defensive-programming,data-integrity,Java,Defensive Programming,Data Integrity,对于我的data structures项目,目标是读取一个提供的文件,其中包含10000多首歌曲,并清楚地标记了艺术家、标题和歌词,每首歌曲之间用一行单双引号隔开。我编写了这段代码来解析文本文件,它可以正常工作,运行时间不到3秒 阅读422K行文本 创建歌曲对象 将所述歌曲添加到ArrayList 我编写的解析代码是: if (songSource.canRead()) { //checks to see if file is valid to read readIn= new Sca

对于我的data structures项目,目标是读取一个提供的文件,其中包含10000多首歌曲,并清楚地标记了艺术家、标题和歌词,每首歌曲之间用一行单双引号隔开。我编写了这段代码来解析文本文件,它可以正常工作,运行时间不到3秒 阅读422K行文本 创建歌曲对象 将所述歌曲添加到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 
我和我的算法教授介绍了这个项目的代码,他说我应该在代码中采取更具防御性的措施,以避免其他人提供的数据不一致。最初,我在艺术家、标题和歌词字段之间使用if/else块,根据他的建议,我改为顺序if语句。虽然我可以理解他的观点,但使用这个代码示例,我怎么能对允许输入不一致性更具防御性呢

我将替换,例如:

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

其他修改包括:

重置局部变量,这样,如果在第一首歌曲之后没有为某些歌曲提供艺术家,您就不会意外地为歌曲找到错误的艺术家 决定如果缺少某些数据该怎么办-是否仍要将歌曲添加到歌曲列表中?
在现实世界中,有一些关于数据完整性的保证。在处理来自stdin或文件的用户输入时,有一些项目定义的范例用于通知用户需要注意的问题

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

所以这里有一些基本的问题要问你自己: 1.是否保证每一行包含每一个字段? 2.是否保证字段的顺序


如果这些是输入合同的条件并且被违反,您应该忽略/报告该行。如果它们不是输入的条件,那么您需要处理它。。您目前没有。以下是一些可以解决的问题:

您的代码假定前面没有空格,例如ARTIST,在=符号周围没有空格,等等

您的代码假定关键字包含在所有大写字母中。有些人可以使用小写或混合大小写

代码假定不以关键字=\开头的行是歌曲歌词的延续。但是如果用户输入了ARTOST=Sting怎么办?或者,如果用户尝试使用两行作为艺术家名称,会怎么样


最后,我不相信在本例中用if替换else if会对代码的健壮性产生任何影响。

我发现这里缺少一些东西

我认为if/else很好,不会改变逻辑。但是,您应该尽可能地限制变量的范围。通过在while循环中声明artist、title等,它们将被初始化为null或其他任何值。如果某个条目缺少artist,那么它将无法获取最后一个条目的值

另外,如果标题、艺术家等有引用,会发生什么?这是怎么处理的?歌词似乎是多行的,对吗


如果存在未知字段(可能是拼写错误),会发生什么情况?它将被添加到歌词的结尾,这似乎不正确。只有找到歌词字段后,才应将其追加。如果歌词为空,那么它将以空开头。

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

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"
"
根据你的算法,你现在有两首歌的特点是

songList = { Song("JOHN", "HELLO WORLD", "Sing Song All night long"),
             Song("Peter", "HELLO WORLD", "Sing Song All night long") }
使用当前的算法,艺术家和标题将被公开,并将显示在第二首歌曲中,即使它们没有定义。您需要重置三个变量

在你的《else》中,你只是把整句话倒进歌词里。如果你已经把歌词拉出来了,你现在就要覆盖它了。测试用例

 ARTIST="John"
 LYRICS="Sing Song All night long"
 TILET="HELLO WORLD"
 "
考虑将此记录发送到错误状态。因此,当批量读取完成时,可以生成并修复错误报告


也只有在一个艺术家被读完之后你才会考虑EOF。如果在艺术家读取期间发生EOF,并且文件没有以结束,该怎么办。你会得到一个例外。在do/while中,为hasNextLine添加另一个检查

处理异常我想扫描器可能会为无效字符抛出InputMismatchException

看起来像是在。。。如果文件格式不正确,并且到达文件末尾,则可以无休止地循环


没有任何东西可以阻止艺术家或标题为空。

是否可以优化regexp或为每次迭代构造它?@Thorborn-这不会影响代码的健壮性。。。只有
它的性能。即使这样,也不多。在IIRC中,Pattern.compile方法使用一个简单的单正则表达式缓存来避免重复编译同一个正则表达式。在这种情况下,它将是有效的。谢谢你的例子,你给了我一些思考。这是一个使你的代码更好的开放问题。考虑让它成为社区维基吧?这正是我喜欢这个网站的原因。我想我遇到了这个CS程序设计方式的一些缺点。它似乎更感兴趣的是先了解整体概念,然后再深入细节,但除了关于代码语法和空格的讲义外,很少有人强调正确的过程,如防御性编码。我选择您的回答作为答案,因为尽管我在当前项目中没有使用它,您给了我一个具体的例子,说明如何在不破坏程序的情况下解决用户输入错误。
 ARTIST="John"
 LYRICS="Sing Song All night long"
 TILET="HELLO WORLD"
 "