20145208 《Java程序设计》第5周学习总结

20145208 《Java程序设计》第5周学习总结

教材学习内容总结

语法和继承架构

异常处理关键字

  • 第八章内容主要是对Java的异常处理,所以我先了解了一下关键字
  • Java的异常处理是通过5个关键字来实现的:try,catch,throw,throws,finally。
    • Throws:throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。 如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。

    • Throw:throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

    • Try:try语句用大括号{}指定了一段代码,该段代码可能会抛弃一个或多个例外。

    • Catch:

      • catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。
      • catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。
      • 也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。 
    • Finally:try所限定的代码中,当抛弃一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛弃或不抛弃例外,也无论catch语句的例外类型是否与所抛弃的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。

try...catch语法

  • try…catch语法可以捕捉try部分的异常,如果没有try…catch的时候,出现异常的时候程序就会报错,如果加上try…catch,出现异常程序可以正常运行,只是把错误信息存储到Exception里,所以catch是用来提取异常信息的,我们需要在Catch部分加上一句System.out.println(xxx);等类似的代码,将出现异常可以把异常打印出来。在捕捉到异常之后千万不要像下面这样的代码一样什么都不做:
try{
……
}catch(SomeException ex){
}
  • 这样的话我们在捕捉到错误信息之后都不知道发生了什么,很不利于维护,当然,我们也不可以对异常执行一些错误的处理,这样会误导维护者。

  • 是抓还是抛?

    • throws:自己无法处理,用在方法声明
    • throw:方法中抛出Checked Exception,方法声明中必须有throws

Collection与Map

使用Collection集合对象

  • 本节内容和数据结构与算法这门课有很大的联系,学习起来也颇有触类旁通的感觉
  • List: 类似数组,具有位置信息,带索引
    • 核心方法:
      • add(int index, E element):可以将指定的元素插入此列表中的指定位置。
      • remove(int index):移除此向量中指定位置的元素。
      • set(int index, E element):用指定元素替换列表中指定位置的元素。
    • ArrayList:《数据结构》中的线性表
    • LinkedList:《数据结构》中的链表
  • Set: 其中的对象不能有重复的
  • Queue: 队列
    • 核心方法
      • offer:添加一个元素并返回true,如果队列已满,则返回false
      • poll:移除并返问队列头部的元素,如果队列为空,则返回null
      • peek:返回队列头部的元素,如果队列为空,则返回null
    • Deque: 双向队列

键值对应的Map

  • HashMap:建立的键值对应是无序的
  • TreeMap:建立的键值对应是有序的
  • values方法是获取集合中的所有的值,没有键,没有对应关系
  • KeySet是将Map中所有的键存入到set集合中。因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。keySet():迭代后只能通过get()取key。

教材学习中的问题和解决过程

问题一

  • 在学习使用Properties的时候我一开始不知道如何从文档中加载属性,代码如下:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class MapLoadProperties {
    public static void main(String[] args) throws IOException {
        Properties props = new Properties();
        props.load(new FileInputStream(args[0]));
        System.out.println(props.getProperty("CH5.username"));
        System.out.println(props.getProperty("CH5.password"));
    }
}
  • 解决方案:
  • 从代码中我发现,后面输出的变量是props.getProperty,所以我觉得应该从这个变量入手,也就是从代码段props.load(new FileInputStream(args[0]));来研究输出的变量,我通过API中了解FileInputStream()调用的应该就是前面说的文档,那么该如何调用呢?
  • 一开始我尝试了直接用properties文件名替换掉args[0],但是程序无法编译了,思考了一下我觉得应该是在调用文档的时候,文档名少了""的关系,果然加上了就可以编译了
  • 但是编译是可以编译了,程序抛出了问题:

  • 虽然有了问题,但是解决方案却更清晰了,既然是提醒我找不到指定文件,那我告诉系统文件在哪里就好了!于是我将代码段修改了一下:
props.load(new FileInputStream("C:/Users/Cai Ye/IdeaProjects/HelloWorld/out/production/HelloWorld/CH5/Mapperson.properties"));
  • 最后输出了文档中我存储的属性:

  • 成功了!

问题二

  • finally块中的代码一定会被执行吗?
  • 想要验证finally块中的代码是不是一定会被执行,我的思路是在finally块前加一些终止类型的代码来看看能不能阻止它执行,例如return:
  • 原代码如下:
