面向对象

异   常

什么是异常:异常是指在程序的运行过程中所发生的不正常的事件,它会中断运行的程序。

异常处理通过五个关键字来实现:try、catch、finally、throw和throws

try:执行可能产生的异常代码(try包裹整个执行的代码从头到尾)

catch:捕获异常,根据执行条件写入相关异常类型。

finally:无论是否发生异常,代码都能执行。

throw:声明方法可能要 抛出的各种异常,只能用于抛出一种异常。

throws:手动抛出异常,让调用者处理异常

try-catch块

在catch块中处理异常

1.加入用户自定义处理信息

System.err.println("出现错误:年龄不能是负数")

2.调用方法输出异常信息

e.printStackTrace();

3.异常处理方法

1.void printStackTrace()  输出异常的堆栈信息

2.String getMessage()   返回异常信息描述字符串,是printStackTrace()输出信息的一部分

常见的异常类型

Exception    异常层次结构的父类

ArithmeticException   算术错误情形,如以零作除数

ArraylndexOutOfBoundsException   数组下标越界

NullPointerException   尝试访问 null 对象成员

ClassNotFoundException   不能加载所需的类

IllegalArgumentException    方法接收到非法参数

NumberFormatException   数字格式转换异常

ClassCastException     对象强制类型转换出错

多重catch块

1.排列catch 语句的顺序:先子类后父类

2.发生异常时按顺序逐个匹配

3.只执行第一个与异常类型匹配的catch语句

异常的分类

Error:程序本身的异常,重启程序或没有解决办法。(现实中硬件出问题了,只能更换硬件)

Exception:分为检查性异常非检查性异

检查性异常:必须在编写代码时,使用try catch捕获。

非检查性异:在Java中所有RuntimeException的派生类都是非检查型异常,与检查型异常对比,非检查型异常可以不在函数声明中添加throws语句,调用函数上也不需要强制处理。如果有异常产生,则异常将由JVM虚拟机进行处理。

log4j记录日志

日志(log)

主要用来记录系统运行中一些重要操作信息。

便于监视系统运行情况,帮助用户提前发现和避开可能出现的问题,或者出现问题后根据日志找到原因。

log4j

控制日志的输出级别。

控制日志信息输送的目的地是控制台、文件等。

控制每一条日志的输出格式。

Java集合框架

Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中

java.util包中常用的类和接口

1.常用接口

(1)Collection

Collection 层次结构 中的根接口。

(2)Iterator

对 collection 进行迭代的迭代器。

(3)List

有序的 collection(也称为序列)。

(4)Map

将键映射到值的对象。

(5)Map.Entry

映射项(键-值对)。

(6)Set
一个不包含重复元素的 collection。

2.常用类

ArrayList

List 接口的大小可变数组的实现。

Arrays

此类包含用来操作数组(比如排序和搜索)的各种方法

Collections

此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。

Date

类 Date 表示特定的瞬间,精确到毫秒。

HashMap

基于哈希表的 Map 接口的实现。

HashSet

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。

Random

此类的实例用于生成伪随机数流。

Timer

一种工具,线程用其安排以后在后台线程中执行的任务。

接口

collection接口存储一组不唯一,无序的对象。

List 接口存储一组不唯一,有序(插入顺序)的对象。

Set 接口存储一组唯一,无序的对象。

Map接口存储一组键值对象,提供key到value的映射。

List:

ArrayList可变数组,在内存中分配连续的空间。访问效率比较高。

LinkedList采用链表存储方式。插入、删除(修改)元素时效率比较高

常用方法

LinkedList:频繁修改时,可使用LinkedList来提高效率。提供头尾元素进行添加和删除操作的方法

使用方法:

迭代器Iterator

如果遇到遍历容器时,判断删除元素的情况,使用迭代器遍历。

/*
*迭代器遍历Set
*/
public class Test {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        for (int i = 0; i < 5; i++) {
            set.add("a" + i);
        }
        System.out.println(set);
        for (Iterator<String> iter = set.iterator(); iter.hasNext();) {
            String temp = iter.next();
            System.out.print(temp + "	");
        }
        System.out.println();
        System.out.println(set);
    }
}

迭代器遍历Map

//1
public class Test {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("A", "王五");
        map.put("B", "小赛文");
        Set<Entry<String, String>> ss = map.entrySet();
        for (Iterator<Entry<String, String>> iterator = ss.iterator(); iterator.hasNext();) {
            Entry<String, String> e = iterator.next();
            System.out.println(e.getKey() + "--" + e.getValue());
        }
    }
}

//2
public class Test {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("A", "王五");
        map.put("B", "小赛");
        Set<String> ss = map.keySet();
        for (Iterator<String> iterator = ss.iterator(); iterator.hasNext();) {
            String key = iterator.next();
            System.out.println(key + "--" + map.get(key));
        }
    }
}

多线程

