学习JavaEE的日子 Day28 异常,多线程

Day28

1.异常机制

1.1 异常概念

异常是程序在运行期发生的不正常的事件,它会打断指令的正常执行流程。

设计良好的程序应该在异常发生时提供处理这些不正常事件的方法,使程序不会因为异常的发生而阻断或产生不可预见的结果。

​ Java语言使用异常处理机制为程序提供了异常处理的能力

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。

在这里插入图片描述

1.2 异常分类

Java程序运行过程中所发生的异常事件从严重性可分为两类:

1、 错误(Error):JVM系统内部错误或资源耗尽等严重情况-属于JVM需要负担的责任这一类异常事件无法恢复或不可能捕获,将导致应用程序中断。

2、 异常(Exception):其它因编程错误或偶然的外在因素导致的一般性问题。这类异常得到恰当的处理时,程序有机会恢复至正常运行状况。

在这里插入图片描述

1.2.1 错误出现的情况

错误(Error):JVM系统内部错误或资源耗尽等严重情况,属于JVM需要负担的责任,这一类异常事件无法恢复或不可能捕获,将导致应用程序中断。

错误Error,无法通过处理的错误,只能事先避免,好比绝症。

public class Test01 {public static void main(String[] args) {//StackOverflowError - 栈内存溢出的错误//出现原因:调用方法会在栈中开辟空间,用于存放该方法的局部变量,死循环的调用方法,栈内存就满载并溢出了method();}public static void method(){method();}
}
public class Test02 {public static void main(String[] args) {//OutOfMemoryError -- 内存溢出的错误//出现原因:new出来的数组添加到集合中,该数组不会被回收ArrayList<byte[]> list = new ArrayList<>();while(true){byte[] bs = new byte[8192];list.add(bs);}		}
}
1.2.2 异常出现的情况

异常(Exception):其它因编程错误或偶然的外在因素导致的一般性问题。

这类异常得到恰当的处理时,程序有机会恢复至正常运行状况。

分类:

RuntimeException – 非受检性异常

一般性异常 --------- 受检性异常

非受检性异常

RuntimeException(非受检性异常):

编译器不要求强制处置的异常。一般是指编程时的逻辑错误。是程序员应该积极避免其出现的异常。

注意:java.lang.RuntimeException及它的子类都是非受检异常

错误的类型转换:java.lang.ClassCastException

数组下标越界:java.lang.ArrayIndexOutOfBoundsException

空指针访问:java.lang.NullPointerException

算术异常(除0溢出):java.lang.ArithmeticException

public class Test03 {public static void main(String[] args) {//ArithmeticException -- 算数异常System.out.println(10/0);//ArrayIndexOutOfBoundsException -- 数组下标越界异常int[] arr = {1,2,3};System.out.println(arr[1000]);//IndexOutOfBoundsException - 下标越界异常ArrayList<Object> list = new  ArrayList<>();System.out.println(list.get(100));//ClassCastException - 类型转换异常Object obj = new Integer(100);String str = (String) obj;System.out.println(str);//NullPointerException --空指针异常String str = null;method(str);}public static void method(String str) {System.out.println(str.length());}}
受检性异常

一般性异常(受检性异常):编译器要求必须处置的异常。指的是程序在运行时由于外界因素造成的一般性异常。

没有找到指定名称的类:java.lang.ClassNotFoundException

访问不存在的文件:java.io.FileNotFoundException

操作文件时发生的异常:java.io.IOException

操作数据库时发生的异常:java.sql.SQLException

public class Test08 {public static void main(String[] args) throws ClassNotFoundException {	//ClassNotFoundException -- 类未找到异常Class<?> clazz = Class.forName("java.lang.String111111");System.out.println(clazz);//FileNotFoundException - 文件未找到异常FileInputStream fis = new FileInputStream("C:\\Users\\Desktop\\异常理解图.png");System.out.println(fis);}}

1.3 Java的异常处理机制(面试题)

1.Java程序在执行过程中如果出现异常,会自动生成一个异常类对象, 该异常对象将被自动提交给JVM,这个过程称为抛出(throw)异常。

2.当JVM接收到异常对象时,会寻找能处理这一异常的代码

​ 3.1 找到了 - 把当前异常对象交给其处理,这一过程称为捕获(catch)异常和处理异常。

​ 3.2 没找到 - 运行时系统将终止,相应的Java程序也将退出。

1.4 Java处理异常的能力

1.try…catch…

2.throws

3.throw

1.4.1 try…catch…

语法结构:

try{

​ … //可能产生异常的代码

}catch( ExceptionName1 e ){

​ … //异常的处理代码

}catch( ExceptionName2 e ){

… //异常的处理代码

} finally{

… //无论如何都会执行的语句

}

理解:

try:该代码块中编写可能产生异常的代码。

catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。

场景:处理一个异常的情况

public class Test01 {		public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请输入一个数字:");int a = scan.nextInt();System.out.println("请输入第二个数字:");int b = scan.nextInt();try{System.out.println("111");System.out.println(a/b);System.out.println("222");}catch (ArithmeticException e) {System.out.println("处理算数异常");}finally {scan.close();}}		
}

场景:处理多个异常,但处理方式不一样的情况

注意:

1.finally代码块根据需求可写可不写

2.经验告诉我们关闭资源的代码一般写在finally

3.try…catch…可以有多个catch

4.try 代码段包含的是可能产生异常的代码

5.先捕获的异常范围不能大于后捕获的异常范围

6.当异常发生时,程序会中止当前的流程去执行相应的catch代码段。

7.finally段的代码无论是否发生异常都执行

public class Test02 {public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请输入一个数字:");int a = scan.nextInt();System.out.println("请输入第二个数字:");int b = scan.nextInt();System.out.println("请输入类的全路径:");String classPath = scan.next();try{System.out.println("111");System.out.println(a/b);System.out.println("222");Class<?> clazz = Class.forName(classPath);System.out.println(clazz.getName());System.out.println("333");}catch (ArithmeticException e) {System.out.println("处理算数异常");}catch (ClassNotFoundException e){System.out.println("处理类未找到异常");}finally {scan.close();}}}
1.4.2 throws

在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用出进行处理。

1.本身的程序处理不了了,往上一层抛,由上一层去处理

2.定义一个方法的时候,通过这种方式来告知调用方,我这个方法有可能会发生异常的。

语法结构:

public void method() throws 异常1,异常2{}

理解:

throws是抛出异常

抛给方法的调用方

一层一层往上面抛,最后try…catch…处理

注意:此时抛出的是异常类型,并且抛出的异常类型是紧跟在方法名之后。

关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).

public class Test01 {public static void main(String[] args) {try {method01();} catch (ClassNotFoundException e) {System.out.println("处理异常");}}public static void method01() throws ClassNotFoundException{method02();}public static void method02() throws ClassNotFoundException{method03();}public static void method03() throws ClassNotFoundException{Scanner scan = new Scanner(System.in);System.out.println("请输入类的全路径:");String classPath = scan.next();Class<?> clazz = Class.forName(classPath);System.out.println(clazz.getName());scan.close();}
}
1.4.3 throw

异常不仅仅虚拟机可以抛,我们自己也可以抛。我们可以在代码中使用throw关键字(注意不带s)来抛出某个具体的异常对象。很多情况下我们会手动抛出运行时异常。

语法结构:

throw new 异常(); //抛给自己写的异常类

throw new NullPointerException(“要访问的arr数组不存在”); //直接解决,不用创建异常类

理解:

手动抛出异常—throw new RuntimeException(“程序出现了异常”);

throw 结合自定义异常使用(自己写一个异常类)

throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

public class Test01 {public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请输入一个数字:");int a = scan.nextInt();System.out.println("请输入第二个数字:");int b = scan.nextInt();try {if(b == 0){throw new MyException(); //throw new Exception("XXXX");}} catch (MyException e) { //这里也要写自己写的异常类 或者 Exception eb = 1;System.out.println(e);}System.out.println(a/b);scan.close();}
}

创建自定义异常,需要继承Exception 或其子类。

public class MyException extends Exception{@Overridepublic String toString() {return "除数不能为0的异常";}
}

多线程

1.什么是进程

进程是系统进行资源分配和调用的独立单元,每一个进程都有它的独立内存空间和系统资源。

2.单进程操作系统和多进程操作系统的区别

单进程操作系统:dos(一瞬间只能执行一个任务)

多进程单用户操作系统:Windows(一瞬间只能执行多个任务)

多进程多用户操作系统:Linux(一瞬间只能执行多个任务)

3.现在的多核CPU是否可以让系统在同一个时刻可以执行多个任务吗?

理论上是可以的

4.什么是线程,理解线程和进程的关系

什么是线程?

线程是进程里面的一条执行路径,每个线程同享进程里面的内存空间和系统资源

一个进程 可以有 多个线程:各个线程都有不同的分工

理解线程和进程的关系

进程 与 进程 之间的关系:进程之间的内存空间和系统资源是独立的

同一个进程里的多条线程 :线程之间的内存空间和系统资源是共享的

进程里:可以有一条或一条以上的线程

进程里只有一条线程的情况下,这条线程就叫做主线程

进程里有多条线程的情况下,只有一条线程叫做主线程

Ps:线程是在进程里的,他们是包含关系

5.我们应用的软件有哪些是多线程的应用?

都是

6.Java中,如何来编写多线程的应用程序?有哪些方法

6.1 创建线程 – 线程类(继承Thread类)

步骤:

1.创建线程类(MyThread),继承Thread,重写run方法

2.创建子线程 – MyThread t = new MyThread();

3.启动线程 ---- t.start();

public class Test01 {public static void main(String[] args) {//创建子线程MyThread t = new MyThread();//启动子线程t.start();}
}
public class MyThread extends Thread{//该线程的对象抢到CPU资源后,才会调用run方法@Overridepublic void run() {System.out.println("MyThread类中的run方法被调用了");}
}

void run() :在线程开启后,此方法将被调用执行

void start() :使此线程开始执行,Java虚拟机会调用run方法()

- 两个小问题

- 为什么要重写run()方法?

因为run()是用来封装被线程执行的代码

- run()方法和start()方法的区别?

run():封装线程执行的代码,直接调用,相当于普通方法的调用

start():启动线程;然后由JVM调用此线程的run()方法

6.2 创建线程 – 任务类(实现Runnable接口)

步骤:

1.创建任务类(Task),实现Runnable接口中的run方法

2.创建任务类对象 – Task task = new Task();

3.创建子线程,并把任务交给他 – Thread t = new Thread(task);

4.启动线程 – t.start();

public class Test01 {public static void main(String[] args) {//创建任务类对象Task task = new Task();//创建子线程,并把任务交给他Thread t = new Thread(task);//启动线程t.start();}
}
public class Task implements Runnable{//线程对象抢到CPU资源后才会调用run方法@Overridepublic void run() {System.out.println("Task类中的run方法被调用了");}}

3.带返回值的任务类

4.线程池

七、感受多线程之间争抢资源的场景

需求:编写一个多线程的应用程序,主线程打印1-100之间的数字,子线程打印200-300之间的数字,观察其输出的结果,体会多线程互相争抢资源的场景

public class Test01 {public static void main(String[] args) {MyThread t = new MyThread();t.start();for (int i = 1; i <= 100; i++) {System.out.println("主线程:" + i);}}
}
public class MyThread extends Thread{@Overridepublic void run() {for (int i = 200; i <= 300; i++) {System.out.println("子线程:" + i);}}
}

八、小结

进程 与 进程 的关系:独享内存空间和系统资源

线程 与 进程 的关系:有一个进程中至少包含一个线程

线程 与 线程 的关系:在同一个进程里,多个线程共享内存空间和系统资源

一个进程中包含多个线程,只有一个主线程

经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为单线程的?为什么?

不是,是多线程,因为还有垃圾回收器

垃圾回收器是一个后台线程

九、线程的优先级别

含义:给线程定义抢到CPU资源的优先级

理解:

1.优先级别:1~10,数字越大,优先级越高

2.线程的优先级别不能决定线程是否优先抢到资源,优先级别只能影响(概率问题)

需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。

a.setPriority(Thread.MAX_PRIORITY);//10
b.setPriority(Thread.NORM_PRIORITY);//5 — 默认的
c.setPriority(Thread.MIN_PRIORITY);//1

final int getPriority():返回此线程的优先级

final void setPriority(int newPriority):更改此线程的优先级线程默认优先级是5;线程优先级的范围是:1-10

public class Test01 {public static void main(String[] args) {A a = new A();B b = new B();C c = new C();//设置优先级别 --- a抢到资源的概率大一点,c小一点a.setPriority(Thread.MAX_PRIORITY);//10b.setPriority(Thread.NORM_PRIORITY);//5c.setPriority(Thread.MIN_PRIORITY);//1a.start();b.start();c.start();}
}
public class A extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("A:" + i);}}
}
public class B extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("B:" + i);}}
}
public class C extends Thread{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("C:" + i);}}
}

- 线程调度

- 两种调度方式

- 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

- 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些

- Java使用的是抢占式调度模型

- 随机性

假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的

十、给线程自定义名称

