• 20145218 《Java程序设计》第五周学习总结


    20145218 《Java程序设计》第五周学习总结

    教材学习内容总结

    异常

    程序中总有些意想不到的状况所引发的错误,如果不对异常进行正确的处理,则可能导致程序的中断执行,造成不必要的损失,

    所以在程序的设计中必须要考虑各种异常的发生,并正确的做好相应的处理,这样才能保证程序正常的执行。

    使用try、catch

    • java中所有的错误都会被打包为对象,并提供了特有的语句进行处理。使用了try、catch语法,JVM会尝试执行try区块中的程序代码,如果发生错误,执行流程会跳离错误发生点,然后对比catch括号中声明的类型,是否符合被抛出的错误对象类型,如果是的话,就执行catch区块中的程序代码。
    • 代码如下
    import java.util.*;
    public class Average2{
    	public static void main(String[] args){
    		try{
    			Scanner console=new Scanner(System.in);
    		double sum=0;
    		int count=0;
    		while(true){
    			int number=console.nextInt();
    			if(number==0){
    				break;
    			}
    			sum+=number;
    			count++;
    		}
    		System.out.printf("average %.2f%n",sum/count);
    		}catch (InputMismatchException ex){
    			System.out.printf("you must input an integer");
    		}
    		
    	}
    }
    
    • 运行结果如下

    异常类的继承结构

    在整个java的异常结构中,实际上有以下两个最常用的类:Exception、Error,这两个类全都是Throwable的子类
    Exception:一般表示的是程序中出现的问题,可以直接使用try...catch处理。
    Error:一般指的是JVM错误,程序中无法处理。
    在先前的Average范例中,没用到try、catch语句,照样可以编译执行。为什么在书上230页的范例会编译错误?要解决这个错误信息有两种方式,一是使用try、catch打包System.in.read(),二是在main()方法旁声明throws java.io.IOException。

    • 代码如下
    import java.util.Scanner;
    public class Average4{
    	public static void main(String[] args){
    		double sum=0;
    		int count=0;
    		while(true){
    			int number=console.nextInt();
    			if(number==0){
    			break;
    			}
    			sum+=number;
    			count++;
    		}
    		System.out.printf("average %.2f%n",sum/count);
    		}
    		static Scanner console=new Scanner(System.in);
    		static int nextInt(){
    			String input=console.next();
    		while(!input.matches("\d*")){
    			System.out.println("please input a number");
    			input=console.next();
    		}
    		return Integer.parseInt(input);
    		}
    }
    
    • 运行结果如下

    要抓还是要抛

    如果方法设计流程中发生异常,而你设计时并没有充足的信息知道该如何处理那么可以抛出异常,让调用方法的客户端来处理。操作对象的过程中如果会抛出受检异常,但目前环境信息不足以处理异常,无法使用try、catch处理时,可由方法的客户端依据当时调用的环境信息进行处理。在catch区块进行完部分错误处理后,可以使用throw将异常再抛出。可以在任何流程中抛出异常,不一定要在catch区块中。
    如果使用继承时,父类某个方法声明throws某些异常,子类重新定义该方法时可以:1.不声明throws任何异常。 2.throws父类该方法中声明的某些异常。 3.throws父类该方法中声明异常的子类。4.throws父类方法中未声明的其他异常。 5.throws父类方法中声明异常的父类

    • 代码如下
    import java.io.*;
    import java.util.Scanner;
    public class FileUtil{
        public static String readFile(String name)throws FileNotFoundException{
            StringBuilder text=new StringBuilder();
            try{
                Scanner console=new Scanner(new FileInputStream(name));
                while(console.hasNext()){
                    text.append(console.nextLine())
                    .append('
    ');
                }
            }catch(FileNotFoundException ex){
                ex.printStackTrace();
                throw ex;
            }
            return text.toString();
        }
    }
    

    贴心还是造成麻烦

    • 异常处理的本意:在程序错误发生时能有有明确的方式通知API客户端。
    • java是唯一采用受检异常的语言。这有两个目的:一是文件化,受检异常声明会是API操作接口的一部分,客户端只要查阅文件,就可以知道方法可能会引发哪些异常。二是提供编译程序信息,让编译程序能够在编译时期就检查出API客户端没有处理异常。
    • 受检异常本意良好,有助于程序设计人员注意到异常的可能性并加以处理,但在应用程序规模扩大时,会逐渐对维护造成困难。

    认识堆栈追踪

    • 在多重方法调用下,异常发生点可能是在某个方法之中,若想得知异常发生的根源,以及多重方法调用下异常的堆栈传播,可以使用堆栈追踪来取得相关信息。
    • 使用方法:直接调用异常对象的printStackTrace()。
    • 堆栈追踪信息中显示了异常类型,最顶层是异常的根源,以下是调用方法的顺序,程序代码行数是对应于当初的程序原始码,如果想要取得个别的堆栈追踪元素进行处理,则可以使用getStackTrace(),在捕捉异常后什么都不做的话或者做了不适当的处理,这种程序代码会对应用程序维护造成严重伤害。在使用throws重抛异常时,异常的追踪堆栈起点,仍是异常的发生根源,而不是重抛异常的地方。如果想要让异常堆栈起点为重抛异常的地方,可以使用fillInStackTrace()方法,这个方法会重新装填异常堆栈,将起点设为重抛异常的地方,并返回Throwable对象。
    • 代码如下
    public class StackTraceDemo3{
        public static void main(String[] args){
            try{
                c();
            }catch(NullPointerException ex){
                ex.printStackTrace();
            }
        }
        static void c(){
            try{
                b();
            }catch(NullPointerException ex){
                ex.printStackTrace();
                Throwable t=ex.fillInStackTrace();
                throw (NullPointerException) t;
            }
        }
        static void b(){
            a();
        }
        static String a(){
            String text=null;
            return text.toUpperCase();
        }
    }
    
    • 运行结果如下

    关于assert

    • assert的两种使用语法:
      1.assert boolean_expression
      2.assert boolean_expression : detail_expression
    • boolean_expression 若为true则什么事都不会发生,若为false则会发生java.lang.Assertionerror。
    • 关于何时该使用断言?1.断言客户端调用方法前,已经准备好某些前置条件。2.断言客户端调用方法后名具有方法承诺的结果。3.断言对象某个时间点下的状态。4.使用断言取代批注。5.断言程序流程中绝对不会执行到的程序代码部分。

    使用finally

    • finally代码块:定义一定执行的代码。
    • 如果创建FileInputStream实例就会开启文档,不使用时,应当调用close()关闭文档。若想要的是无论如何,最后一定要执行关闭动作。
    • try、catch语法还可以搭配finally使用,无论try区块中有无发生异常,若撰写有finally区块,则finally区块一定会被执行。如果程序撰写的流程中先return了,而且也有finally区块,那么finally区块会先执行完后,再将值返回。
    • 代码如下
    public class FinallyDemo{
        public static void main(String[] args){
            System.out.println(test(true));
        }
        static int test(boolean flag){
            try{
                if(flag){
                    return 1;
                }
            }finally{
                System.out.println("finally...");
            }
            return 0;
        }
    }
    
    • 运行结果如下

    自动尝试关闭资源

    • 想要尝试自动关闭资源的对象,是撰写在try之后的括号中,如果无须catch处理任何异常,可以不用撰写,也不用撰写finally自行尝试关闭资源。
    • 使用自动尝试关闭资源语法时,也可以搭配catch,并不影响对特定异常的处理,实际上,自动尝试关闭资源语法也仅仅是协助你关闭资源,而不是用于处理异常。

    java.lang.AutoCloseable接口

    • JDK7的尝试关闭资源语法可套用的对象,必须操作java.lang.AutoCloseable接口。
    • AutoCloseable是JDK7新增的接口,仅定义了close()方法。只要操作AutoCloseable接口,就可以套用至尝试关闭资源语法。尝试关闭资源语法也可以同时关闭两个以上的对象资源,只要中间以分号间隔。
    • 在try的括号中,越后面撰写的对象资源会越早被关闭。
    • 代码如下
    import static java.lang.System.out;
    
    public class AutoClosableDemo2{
        public static void main(String[] args){
            try(ResourceSome some=new ResourceSome();
            ResourceOther other=new ResourceOther()){
                some.doSome();
                other.doOther();
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
    }
    
    class ResourceSome implements AutoClosable{
        void doSome(){
            out.println("做一些事");
        }
        @Override
        public void close() throws Exception{
            out.println("资源Some被关闭");
        }
    }
    
    class ResourceOther implements AutoClosable{
        void doOther(){
            out.println("做其他事");
        }
        @Override
        public void close() throws Exception{
            out.println("资源Other被关闭");
        }
    }
    

    认识Collection架构

    • 程序中常有收集对象的需求,其中学过的只有使用object数组,在javaSE中其实就提供了数个收集对象的类。
    • 收集对象的行为,像是新增对象的add()方法,移除对象的remove()方法等,都是定义在java.util.Collection中。
    • 既能收集对象,也能逐一取得对象,这就是java.lang.Iterable定义的行为,它定义了iterator()方法返回java.util.Iterator操作对象,可以让你逐一取得对象。然而收集对象会有不同的需求,如果希望收集时记录每个对象的索引顺序,并可依索引取回对象,这样的行为定义在java.util.List接口中。如果希望收集的对象不重复,具有集合的行为,则由java.util.Set定义。如果希望收集对象时,以队列排列。收集的对象加入至尾端,取得对象时从前端,则可以使用java.util.Queue。如果希望对Queue的两端进行加入、移除等动作,则可以使用java.util.Deque。

    具有索引的List

    • List是一种Collection,作用是收集对象,并以索引方式保留收集的对象顺序,其操作类之一是java.util.ArrayList。
    • 查看API文件的时候发现,List接口定义了add()、remove()、set()等许多依索引操作的方法。
    • ArrayList适合排序的时候用,可得到较好的速度表现。而LinkedList采用了链接结构,当需要调整索引顺序时,比较适用。
    • ArrayList特性:数组在内存中会是连续的线性空间,根据索引随机存取时速度快。有可指定容量的构造函数。
    • LinkedList特性:若收集的对象经常会有变动索引的情况。

    内容不重复的Set

    • 使用Set接口的操作对象:同样是收集对象,在收集过程中若有相同对象,则不再重复收集。
    • String的Split()方法,可以指定切割字符串的方式。一般用hashcode()与equals()来判断对象是否相同。
    • 代码如下
    import java.util.*;
    
    class Student2 {
        private String name;
        private String number;
    
        Student2(String name, String number) {
            this.name = name;
            this.number = number;
        }
    
    
        @Override
        public int hashCode()
        {
            int hash = 7;
            hash = 47 * hash + Objects.hashCode(this.name);
            hash = 47 * hash + Objects.hashCode(this.number);
            return hash;
        }
    
        @Override
        public boolean equals(Objects obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Student2 other = (Student2) obj;
            if (!Objects.equals(this.name, other.name)) {
                return false;
            }
            if (!Objects.equals(this.number, other.number)) {
                return false;
            }
            return true;
        }
    
        @Override
        public String toString()
        {
            return String.format("(%s,%s)", name, number);
        }
    }
    public class Students2
    {
        public static void main(String[] args)
        {
            Set students = new HashSet();
            students.add(new Student2("Justin","B835031"));
            students.add(new Student2("Monica","B835032"));
            students.add(new Student2("Justin","B835031"));
            System.out.println(students);
        }
    }
    

    支持队列操作的Queue

    • Queue继承自Collection,所以也具有Collection的add()、remove()、element()等方法,然而Queue定义了自己的offer()、poll()与peek()等方法。
    • 最主要的差别在于,add()、remove()、element()等方法操作失败时会抛出异常,而offer()、poll()、peek()等方法操作失败时会返回特定值。
    • 代码如下
    import java.util.*;
    import static java.lang.System.out;
    
    public class Stack
    {
        private Deque elems = new ArrayDeque();
        private int capacity ;
    
        public Stack(int capacity)
        {
            this.capacity = capacity;
        }
    
        public boolean push(Object elem)
        {
            if(isFull())
            {
                return false;
            }
            return elems.offerLast(elem);
        }
    
        private boolean ifFull()
        {
            return elems.size() + 1 > capacity;
        }
    
        public Object pop()
        {
            return elems.pollLast();
        }
    
        public Object peek()
        {
            return elems.size();
        }
    
        public static  void main (String[] agrs)
        {
            Stack stack = new Stack(5);
            stack.push("Justin");
            stack.push("Monica");
            stack.push("Irene");
            out.println(stack.pop());
            out.println(stack.pop());
            out.println(stack.pop());
        }
    }
    

    使用泛型

    • JDK5之后增加了泛型语法。若接口支持泛型,在操作时也会比较方便,只要声明参考时有指定类型,那么创建对象时就不用再写类型了,泛型也可以仅定义在方法上,最常见的是在静态方法上定义泛型。
    • 代码如下
    import java.util.Arrays;
    import java.util.Objects;
    
    public class ArrayList<E>
    {
        private Object[] elems;
        private int next;
    
        public ArrayList(int capacity)
        {
            elems = new Object [capacity];
        }
    
        public ArrayList()
        {
            this(16);
        }
    
        public void add(E e)
        {
            if(next == elems.length)
            {
                elems = Arrays.copyOf(elems,elems.length * 2);
            }
            elems[next++] = e;
        }
    
        public E get (int index)
        {
            return (E) elems[index];
        }
    
        public int size()
        {
            return next;
        }
    }
    

    简介Lambda表达式

    • Lambda表达式的语法省略了接口类型与方法名称,->左边是参数列,右边是方法本体。
      简化以下代码。
    IntegerFunction doubleFunction = new IntegerFunction()
    {
        public Integer apply(Integer i)
        {
            return i*2;    
        }
        
    }
    

    简化后

    IntegerFunction doubleFunction = (Integer i) -> i * 2;
    

    常用Map操作类

    • 常用的Map操作类为java.util.HashMap与java.util.TreeMap,其继承自抽象类java.util.AbstractMap。
    • 建立Map操作对象时,可以使用泛型语法指定键与值的类型。要建立键值对应,可以使用put()方法,第一个自变量是键,第二个自变量是值,对于Map而言,键不会重复,判断键是否重复是根据hashCode()与equals(),所以作为键的对象必须操作hashCode()与equals()。
    • 若要指定键取回对应的值,则使用get()方法,在hashMap中建立键值对应后,键是无序的,这可以在执行结果中看到。如果想让键是有序的,则可以使用TreeMap。

    访问Map键值

    • Map虽然与Collection没有继承上的关系,但它们却是彼此的API。
    • 如果想取得Map中所有的键,可以调用Map的keySet() 返回Set对象,由于键是不重复的,所以用Set操作返回是理所当然的做法。如果想取得Map中所有的值,则可以使用values()返回Collection对象。

    本周代码托管截图

    其他(感悟、思考等,可选)

    之前感觉java每周的学习太过紧张,因为是将任务全都堆到周末去做,所以在周末的两天里要看大量的视频,写大量的文字。但是其实只要每天都拿出时间来学java,就可以减轻一点周末写博客时的压力写博客也不只是抄书,而要进行自己的思考与感悟,虽然现在让我们自己写代码仍是有一定难度,毕竟练习的还是少,实话说我现在根本写不出,只能依葫芦画瓢去打书上的代码,稍微改动一点就会蒙掉,但是我相信经过之后的学习与努力,我最终可以写出自己的代码。

    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时
    第一周 200/200 1/2 20/20
    第二周 300/500 1/3 18/38
    第三周 500/1000 1/4 22/60
    第四周 1292/1300 1/5 40/90
    第五周 993/1300 1/6 35/160

    参考资料

  • 相关阅读:
    类和对象系列教材 (十二)- 怎么写一个Java的饿汉式与懒汉式单例模式
    类和对象系列教材 (十二)- 怎么写一个Java的饿汉式与懒汉式单例模式
    [LeetCode] 285. Inorder Successor in BST
    [LeetCode] 671. Second Minimum Node In a Binary Tree
    [LeetCode] 230. Kth Smallest Element in a BST
    [LeetCode] 238. Product of Array Except Self
    [LeetCode] 273. Integer to English Words
    [LeetCode] 266. Palindrome Permutation
    [LeetCode] 409. Longest Palindrome
    [LeetCode] 124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/senlinmilelu/p/5350497.html
Copyright © 2020-2023  润新知