一、配置文件
1、概述
在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中,而不是在Java代码写死。我们把这种存放程序配置信息的文件,统称为配置文件。配置文件一般要求有明确的格式,以方便读写操作。
2、Properties
Properties是一个Map集合(键值对集合),但是一般不会当集合使用。
核心作用:Properties是用来代表属性文件的,通过Properties可以读写 .properties属性文件里的内容。
.properties属性文件中每一行都是一个键值对,用=或者空格隔开,且键不能重复,值可以。
使用Properties读取属性文件里的键值对数据:
使用Properties把键值对数据写出到属性文件里去:
示例代码:
public class Demo1 {
public static void main(String[] args) throws Exception {
//1. 创建一个配置文件对象
Properties properties = new Properties();
//2. 读取
properties.load(new FileReader("code-10/user.properties"));
String pwd = properties.getProperty("admin");
System.out.println("admin");
System.out.println(pwd);
//3. 写出
Properties prop2 = new Properties();
prop2.setProperty("王五", "123456");
prop2.setProperty("zhaoliu", "123好好好");
prop2.store(new FileWriter("code-10/user.properties"), "这是从程序写入的文字");
}
}
3、XML
XML全称Extensible Markup Language, 可扩展标记语言;
本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系。
特点:
1.XML中的“<标签名>” 称为一个标签或一个元素,一般是成对出现的。
2.XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套。
3.XML中只能有一个根标签。
4.XML中的标签可以有属性。
5.XML文件的后缀名为:xml,文档声明必须是第一行。
<?xml version="1.0" encoding="UTF-8" ?>
version:XML默认的版本号码、该属性是必须存在的
encoding:本XML文件的编码
6.XML中可以定义注释信息:<!–- 注释内容 -->,快捷键是Ctrl+shift+/。
7.XML中书写”<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 引号
XML中可以写一个叫CDATA的数据区: <![CDATA[ …内容… ]]>,里面的内容可以随便写。直接输入CD,就会有提示
<![CDATA[ 这里面随便输入 ]]>
解析XML文件:
- 最知名的好用的解析XML的框架是:Dom4j(第三方研发的)
Dom4j解析XML-得到Document对象
SAXReader:Dom4j提供的解析器,可以认为是代表整个Dom4j框架
Document
Element提供的方法:
示例代码:
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public class Demo2_2 {
public static void main(String[] args) throws FileNotFoundException, DocumentException {
ArrayList<User1> userList = new ArrayList<>();//创建存储User1对象的list集合(最下面要用的)
//1、将dom4j的jar包加入到项目中
//2、创建DOM4]解析器对象SAXReader
SAXReader saxReader = new SAXReader();
//3、获取Document文档对象,获取根标签对象
//Document的对象看似是只获得了根标签(root标签),其实已经包含了所有的子标签
Document document = saxReader.read(new FileReader("day0908-10/b-2.xml"));
//4、从根标签对象开始往下层层解析
Element rootElement = document.getRootElement();
//获取根标签的名字
String rootElementName = rootElement.getName();
//获取根标签下的所有子标签
List<Element> elements = rootElement.elements();
System.out.println(elements.size());
//遍历拿到的标签集合elements
for (Element element : elements) {
System.out.println("=============");
String name = element.element("name").getText();//获取name标签的内容并得到文本内容
System.out.println("name="+name);
String password = element.elementText("password");
System.out.println("password:"+password);
String address = element.elementText("address");
System.out.println("address:" + address);
String gender = element.elementText("gender");
System.out.println("gender:" + gender);
User1 user1 = new User1(name, password, address, gender);
userList.add(user1);
}
for (User1 user1 : userList) {
System.out.println(user1);
}
}
}
class User1 {
private String name;
private String password;
private String address;
private String gender;
public User1() {
}
public User1(String name, String password, String address, String gender) {
this.name = name;
this.password = password;
this.address = address;
this.gender = gender;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
", gender='" + gender + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
二、日志技术
1、概述
程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息。
我们在初学Java的时候经常用到的输出语句System.out.println()所输出的内容就可以看作是一种日志,但是输出语句有许多弊端:
- 日志会展示在控制台
- 不能更方便的将日志记录到其他的位置(文件,数据库)
- 想取消日志,需要修改源代码才可以完成
在实际项目开发中就会使用日志技术,可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。也可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
日志技术的体系结构:
- 日志接口:设计日志框架的一套标准,日志框架需要实现这些接口。
- 日志框架:大佬或者第三方公司已经做好的实现代码,后来者直接可以拿去使用。
- 注意1:因为对Commons Logging接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback。
- 注意2:Logback是基于slf4j的日志规范实现的框架。
使用Logback日志框架,至少需要在项目中整合slf4j-api日志接口、logback-core核心模块、logback-classic API模块。
2、Logback
使用Logback日志框架的步骤:
1.导入Logback框架到项目中去。(slf4j-api日志接口、logback-core核心模块、logback-classic API模块)
2.将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)
3.创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息
public static final Logger LOGGER = LoggerFactory.getLogger("当前类类名");
核心配置文件logback.xml
对Logback日志框架进行控制的,通常可以设置2个输出日志的位置:一个是控制台、一个是系统文件中:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
开启日志(ALL),取消日志(OFF)
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
ALL 和 OFF分别是打开全部日志和关闭全部日志。
3、Logback设置日志级别
日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(优先级依次升高):
<root level=“info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
只有日志的级别是大于或等于核心配置文件配置的日志级别,才会被记录,否则不记录。
示例代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo1 {
public static final Logger LOGGER = LoggerFactory.getLogger("Demo1");
public static void main(String[] args) {
LOGGER.debug("程序开始");
div(1,0);
}
public static int div(int a, int b) {
LOGGER.debug("方法执行了,a={},b={}",a,b);
try {
int c = a/b;
return c;
}catch (Exception e) {
LOGGER.error("{}/{} 出错了",a,b);
e.printStackTrace();
throw new RuntimeException("好好好");
}
}
}
三、多线程
1、概述
什么是线程:
- 线程:简单的说,就是计算机在做一件事
- 单线程:在计算机中同一时间只能做一件事
- 多线程:在计算机中同一时间可以做多件事
多线程的主要好处有:减少队列阻塞带来的影响、提高CPU的利用率。
2、线程的创建方式
(1)继承Thread类
- 定义一个子类继承线程类java.lang.Thread,重写run()方法
- 创建子类的对象
- 调用子类对象的start()方法启动线程(底层会自动去执行run方法)
优缺点:
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。
示例代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo1 {
public static final Logger LOGGER = LoggerFactory.getLogger("Demo1");
public static void main(String[] args) {
LOGGER.info("程序开始");
//需求:创建两个线程,分别用于打印10个A和10个B,最后观察下输出顺序
//创建子类的对象
AThread aThread = new AThread();
BThread bThread = new BThread();
//调用子类对象的start()方法启动线程(底层会自动去执行run方法)
aThread.start();
bThread.start();
}
}
/**
* 定义一个子类继承线程类java.lang.Thread,重写run()方法
*/
class AThread extends Thread {
public static final Logger LOGGER = LoggerFactory.getLogger("AThread");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.debug("AThread-A{}", i );
}
}
}
/**
* 定义一个子类继承线程类java.lang.Thread,重写run()方法
*/
class BThread extends Thread {
public static final Logger LOGGER = LoggerFactory.getLogger("BThread");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.debug("BThread-B{}", i );
}
}
}
创建两个分别继承了Thread的类,main方法中创建这两个类的对象,然后对象之间调用start()方法即可实现多线程启动。
注意事项:
1.启动线程必须是调用start方法,不是调用run方法
- 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行
- 只有调用start方法才是启动一个新的线程执行
- 这样主线程一直是先跑完的,相当于是一个单线程的效果了
2.不要把主线程任务放在启动子线程之前
(2)实现Runnable接口
- 定义一个线程任务类实现Runnable接口,重写run()方法
- 创建任务类对象
- 把任务类对象交给Thread处理、
- 调用线程对象的start()方法启动线程
优缺点:
优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
缺点:需要多一个Runnable对象,如果线程有执行结果是不能直接返回的。
示例代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo1 {
public static void main(String[] args) {
//需求:创建两个线程,分别用于打印10个A和10个B,最后观察下输出顺序
//创建任务类对象
AThread aThread = new AThread();
BThread bThread = new BThread();
//把任务类对象交给Thread处理
Thread t1 = new Thread(aThread);
Thread t2 = new Thread(bThread);
//调用线程对象的start()方法启动线程
t1.start();
t2.start();
}
}
/**
* 定义一个线程任务类实现Runnable接口,重写run()方法
*/
class AThread implements Runnable {
public static final Logger LOGGER = LoggerFactory.getLogger("AThread");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.debug("AThread-A{}", i );
}
}
}
/**
* 定义一个线程任务类实现Runnable接口,重写run()方法
*/
class BThread implements Runnable {
public static final Logger LOGGER = LoggerFactory.getLogger("BThread");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.debug("BThread-B{}", i );
}
}
}
(3)实现Callable接口
JDK 5.0提供了Callable接口和FutureTask类来实现多线程,这种方式最大的优点:可以返回线程执行完毕后的结果。
1.创建任务对象
- 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
- 把Callable类型的对象封装成FutureTask(线程任务对象)
2.把线程任务对象交给Thread对象
3.调用Thread对象的start方法启动线程
4.线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果
FutureTask的API
优缺点:
优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
缺点:编码复杂一点。
示例代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Demo1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//需求:启动两个子线程,分别计算100之内的奇数的和和偶数的和,然后在主线程中再做个汇总,得到总和
AThread aThread = new AThread();
BThread bThread = new BThread();
// 把Callable类型的对象封装成FutureTask(线程任务对象)
FutureTask<Integer> aFutureTask = new FutureTask<>(aThread);
FutureTask<Integer> bFutureTask = new FutureTask<>(bThread);
//把线程任务对象交给Thread对象。
Thread t1 = new Thread(aFutureTask);
Thread t2 = new Thread(bFutureTask);
//调用Thread对象的start方法启动线程
t1.start();
t2.start();
//线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果
Integer aSum = aFutureTask.get();
Integer bSum = bFutureTask.get();
int sum =aSum + bSum;
System.out.println("sum=" +sum);
}
}
/**
* 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
*/
class AThread implements Callable<Integer> {
public static final Logger LOGGER = LoggerFactory.getLogger("AThread");
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i+=2) {
sum += i;
}
return sum;
}
}
/**
* 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
*/
class BThread implements Callable<Integer> {
public static final Logger LOGGER = LoggerFactory.getLogger("BThread");
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i+=2) {
sum += i;
}
return sum;
}
}
3、Thread类的方法
获取线程名称、设置线程名称、拿到当前线程对象、线程休眠、线程优先执行(join)等方法
示例代码:
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//在主线程序中创建A、B两个子线程
A a = new A();
B b = new B();
//在主线程序中开启A、B两个子线程
a.start();
//B线程要等A线程打印完毕,再开始打印
a.join();
b.start();
}
}
/**
* 创建A、B两个线程类,分别打印1~5
*/
class A extends Thread {
@Override
public void run() {
for (int i = 1; i <= 5 ; i++) {
System.out.println("A-->" +i);
try {
//让A线程每打印一次,都要暂停3秒钟
Thread.sleep(3000);
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
class B extends Thread{
@Override
public void run(){
for(int i=1;i<=5;i++){
System.out.println("B-->"+i);
}
}
}
标签:Java,String,配置文件,Thread,线程,new,日志,多线程,public
From: https://blog.csdn.net/weixin_69134024/article/details/142032664