在一般情况下,创建一个线程是不能提高程序的执行效率的,所以要创建多个线程。但是多个线程同时运行的时候可能调用线程函数,在多个线程同时对同一个内存地址进行写入,由于CPU时间调度上的问题,写入数据会被多次的覆盖,所以就要使线程同步。

在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

好处:

1.充分利用CPU的资源

2.简化编程模型

3.良好的用户体验

主线程

1.main()方法即为主线程入口

2.产生其他子线程的线程

3.必须最后完成执行,因为它执行各种关闭动作

4.终止线程

线程:

1. 一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。
2. 一个进程可拥有多个并行的(concurrent)线程。
3. 一个进程中的多个线程共享相同的内存单元/内存地址空间,可以访问相同的变量和对象,而且它们从同一堆中分配对象并进行通信、数据交换和同步操作。
4. 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。
5. 线程的启动、中断、消亡,消耗的资源非常少。

继承Thread类创建线程

public class TestThread extends Thread {  //自定义类继承Thread类
    
    public void run() {  //run()方法里是线程体
        for (int i = 0; i < 10; i++) {
            System.out.println(this.getName() + ":" + i);
//getName()方法是返回线程名称
        }
    }
 
    public static void main(String[] args) {
        TestThread thread1 = new TestThread();   //创建线程对象
        thread1.start();   //启动线程
        TestThread thread2 = new TestThread();
        thread2.start();
    }
}

多个线程交替执行,线程每次执行时长由CPU决定

Runnable接口创建线程

1.定义MyRunnable类实现Runnable接口

2.实现run()方法,编写线程执行体

3.创建线程对象,调用start()方法启动线程

public class TestThread2 implements Runnable {   //自定义类实现Runnable接口;
    public void run() {    //run()方法里是线程体;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
    public static void main(String[] args) {
        //创建线程对象,把实现了Runnable接口的对象作为参数传入;
        Thread thread1 = new Thread(new TestThread2());
        thread1.start();    //启动线程;
        Thread thread2 = new Thread(new TestThread2());
        thread2.start();
    }
}

线程调度

线程调度指按照特定机制为多个线程分配CPU的使用权

 线程优先级

1.线程优先级由1~10表示,1最低,默认优先级为5

2.优先级高的线程获得CPU资源的概率较大

线程休眠

让线程暂时睡眠指定时长,线程进入阻塞状态

睡眠时间过后线程会再进入可运行状态

public class Wait {
public static void bySec(long s) {
    for (int i = 0; i < s; i++) {
        System.out.println(i + 1 + "秒");
        try {
            Thread.sleep(1000);    //线程休眠1秒(1秒=1000毫秒)
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
                }
         }
}

线程的强制运行

public final void join()

public final void join(long mills)

public final void join(long mills,int nanos)

millis:以毫秒为单位的等待时长

nanos:要等待的附加纳秒时长

需处理InterruptedException异常

死锁及解决方案

死锁的概念

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。

因此, 某一个同步块需要同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题。

“化妆线程”需要同时拥有“镜子对象”、“口红对象”才能运行同步块。那么,实际运行时,“小丫的化妆线程”拥有了“镜子对象”,“大丫的化妆线程”拥有了“口红对象”,都在互相等待对方释放资源,才能化妆。这样,两个线程就形成了互相等待,无法继续运行的“死锁状态”。(一下是百战程序员案例代码)

class Lipstick {//口红类
 
}
class Mirror {//镜子类
 
}
class Makeup extends Thread {//化妆类继承了Thread类
    int flag;
    String girl;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        doMakeup();
    }
 
    void doMakeup() {
        if (flag == 0) {
            synchronized (lipstick) {//需要得到口红的“锁”;
                System.out.println(girl + "拿着口红!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                synchronized (mirror) {//需要得到镜子的“锁”;
                    System.out.println(girl + "拿着镜子!");
                }
 
            }
        } else {
            synchronized (mirror) {
                System.out.println(girl + "拿着镜子!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lipstick) {
                    System.out.println(girl + "拿着口红!");
                }
            }
        }
    }
 
}
 
public class TestDeadLock {
    public static void main(String[] args) {
        Makeup m1 = new Makeup();//大丫的化妆线程;
        m1.girl = "大丫";
        m1.flag = 0;
        Makeup m2 = new Makeup();//小丫的化妆线程;
        m2.girl = "小丫";
        m2.flag = 1;
        m1.start();
        m2.start();
    }
}

 在实际开发中,尤其是“架构设计”中,会大量使用这个模式。这就是必须掌握的内容。

IO流

字节流:二进制,可以一切文件 包括  纯文本 doc 音频、视频等等

字符流:文本文件,只能处理纯文本

输入流和输出流,差别在于出和入,是相对于程序而言的。“输入流式得到数据,输出流是输出数据”,这种说法是对的。你把问题想复杂了,输入是程序得到外部数据,输出是程序向外部传输数据,二者没专有必然的联系,都是流,差别是方向不同,也就是说,程序可以只有输入流而没有输出流,或者只有输出流而没有输入流

原文地址:https://www.cnblogs.com/zhrehe-11/p/12885301.html