  1. 自己写getThreadName/setThreadName
  2. 调用父类的一个参数的构造方法和getName
  3. Thread.currentThread().getName()

有多个类,有相同的功能,就可以不用一个一个创建类,直接创一个MyThread类,有参构造传参就可以了

需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。

public class Test01 {public static void main(String[] args) {MyThread a = new MyThread("A");MyThread b = new MyThread("B");MyThread c = new MyThread("C");//设置优先级别a.setPriority(Thread.MAX_PRIORITY);//10b.setPriority(Thread.NORM_PRIORITY);//5c.setPriority(Thread.MIN_PRIORITY);//1a.start();b.start();c.start();}
}
public class MyThread extends Thread{private String threadName;public MyThread(String threadName) {  //有参构造this.threadName = threadName;}@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(threadName + ":" + i);}}
}

另外一种写法:

public class MyThread extends Thread{public MyThread(String name) {super(name);}@Overridepublic void run() {//获取当前线程对象Thread t = Thread.currentThread();for (int i = 1; i <= 100; i++) {System.out.println(t.getName() + ":" + i);}}
}

String getName():返回此线程的名称

Thread currentThread() :返回对当前正在执行的线程对象的引用

十一、让线程休眠

需求:编写一个抽取学员回答问题的程序,要求倒数三秒后输出被抽中的学员姓名

Thread.sleep(1000);

此方法为静态方法,写在哪个线程中,哪个线程就休眠

public class Test01 {public static void main(String[] args) throws InterruptedException {String[] names = {"小浩","小李","小伟","小燕","小威","小彭","小王"};Random random = new Random();int index = random.nextInt(names.length);for(int i = 3;i>0;i--){System.out.println(i);//Thread的静态方法 -- sleep(毫秒),表示让当前线程休眠Thread.sleep(1000);}System.out.println(names[index]);// 3 2 1 小李}
}   

static void sleep(long millis) :使当前正在执行的线程停留(暂停执行)指定的毫秒数

总结

1.异常
异常的概念
异常的分类
异常处理机制 – 面试题
异常处理的能力:
1.try…catch…
2.throws
3.throw

2.多线程
进程的概念
线程的概念
创建线程的方式(线程类、任务类)
线程的优先级别
给线程命名
线程的休眠

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/759723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW柴油机安保监控系统

LabVIEW柴油机安保监控系统 随着航运业的快速发展&#xff0c;确保船舶柴油机的安全稳定运行变得尤为重要。船舶柴油机故障不仅会导致重大的经济损失&#xff0c;还可能危及人员安全和环境。设计并开发了一套基于LabVIEW平台的柴油机安保监控系统&#xff0c;旨在通过实时监控…

Python数学建模-2.9Matplotlib库

Matplotlib库是Python中一个非常流行的绘图库&#xff0c;它提供了大量的绘图工具&#xff0c;可以生成各种类型的静态、动态、交互式的图表。Matplotlib的设计初衷是为了与NumPy配合使用&#xff0c;从而提供一个强大的数学绘图工具。 1.Matplotlib的主要特点 丰富的图表类型…

Ubuntu18.04显示--有线连接未托管

引用: Ubuntu18.04连不网 报"有线连接未托管"_ubuntu20.04以太网未托管-CSDN博客 正文 虚拟机环境配置&#xff1a; VirtaualBox Ubuntu18.04桌面版 问题现象&#xff1a; Ubuntu18.04虚拟机的桌面上提示“有线连接未托管”&#xff0c;虚拟机不能上网&#xf…

抖音视频批量下载软件可导出视频分享链接|手机网页视频提取|视频爬虫采集工具

解锁抖音视频无水印批量下载新姿势&#xff01; 在快节奏的生活中&#xff0c;抖音作为时下最热门的短视频平台之一&#xff0c;吸引着广大用户的目光。而如何高效地获取喜欢的视频内容成为了许多人关注的焦点。Q:290615413现在&#xff0c;我们推出的抖音视频批量下载软件&…

初始Java篇(JavaSE基础语法)(3)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 目录 方法的使用 方法定义 实参和形参的关系 方法重载 方法签名 递归 方法的使用 方法就是一个代码片段. 类似于 C 语言中的 "函数"…

WordPress Plugin NotificationX插件 SQL注入漏洞复现(CVE-2024-1698)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。 0x02 漏洞概述 WordPress plugin NotificationX是一个应用插件。2.8.2版本及之前 存在安全漏洞,该…

音频转换器哪个好?5个角度详细测评~

我们常常会用到音频转换器&#xff0c;比如因为平台和设备对某些格式的不兼容&#xff0c;需要进行格式转换&#xff1b;比如有些音频文件可能过大&#xff0c;需要转换为更高效&#xff1b;压缩格式以节省存储空间或加快传输速度&#xff1b;比如调整音频文件的比特率、采样率…

Dijkstra算法

Dijkstra算法用于求无向图或者有向图中起点到各个顶点的最短路径&#xff0c;且边的权值需要为非负数下面这个题就可以用该算法求解 743. 网络延迟时间 有 n 个网络节点&#xff0c;标记为 1 到 n。 给你一个列表 times&#xff0c;表示信号经过 有向 边的传递时间。 times[i]…

【实例】React 组件传值方法: Props、回调函数、Context、路由传参

React原始传值方法 借用状态管理库的传值见下篇文&#xff1a;MobX 和 Redux 【实例】React 状态管理库 MobX Redux 入门及对比 文章目录 React原始传值方法父组件->子组件 props子组件->父组件 回调函数Context路由传值 父组件->子组件 props 父组件可以通过属性&a…

matlab实现对全球不规则投影数据的投影转换

前几个专栏我们讨论了几个不规则的投影转换问题&#xff0c;有需要的可以阅读以下文章&#xff1a; matlab实现对极地投影数据的投影转换_matlab极地投影-CSDN博客 联合matlab和Arcgis进行netcdf格式的雪覆盖数据的重新投影栅格-CSDN博客 这次遇到的问题是一个墨卡托投影的数据…

【机器学习】基于粒子群算法优化的BP神经网络分类预测(PSO-BP)

目录 1.原理与思路2.设计与实现3.结果预测4.代码获取 1.原理与思路 【智能算法应用】智能算法优化BP神经网络思路【智能算法】粒子群算法&#xff08;PSO&#xff09;原理及实现 2.设计与实现 数据集&#xff1a; 多输入多输出&#xff1a;样本特征24&#xff0c;标签类别4…

【web算法】列车车厢重排问题

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

大数据开发--02.环境准备

一.准备三台linux虚拟机 1.分别取名node1,node2,node3 2.配置静态ip 这里以node1为例&#xff0c;配置静态ip地址&#xff0c;其他node2.node3一样 配置完成之后别忘记 systemctl restart network 3.在各自的/etc/hosts文件中编辑三个Ip地址 三台都要配置&#xff0c; 4.然…

【PostGresql】------ pg多表数据多个条件汇总 使用 union 方法示例代码

1. 示例代码如下&#xff1a; SELECT"ID","DT_DATE","CNAME","RMAN_NAME","DEP_NAME","DEP_ID","INVEST_MAN_NAME","TYPE_NAME","INVEST_LEVEL_NAME","POSITION_NAME",…

第1关:创建数据库

任务描述 创建一个名为mydata的数据库。 相关知识 MySQL创建数据库的语法如下&#xff1a; 其中&#xff0c;database_name是要创建的数据库的名称。 开始你的任务吧&#xff0c;祝你成功&#xff01; #请在此处添加实现代码 ########## Begin ########## CREATE DATABASE …

asp.net在线租车平台

说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net架构和sql server数据库 功能模块&#xff1a; asp.net在线租车平台 用户功能有首页 行业新闻用户注册车辆查询租车介绍访问后台 后台管理员可以进行用户管理 管…

ubuntu20.04安装Pycharm

下载pycharm安装包 https://www.jetbrains.com/pycharm/download/#sectionlinux 使用社区版点击download 下载好的pycharm如图所示&#xff0c;右键解压&#xff1a; 打开终端&#xff0c;输入cd命令&#xff0c;进入刚刚解压文件夹下的bin文件夹&#xff0c;命令行是cd 文…

19.WEB渗透测试--抓包技术(下)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;18.WEB渗透测试--抓包技术&#xff08;上&#xff09;-CSDN博客 Burp含义和内容参考&…

CCDP.01.使用NotePad++辅助部署OpenStack的说明

前言 对于象OpenStack&#xff08;OS&#xff09;这样的复杂分布式系统&#xff08;云计算平台&#xff09;&#xff0c;一次部署通过是需要相当的Linux基础、网络基础、分布式系统基础、云计算基础的。这里类比在开发大型复杂系统常常采用的“防御式编程”方法论&#xff0c;探…

写一个简单的 C++ 日志库 - cllogger(3)- CRT

通过上一篇 《写一个简单的 C 日志库 - cllogger&#xff08;2&#xff09;- 日期时间》我们已经掌握了如何通过 std::chrono 提供的日期时间工具转换时间参数为指定格式的字符串。 现在我们可以把各个参数信息拼装为 Entry 实例&#xff0c;交给 OutputMessage() void cllog…