1.配置文件
1.1配置文件的介绍
在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中,而不是在Java代码
写死 我们把这种存放程序配置信息的文件,统称为配置文件
配置文件一般要求有明确的格式,以方便读写操作。
1.2Properties
Properties是一个Map集合(键值对集合),但是我们一般不会当集合使用。
核心作用:Properties是用来代表属性文件的,通过Properties可以读写属性文件里的内容。
Properties的常用方法:
Properties的读取和写入方法:
读取:
写入:
1.3XML
XML全称Extensible Markup Language, 是可扩展标记语言,本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系。
XML的特点:
1.XML中的“<标签名>” 称为一个标签或一个元素,一般是成对出现的。
2.XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套。
3.XML中只能有一个根标签。
4.XML文件中可以定义注释信息:<!–- 注释内容 -->
5.标签必须成对出现,有开始,有结束标签: <name></name>
详细API SAXReader:Dom4j提供的解析器,可以认为是代表整个Dom4j框架 public SAXReader() 构建Dom4J的解析器对象 public Document read(String path) 把XML文件读成Document对象 Element getRootElement() 获得根元素对象 public String getName() 得到元素名字 public List<Element> elements() 得到当前元素下所有子元素 public List<Element> elements(String name) 得到当前元素下指定名字的子元素返回集合 public Element element(String name) 得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个 public String attributeValue(String name) 通过属性名直接得到属性值 public String elementText(子元素名) 得到指定名称的子元素的文本 public String getText() 得到文本
实例:使用dom4j将xml文件中的内容封装到一个List<User对象的集合>
public class Demo2 {
public static void main(String[] args) throws Exception {
//需求: 解析b-2.xml,将内容封装到一个List<User对象的集合>
//将dom4j的jar包加入到项目中
//创建DOM4]解析器对象SAXReader,获取Document文档对象,获取根标签对象
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new FileReader("F:\\WorkSpace\\JaveSePlus\\day010-review\\src\\b-2.xml"));
//获得根元素对象,开始往下层层解析
Element root = document.getRootElement();
//获取根标签的名字
String rootName = root.getName();
System.out.println("rootName:" + rootName);
//获取根标签下所有子标签
List<Element> elements = root.elements();
ArrayList<User> users = new ArrayList<User>();
//遍历标签的集合
for (Element element : elements) {
System.out.println("========");
//获取子标签的名字
String name = element.getName();
//获取子标签的id属性值
String id = element.attributeValue("id");
System.out.println("子标签名字:" + name + id);
//获取子标签的name标签的文本
String userName = element.element("name").getText();
//获取子标签的password标签的文本
String password = element.element("password").getText();
//获取子标签的address标签的文本
String address = element.element("address").getText();
//获取子标签的gender标签的文本
String gender = element.element("gender").getText();
users.add(new User(userName, password, address, gender));
}
users.forEach(System.out::println);
}
}
class User {
private String name;
private String password;
private String address;
private String gender;
public User() {
}
public User(String name, String password, String address, String gender) {
this.name = name;
this.password = password;
this.address = address;
this.gender = gender;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return password
*/
public String getPassword() {
return password;
}
/**
* 设置
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取
* @return address
*/
public String getAddress() {
return address;
}
/**
* 设置
* @param address
*/
public void setAddress(String address) {
this.address = address;
}
/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "User{name = " + name + ", password = " + password + ", address = " + address + ", gender = " + gender + "}";
}
}
2.日志技术
日志:好比生活中的日记,可以记录你生活中的点点滴滴。 程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息。
日志的优点:可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
2.1Logback快速入门
需求 使用Logback日志框架,纪录系统的运行信息。 实现步骤 1. 导入Logback框架到项目中去。 2. 将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。 4. 创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息。 public static final Logger LOGGER = LoggerFactory.getLogger("当前类类名"); 5. 打印日志 LOGGER.info("日志信息") LOGGER.debug("日志信息") LOGGER.error("日志信息")
2.2Logback设置日志级别
日志的级别:常用的有info、warn、error
在logback.xml中可以自己设置日志的级别,当级别大于所设置的级别时,日志才会输出
3.多线程
线程:简单的说,就是计算机在做一件事
单线程:在计算机中同一时间只能做一件事
多线程:在计算机中同一时间可以做多件事
其实多线程在我们的生活中的使用场景很多,比如网盘的上传下载,12306的多窗口售票等等
它的主要好处有:1. 减少队列阻塞带来的影响 2. 提高CPU的利用率
3.1线程的创建方式
线程的创建方式有三种:
多线程的创建方式一:继承Thread类
1. 定义一个子类继承线程类java.lang.Thread,重写run()方法
2. 创建子类的对象
3. 调用子类对象的start()方法启动线程(底层会自动去执行run方法)
优缺点
优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。
注意事项
1、启动线程必须是调用start方法,不是调用run方法。
2、直接调用run方法会当成普通方法执行,只有调用start方法才是启动一个新的线程执行。
3、不要将主线任务放在start方法之前,这样主线程一直是先跑完的,相当于是一个单线程的效果了。
实例:创建两个线程,分别打印10个A和10个B,观察输出顺序
public class Demo1 {
public static void main(String[] args) {
//2. 创建子类的对象
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
//3. 调用子类对象的start()方法启动线程(底层会自动去执行run方法)
threadA.start();
threadB.start();
}
}
//创建两个线程,并且继承线程java.lang.Thread,重写run()方法
class ThreadA extends Thread {
public static final Logger LOGGER = LoggerFactory.getLogger("ThreadA");
@Override
public void run() {
for (int i = 0; i < 10; i++){
LOGGER.info("A->"+i);
}
}
}
class ThreadB extends Thread {
public static final Logger LOGGER = LoggerFactory.getLogger("ThreadB");
@Override
public void run() {
for (int i = 0; i < 10; i++){
LOGGER.info("B->"+i);
}
}
}
最终打印结果:
多线程的创建方式二:实现Runnable接口 1. 定义一个线程任务类实现Runnable接口,重写run()方法 2. 创建任务类对象 3. 把任务类对象交给Thread处理 public Thread(Runnable target) 4. 调用线程对象的start()方法启动线程 优缺点 优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。 缺点:需要多一个Runnable对象。
实例:创建两个线程,分别打印10个A和10个B,观察输出顺序
public class Demo1 {
public static void main(String[] args) {
// 2. 创建任务类对象
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
//3. 把任务类对象交给Thread处理
//public Thread(Runnable target)
Thread threada = new Thread(threadA);
Thread threadb = new Thread(threadB);
//4. 调用线程对象的start()方法启动线程
threada.start();
threadb.start();
}
}
// 1. 定义两个线程任务类实现Runnable接口,重写run()方法
class ThreadA implements Runnable {
public static final Logger LOGGER = LoggerFactory.getLogger("ThreadA");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.info("A->" + i);
}
}
}
class ThreadB implements Runnable {
public static final Logger LOGGER = LoggerFactory.getLogger("ThreadB");
@Override
public void run() {
for (int i = 0; i < 10; i++) {
LOGGER.info("B->" + i);
}
}
}
最终打印结果:
多线程的创建方式三:实现Callable接口 1. 创建任务对象 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据 把Callable类型的对象封装成FutureTask(线程任务对象) public FutureTask<>(Callable call) 把Callable对象封装成FutureTask对象 public V get() throws Exception 获取线程执行call方法返回的结果 2. 把线程任务对象交给Thread对象。 3. 调用Thread对象的start方法启动线程。 4. 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果 优缺点 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果 缺点:编码复杂一点。
启动两个子线程,分别计算100之内的奇数的和和偶数的和,然后在主线程中再做个汇总,得到总和:
public class Demo1 {
public static final Logger LOGGER = LoggerFactory.getLogger("Demo1");
public static void main(String[] args) throws ExecutionException, InterruptedException {
//把Callable类型的对象封装成FutureTask(线程任务对象)
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
//public FutureTask<>(Callable call) 把Callable对象封装成FutureTask对象
FutureTask<Integer> ftA = new FutureTask<>(threadA);
FutureTask<Integer> ftB = new FutureTask<>(threadB);
// 2. 把线程任务对象交给Thread对象。
Thread thread1 = new Thread(ftA);
Thread thread2 = new Thread(ftB);
thread1.start();
thread2.start();
//public V get() throws Exception 获取线程执行call方法返回的结果
Integer i = ftA.get();
Integer j = ftB.get();
//4. 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果
LOGGER.info("奇数和为{}",i);
LOGGER.info("偶数和为{}",j);
LOGGER.info("总和为{}",i+j);
}
}
// 1. 创建任务对象
// 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
class ThreadA implements Callable<Integer> {
int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 1; i < 100; i += 2) {
count += i;
}
return count;
}
}
class ThreadB implements Callable<Integer> {
int count = 0;
@Override
public Integer call() throws Exception {
for (int i = 2; i < 100; i += 2) {
count += i;
}
return count;
}
}