今天上午的软件工程课讲到了写程序时做单元测试和代码规范的重要性,反观自己每次被程序搞得焦头烂额也是因为这方面习惯不好的原因,等闲暇时再写一篇这方面的文章。
另外,对前一篇博文中的代码也并不是很满意,想对其进行进一步的完善。中午在永哥的帮助下也学到了程序调试上的一些技巧,特把前天发表的博文中的代码做了一些修改,也得到了更满意的结果,虽然还是有些缺陷,还是拿出来和大家共享一下。
在这篇博文中想要先补充一下之前没写到的时间分配的问题,其实我在编程上一直是一个没有什么时间观念的问题,心情好了可以在电脑前坐一天,心情不爽一下都懒得碰。按照老师在课上举医生的例子,我大概是那个一边翻医书一边治病的医生吧。整个程序的完成用了五个小时,首先是选择了一个心情好的时候,星期六的早上九点到十二点,下午两点到四点。首先在脑子里形成了大体的思路,读取文件-->处理内容(分析单词,统计各单词数量)-->对单词按数量进行排序-->输出结果。当了解到map这个概念之后,查阅了大量介绍的文章和代码,说我是代码的搬运工这句话一点也没有错,有了自己的思路,只需要在这个基础上堆砌代码,在阅读了很多的hashmap的用法以及对hashmap进行排序的算法之后,很快的将自己脑子里的想法用代码堆砌了出来。
之前的代码有些细节没有处理好,也因为赶时间没有进行深究,在这次完善的过程中我也找到了解决的方法,一切正常的感觉还是很爽的!~
好了,切入正题!
首先还是读入文件的部分,比昨天稍好的一点是可以在没有规定要读的文件,而是可以由用户自行输入,但是在异常处理上掌握的不好,未能加入异常处理,所以对于用户来讲,这个程序界面还不够友好,希望能得到指点使之更加完善。
1 /* 2 *分析一个文本文件(英文文章)中各个词出现的频率, 3 *并且把频率最高的10个词打印出来。 4 */ 5 import java.util.*; 6 import java.io.*; 7 public class wordrate { 8 9 public static void main(String[] args) throws Exception 10 { 11 Map<String, Integer> hash_Data = new HashMap<String, Integer>(); 12 BufferedReader buf = new BufferedReader (new InputStreamReader(System.in)); 13 System.out.print("请输入文件名称:"); 14 String fileLoad=buf.readLine(); 15 FileReader in =new FileReader(fileLoad); //建立文件输入流 16 BufferedReader bin=new BufferedReader(in); //建立缓冲输入流
我自己也按照书上异常处理部分对本部分代码进行了try{}catch{}的处理,但由于方法不当未能得出正确的结果,这一部分还请大家不吝赐教。
其次是对文件的处理上,昨天的小程序在多次测试后发现也是可以读取4MB的文件的,但是处理速度特别的慢,高达二十多秒。后来我发现速度慢的原因是我将整篇文章都当做一行存入了str中,必然导致速度的变慢,于是做了以下修改,使其将很长的文章以行为单位来处理,大大减少了分析的时间。
1 String str; 2 String file=null; 3 while((str =bin.readLine())!=null) 4 { 5 file=str; 6 file = file.toLowerCase();// 将所有字母化为小写 7 file = file.replaceAll("[^a-z']|\\s+|\t|\r", " "); // 将非字母字符、多个空格回车换行均化为一个空格 8 String words[]= file.split("\\s+");// 取出单词,并将单词存入数组中 9 for (int i = 0; i < words.length; i++) 10 { 11 String key = words[i]; //key对应单词 12 if (hash_Data.get(key) != null) 13 { 14 int value = ((Integer) hash_Data.get(key)).intValue(); //value对应单词出现的频率,单词已在map中存在则value+1 15 value++; 16 hash_Data.put(key, new Integer(value)); 17 } 18 else 19 { 20 hash_Data.put(key, new Integer(1)); //单词未在map中存在则value初始化为1 21 } 22 } 23 }
接下来呢就是排序方面的问题了,之前的运行结果总是出现如下问题:
这段异常的解释如下:
Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract. The previous implementation silently ignored such a situation. If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort, to restore previous mergesort behavior.
试着翻译了一下这段话:使用java.util.arrays.sort和java.util.collections.sort的排序算法已被取代。新的排序算法实现时如果检测到类似的违反合同的情况下可能会抛出一个illegalargumentexception。而在之前的实现中,这样的情况是被忽略掉的。如果需要进行以前的行为,你可以使用新的系统性能,java.util.arrays.uselegacymergesort归并排序,恢复以前的行为。
又具体查到应该是compare没有处理好两个对象相等的情况。选择使用老版本的排序方法,只需要在代码前面加上:System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");就OK啦~
红色的地方是新加入的代码。
1 List<Map.Entry<String, Integer>> list_Data = new ArrayList<Map.Entry<String, Integer>>(hash_Data.entrySet()); 2 System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); 3 Collections.sort(list_Data, new Comparator<Map.Entry<String, Integer>>() 4 { 5 public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) 6 { 7 if(o2.getValue()!=null&&o1.getValue()!=null&&o2.getValue().compareTo(o1.getValue())>0) 8 { 9 return 1; 10 }else 11 { 12 return -1; 13 } 14 } 15 });
最后是输出的部分。
1 System.out.println("频率最高的十个单词:"); 2 for (int i = 0; i <10; i++) { 3 String id = list_Data.get(i).toString(); 4 System.out.print("第"+(i+1)+"."); 5 String word[]=id.split("="); 6 System.out.println(word[0]+":"+word[1]); 7 } 8 } 9 }
最后运行分析了一篇5M的文章,分析时间只用了1秒多。我对这个结果还是很满意的。
可是。。。第6.。你是怎么个意思!?我就不懂了。。。。