public class TryCatchFinallyAutoClosableDemo {
    public static void main(String[] args) {
        try (Resource res = new Resource()) {
            res.doSome();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            System.out.println("finally…");
        }
    }
}
    class Resource implements AutoCloseable {
    void doSome() {
        System.out.println("做一些事情");
    }
    @Override
    public void close() throws Exception {
        System.out.println("资源被关闭");
    }
}
  • 输出结果如下:

  • 在该代码段加上return:
 public static void main(String[] args) {
        try (Resource res = new Resource()) {
            res.doSome();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        finally {
            System.out.println("finally…");
        }
    }
  • 但是结果并没有改变,这证明finally块应该是都会被执行的。
  • 但是我在网上看到一种情况可以让finally块不执行,就是加上System.exit(),这段代码的意义是终止JVM……这太无赖了,脸JVM都被终止了,怎么可能执行别的呢,就像断电了一样……不做常规范围思考……

代码调试中的问题和解决过程

问题一

  • 书上266页上的SimpleLinkedList代码是这样的:
public class CollectionSimpleLinkedList {
    private class Node{
        Node(Object o){
            this.o=o;
        }
        Object o;
        Node next;
    }
    private Node first;
    public void add(Object elem){
        Node node=new Node(elem);
        if (first==null){
            first=node;
        }
        else {
            append(node);
        }
    }
    private void append(Node node){
        Node last=first;
        while (last.next!=null){
            last = last.next;
        }
        last.next=node;
    }
    public int size(){
        int count=0;
        Node last =first;
        while (last!=null){
            last=last.next;
            count++;
        }
        return count;
    }
    public Object get(int index){
        checkSize(index);
        return findElemOf(index);
    }
    private void checkSize(int index)throws IndexOutOfBoundsException{
        int size=size();
        if (index>=size){
            throw new IndexOutOfBoundsException(
                String.format("Index: %d,Size: %d",index,size));
            }
        }
    private Object findElemOf(int index){
        int count=0;
        Node last =first;
        while (count<index){
            last =last.next;
            count++;
        }
        return last.elem;
    }
}
  • 但是编译的时候报错了,报错的理由是找不到last.elem这个变量:

  • 解决方案:

  • 于是我试着通过IDEA进行调试,但IDEA上给的解决方法是创建一个elem或者改变变量的名字。但是我感觉创建一个新的file“elem”是不合理的,所以我觉得还是要改变变量。

  • 于是我仔细看了一下代码,觉得这里想要return的变量应该计数得到的对应索引对象。也就是下面代码段子中的last。于是我将last.elem改成了last。

private Object findElemOf(int index){
        int count=0;
        Node last =first;
        while (count<index){
            last =last.next;
            count++;
        }
        return last;
    }
  • 后来在老师的指导下我知道我上面的那种修改方式也是错的,正确的方式应该是把return last.elem修改为return last.o 或把class Node中的Object o改成Object elem,这样就是正确的返回了对应的索引对象;二者一个是通过将错误的elem量改为正确的o量,另外一个是通过将原本的o改为elem来配合last.elem,二者本质上是相同的,这也给我一个启发,就是一个错误是可以有多种的解决方法,有时候一个相同的问题也可以有多个正确答案,所以在学习和检验代码的时候思路可以开阔一点,不局限于一条路。

问题二

  • 269页的代码Students.java是这样的:
import java.util.*;
class Student{
    private String name;
    private String number;
    Student(String name,String number){
        this.name=name;
        this.number=number;
    }
    @Override
    public String toString(){
        return String.format("(%s,%s)",name,number);
    }
}
public class CollectionStudents {
    public static void main(String[] args) {
        Set students=new HashSet();
        students.add(new Student("Justin","B835031"));
        students.add(new Student("Justin","B835032"));
        students.add(new Student("Justin","B835031"));
        System.out.println(set);
    }
}
  • 但是编译不能通过的:

  • 解决方案:
  • 因为我们之前都没没有提到过set,为什么这里要输出它?我觉得这里是错误的于是我改成了如下代码:
import java.util.*;
class Student{
    private String name;
    private String number;
    Student(String name,String number){
        this.name=name;
        this.number=number;
    }
    @Override
    public String toString(){
        return String.format("(%s,%s)",name,number);
    }
}
public class CollectionStudents {
    public static void main(String[] args) {
        Set students=new HashSet();
        students.add(new Student("Justin","B835031"));
        students.add(new Student("Justin","B835032"));
        students.add(new Student("Justin","B835031"));
        System.out.println(students);
    }
}
  • 因为我之前用Set定义是students所以我把其中的set变为了students。果然编译通过了,结果也是正确的:

问题三

  • 在编译书上296页代码时,我的输出和书上不一样,代码如下:
import java.util.HashMap;
import java.util.Map;
import static java.lang.System.out;
public class MapKeyValue {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("one", "一");
        map.put("two", "二");
        map.put("three", "三");
        out.println("显示键");
        map.keySet().forEach(key -> out.println(key));
        out.println("显示值");
        map.values().forEach(key -> out.println(key));
    }
}
  • 在这段代码中,采用的是HashMap操作,所以结果应该是无序,但是我的结果和书上不同

  • 解决方案:

  • 后来问了老师才意识到,这里的有序无序不是one two three这样的逻辑,而是计算机分析26个英文字母的排列有序。

其他(感悟、思考)

  • 在本周的学习中,我反而在学习的过程中觉得自己有很多不会的地方,一方面可能是因为本周的学习内容相对比较难比较生疏,另一方面,我觉得也是因为我思考的多了,对代码想要了解的更加深入一点,对于出现的错误想要尽可能的解决。所以我觉得本周我对于代码的学习反而没有上周感觉的那么顺畅。
  • 本周的学习中,我认识到了API的作用真的很大,很多时候在代码出现问题的时候,我不了解代码的具体含义和一些引申的东西,所以在改错的时候觉得很困难,但是,如果使用API的话,改正错误代码的方向性就会比较明确,大大节约了我的时间,也让我在调试代码的时候更有条理性。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时 成为超过高级初学者的存在
第一周 150/150 1/3 15/15 第一个JAVA程序
第二周 150/300 2/5 20/35 第一次对教材代码进行自己的修改
第三周 400/700 2/7 20/50 熟练的进行代码托管
第四周 1210/1910 2/9 30/80 在敲代码的时候有自己思考
第五周 1083/2993 1/10 40/120 学习API

参考资料

原文地址:https://www.cnblogs.com/20145208cy/p/5343281.html