作为一名java学生(初学者)我刚刚完成了编写程序以执行以下任务的任务:
阅读文本文件的内容;
挑出文本中的所有字词,将所有大写字母替换为小写字母;
我们被建议有一个包含main方法的类,并使用ArrayList,Scanner,PrintWriter和FileReader类。
我设法做了下面的工作,但是它提出了一些问题/基本差距。
我相信基于良好O.O.的原则。编程实践中,我应该将下面的内容分解为一系列具有单一目的的方法,然后调用这些方法。但是,我真的很难做到这一点。任何人都可以详细说明/建议一种改进特定点的方法吗?如果我错了,还是纠正我?
public class Main
{
private static ArrayList<String> dictionary;
private static ArrayList<String> tempdictionary;
public static void main() throws FileNotFoundException
{
Scanner inFile = new Scanner(new FileReader("H:\\csc8001\\results.txt"));
dictionary = new ArrayList <>();
tempdictionary = new ArrayList <>();
while (inFile.hasNext()) {
dictionary.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
}
inFile.close();
PrintWriter outFile = new PrintWriter("H:\\csc8001\\results1.txt");
int index = 0;
for (String a : dictionary)
{
if (!tempdictionary.contains(a)){
tempdictionary.add(a);
} else {
index++;
}
}
Collections.sort(tempdictionary);
for (int i=0; i<tempdictionary.size(); i++)
outFile.println(tempdictionary.get(i));
outFile.flush();
outFile.close();
}
}
答案 0 :(得分:1)
正如其他人所说,你的代码绝对没有错,因为它代表你已经给出的任务。但是你已经表达了对面向对象原则的兴趣,所以我有一些可能有用的想法。注意 - 以下内容对于对特定任务采取过于笼统的方法的批评是非常开放的 - 关于此问题有perennial debate,许多人订阅了"You ain't gonna need it"学校。
如果您可能需要具有相同类但具有不同属性值的多个副本,则面向对象的方法将非常有用。在您指定的任务中,情况并非如此。
然而,可以想象,你可能想要在一个后续任务中从(一个)其他文件创建一个字典,或者在同一个程序中使用多个文件编写一个程序。
在此任务中,系统会要求您创建字典。字典可以是一个对象。你可以从这个起点接近任务。例如:
public class Dictionary
{
}
词典有什么作用?按字母顺序排序的单词列表。正如其他人所说的那样,一个很好的选择是使用SortedSet
(习惯于查看API documentation a.k.a javadocs,他们是你的基本朋友),但你被告知使用{{1这就是我们要做的。
ArrayList
您可以继续添加方法来执行每项任务。就个人而言,我可能有一个构造函数采用public class Dictionary
{
ArrayList<String> words;
}
文件名。我已将文件的读取直接写入此内容 - 您可以同样调用一个私有方法(例如String
)来获取文件并提取单词。
parseFile()
然后我添加一个removeDuplicates()方法(我上面已经调用过) - 有很多方法可以做到这一点。你可以像你一样使用临时的ArrayList - 我将举一个我怀疑更快的例子。
public Dictionary(String inputFilename) throws FileNotFoundException
{
Scanner inFile = new Scanner(new FileReader(inputFilename));
words = new ArrayList <String>();
while (inFile.hasNext()) {
words.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
}
inFile.close();
removeDuplicates();
Collections.sort(words);
}
最后 - 添加private void removeDuplicates()
{
HashSet<String> dupSet = new HashSet<String>();
dupSet.addAll(words);
words.clear();
words.addAll(dupSet);
}
方法
writeToFile(String outFilename)
你被告知要把你的课程放在主,所以这样做。现在可能很短:
public void writeToFile(String outFilename) throws FileNotFoundException
{
PrintWriter outFile = new PrintWriter(outFilename);
for (int i=0; i<words.size(); i++)
outFile.println(words.get(i));
outFile.flush(); // strictly redundant
outFile.close();
}
您现在拥有一个Dictionary类,您可以将其导入任何项目并按上述方式使用。如果下周的任务是“修改你的字典程序,为这个目录中的所有100个文件制作一个字典”,你就笑了。您还可以向Dictionary类添加函数(例如 public static void main(String[] args) throws FileNotFoundException
{
d = new Dictionary("H:\\csc8001\\results.txt");
d.outputToFile("H:\\csc8001\\results1.txt");
}
),同时相信您不会破坏现有函数或使用这些函数的任何程序。
打电话给你的班级mergeWith(Dictionary d2)
是很不寻常的。没有错,但即使你没有采用上面的字典对象方法,我也会重命名它 - 只要它有主要方法,它仍然可以运行。
你真的不需要tempdictionary - 你可以'unquify'并排序Main
- 从而避免保留带有重复项的未排序列表(以及它使用的相关内存)
初始化PrintWriter看起来有点不寻常,然后进行一些处理(使列表唯一并排序),然后输出。倾向于尽可能地将文件打开到您输出的位置,然后尽快再次关闭它。
答案 1 :(得分:0)
总的来说,你的概念是正确的;想想DRY原则(不要重复自己)。如果您不得不多次编写该代码,请将其粘贴在函数中并调用它。
然而,在这种情况下,写主要的所有代码是&#34; OK&#34;因为程序没有太多 - 你的代码已经符合DRY要求。如果你必须阅读多个文件,那么你绝对应该将代码放入函数而不是像那样的主函数。
如果你真的想要分解它,你可以做一些事情,就像将while (inFile.hasNext())
块放在它自己的函数中一样,你将扫描仪对象作为参数传递。
答案 2 :(得分:0)
我没有看到任何特别值得制作单独方法的东西。但我确实对代码有一些评论,没有特别的顺序:
为什么使用静态类变量而不是局部变量?
index
变量的目的是什么?
为什么要在打开和写入输出文件之间对集合进行排序/过滤?
关闭作家也会刷新它,因此无需明确调用flush()
。
为什么不使用SortedSet
等TreeSet
作为您的收藏品,您可以完全避免排序和过滤?例如:
Scanner inFile = new Scanner(new FileReader("H:\\csc8001\\results.txt"));
SortedSet<String> dictionary = new TreeSet<>();
while (inFile.hasNext()) {
dictionary.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
}
inFile.close();
PrintWriter outFile = new PrintWriter("H:\\csc8001\\results1.txt");
for (String s : dictionary)
outFile.println(s);
outFile.close();