实验四开始,一点点学习异常处理!
首先区分异常(Exception)和错误(Error)
The Error class describes internal system errors and resource exhaustion situations inside the Java runtime system (e.g., VirtualMachineError, LinkageError) that rarely occur.
内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束 。而对于异常:
The Exception class describes the error caused by your program (e.g. FileNotFoundException, IOException).
异常由于自己程序导致的问题,可以捕获、可以处理。
Error举例:User input errors, Device errors, Physical limitations.
既然Error我们无能为力, 那就转向关注我们能够处理的Exception。
Exception Handling
Exception分为unchecked和checked两类,分类如下:
程序员可以通过抛出unchecked exception来声明无法解决,不在自己程序处理能力范围内的异常,而checked exception则是用户所期待的,也是需要程序员去处理的。
如下所示:
实验四
自定义异常
科学记数法表示
根据WZJ老师的建议,可以直接将不符合科学记数法的输入转化为符合要求的数据,也可以Garbage in, garbage out般的Fail Fast,而我本人选择直接抛出异常信息,并且直接让用户重新操作。
值得注意的是,在操作过程中,如果try_catch语句中catch(Exception e)
,那么无论中间有什么自定义exception都会被覆盖,并且不能输出相关的信息。首先,错误样例如下:
如果在总的构造系统中这样catch异常
1 | try { |
则根据文件得到异常信息是这样的:
而如果这样写的话1
2
3
4
5
6
7
8
9try {
······
} catch (NotationFormatException e) {
System.out.println(e.getNumber());
System.out.println("请修改按要求文件后重新读入");
} catch (IOException e) {
System.out.println("IOE EXCEPTION!!!");
e.printStackTrace();
}
则会出现异常的信息:
实验五
工具安装
命名规范
在实验中要求按照特定代码规范进行走查修改。这里简单学习了Java命名规范。
查看详细信息
Set与List的恩怨
除了众所周知的Set不存放重复元素外,两者在contains方法检索元素时差别也巨大!!!
在第一个版本利用graphset元素时,用的是List<Edge<L>> edges
,读取两万数据边的时候就花费10s左右,其中重要一点就是有诸多
1 | if (!edges.contains(e)) { |
利用contains检索的判断语句,而换了之后发现效率大大提升,构造80万的数据也只要1分钟左右,现在考虑把其他List也换成Set!!!
由衷感谢YSC同学的提醒与支持!!!
再学Strategy设计模式
在实验中要求使用策略模式采用不同读写策略来进行对文本的操作。于是在此复习该设计模式。(本人在实验3和4没有用到此模式)
组成:
- Strategy(策略):代表”算法”这一抽象角色,定义了实现策略所必需的接口(API)。
- ConcreteStrategy(具体的策略):表示具体的算法,实现了Strategy中声明的方法,即提供策略的具体实现。
- Context(上下文):负责使用Strategy角色,Context中保存了ConcreteStrategy角色的实例,并使用它去实现需求。
类图如下:
读写策略
读写策略实验提供了多种
- Stream
- Reader/Writer
- Buffer/Channel
- Scanner
- java.nio.file.Files
要注意,本人默认使用的BufferedReader是Writer的子类,类声明中可以看到其extends Writer
,并不是我以前认为的Buff的子类。
BufferedReader
原理:BufferedReader和BufferedWriter出现的目的是为了对FileReader以及FileWriter的读写操作进行增强.原理类似于使用StringBuilder,是把数据先放入他们的一个char数组中,然后再操作char数组。
使用缓冲区的字符流是使用了装饰着模式对FileReader等进行功能上的增强,装饰者模式与继承都可以实现功能上的增强,但是装饰者可以做得更加的灵活,也不会使继承树变得太过复杂。
第一开始采用的读入 BufferedReader 和 BufferedWriter。
注意一下写文件并不会写入空行,整个文件一连串下来非常爆炸。1
2
3
4
5
6
7
8File target = new File("test/file/SocialNetworkCircle.txt");
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(target));
for (String i : info) {
bw.write(i);
}
bw.close();
······
注意:默认为覆盖写入
采用加上写入一换行符试试。bw.write("\n");
!!!在这里发现如果info
为Set<String>
类型,读入后顺序错乱,但是如果用ArrayList
实现,就会按照存入顺序来写入文件,十分美观。
*NOTE:
- 当关闭BufferedReader的时候,传入作为参数的reader也会跟着关闭。
- BufferedReader具有一个特殊的方法readerLine(),功能是读取一行,原理是从char数组中读取,判断是否遇到换行符,是的话返回。
- 本质就是为底层字符输入输出流添加缓冲功能、先将底层流中的要读取或者要写入的数据先以一次读取一组的形式来讲数据读取或者写入到buffer中、再对buffer进行操作、这样不但效率、还能节省资源。
java.nio.file.Files
读入1
2
3
4
5
6String encoding = "UTF-8";
File file = new File(filePath);
if (file.isFile() && file.exists()) { // If the file exists
Path from = Paths.get(filePath);
List<String> lines = Files.readAllLines(from,Charset.forName(encoding));
写入1
2Path from = Paths.get("test/file/SocialNetworkCircle.txt");
Files.write(from,personInfo,Charset.forName("UTF-8"));
Scanner
Scanner经常被我们用于读取控制台的输入,但是我们只需要将他构造函数中的System.in替换成一个File文件,他就可以变成一个读取文件的Scanner了,Scanner的按行读取方法是nextLine()我们在使用它的时候可以在前面判断它时候hasNextLine()。也是十分方便.如下:1
2
3
4
5
6
7
8
9
10File file = new File(filePath);
if (file.isFile() && file.exists()) { // If the file exists
Scanner s = new Scanner(file);
String lineTxt = null;
while (s.hasNext()) {
lineTxt = s.nextLine();
······
}
s.close();
Channel
FileChannel类的使用必须配合一个byteBuffer类使用我们再创建一个FileOutputStream对象之后使用getChannel()方法来创建一条通道,同时我们将要写入的字符串是用getBytes()存在byteBuffer中,翻转byteBuffer使它变为写状态,只要byteBuffe不为空就像FileChannel中写,最后清空bytebuffer完成写操作.
但是这种写入和FileOutputStream都不是分行写入
如果想要加入换行符,需要再写入XX.write("\n".getBytes());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public void channelWrite() throws FileNotFoundException {
FileChannel outChannel = new FileOutputStream(new File("test/file/SocialNetworkCircle.txt")).getChannel();
ByteBuffer byteBuffer = java.nio.ByteBuffer.allocate(1024);
personInfo.addAll(tieInfo);
for(String i :personInfo) {
byteBuffer.put(i.getBytes());
byteBuffer.flip();
while(byteBuffer.hasRemaining()) {
try {
outChannel.write(byteBuffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byteBuffer.clear();
}
}
Stream 流写入
1 | File target = new File("test/file/SocialNetworkCircle.txt"); |