Java日报
部门: **大数据开发六部
姓名: cqmfx(阡陌飞絮)
日期: 2020.11.7
大纲
一、设计(单例)模式
二、初涉线程
三、初涉异常
四、计算每个单词出现的次数
五、归并和效率
Java单例模式+初涉线程+计算每个单词出现的次数+归并和效率
一、设计(单例)模式
1、设计模式的类别(经常使用)
工厂模式(常用)
抽象工厂模式
单例模式(常用)
桥接模式
装饰器模式
代理模式(常用)
观察者模式
策略模式
模板模式
2、单例模式
1)定义
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
2)介绍
**意图:**保证一个类仅有一个实例,并提供一个访问它的全局访问点。
**主要解决:**一个全局使用的类频繁地创建与销毁。
**何时使用:**当您想控制实例数目,节省系统资源的时候。
**如何解决:**判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
**关键代码:**构造函数是私有的。
3)懒汉模式
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class SingLeton2 {
/**
* 懒汉式
*/
// 不去内存里分配空间
// 需要一个静态的成员变量保存咱们的实例
private static SingLeton2 SINGTION2;
// 私有化的构造器 不让外面new
// 不能通过new关键字来构造对象
private SingLeton2(){}
// 持有一个方法,这个方法能返回内存当中的实例
// 通过getInstance来获取 调取这个方法 看一下静态的变量 如果是空 new一个
// 不是空就进不了方法 直接返回 用的时候new 不用的时候 就不new 不到最后的时候不干
public static SingLeton2 getInstance() {
if (SINGTION2 == null){
SINGTION2 = new SingLeton2();
}
return SINGTION2; //不合格写法
}
}
4)饿汉模式
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class SingLeton {
/**
* 饿汉式,无线程安全,占空间,在内存里只能有一个对象存在,且不能通过new引用
*/
private final static SingLeton SINGLENT = new SingLeton();
private SingLeton(){}
// 如果需要 用getInstance 就能得到想要的类或对象 内存里只有一份
public static SingLeton getInstance() {
return SINGLENT;
}
}
二、初涉线程
1、简介
线程是程序中执行的线程。Java虚拟机允许应用程序同时执行多个执行线程。
每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的Thread
对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护线程。
Thread属于Lang包
Java.lang.Object
java.lang.Thread
当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为main
的方法)。 Java虚拟机将继续执行线程,直到发生以下任一情况:
- 已经调用了
Runtime
类的exit
方法,并且安全管理器已经允许进行退出操作。 - 所有不是守护进程线程的线程都已经死亡,无论是从调用返回到
run
方法还是抛出超出run
方法的run
。
创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread
的子类。 这个子类应该重写run
类的方法Thread
, 然后可以分配并启动子类的实例
同步方法: 使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着
2、StringBuilder和StringBuffer
- StringBuffer中的方法都使用了synchronized修饰符,表示同步的,在多线程并发的时候可以保证线程安全,保证线程安全的时候,性能(速度)较低.
- StringBuilder中的方法都没有使用了synchronized修饰符,不安全,但是性能较高.
- StringBuffer和StringBuilder都表示可变的字符串,功能方法都是相同的,常用于拼接字符串。
3、线程生命周期
1、线程的创建可以使用Thread.new,同样可以以同样的语法使用Thread.start 或者Thread.fork这三个方法来创建线程。
2、创建线程后无需启动,线程会自动执行。
3、Thread 类定义了一些方法来操控线程。线程执行Thread.new中的代码块。
4、线程代码块中最后一个语句是线程的值,可以通过线程的方法来调用,如果线程执行完毕,则返回线程值,否则不返回值直到线程执行完毕。
5、Thread.current 方法返回表示当前线程的对象。 Thread.main 方法返回主线程。
6、通过 Thread.Join 方法来执行线程,这个方法会挂起主线程,直到当前线程执行完毕。
4、实操
1)得到当前线程的名字
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class ThreadTest {
public static void main(String[] args) {
//currentThread()返回当前线程 getName()获得当前线程的名字
System.out.println(Thread.currentThread().getName())
}
}
输出: main
2)开启线程(继承).start();
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class MyThread extends Thread {
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是" + Thread.currentThread().getName());
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1Zeqc1t-1604830688309)(E:\day++\day13\设计模式.assets\image-20201107230139575.png)]
4)修改ThreadTest
package xinzhi
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是" + Thread.currentThread().getName());
}
}
}
无序的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gMe8RZik-1604830688312)(E:\day++\day13\设计模式.assets\image-20201107230609998.png)]
5)调用run();,相当于没有开辟新线程,直接调用的主方法
MyThread myThread = new MyThread();
myThread.run();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yQ6v0Mdc-1604830688315)(E:\day++\day13\设计模式.assets\image-20201107230748757.png)]
6)再次开辟一条新线程(多线程)
MyThread myThread = new MyThread();
myThread.start();
MyThread myThread2 = new MyThread();
myThread.start();
无序的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPtw6ZY9-1604830688320)(E:\day++\day13\设计模式.assets\image-20201107231244199.png)]
7)开多线程
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class MyRun implements Runnable {
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是" + Thread.currentThread().getName());
}
}
}
package xinzhi;
public class MyThread extends Thread {
public MyThread(){} //空参构造
public MyThread(String name) { //构造方法,传线程的名字
super(name);
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是" + Thread.currentThread().getName());
}
}
}
package xinzhi;
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread("myThreadde的线程,一号线程");
myThread.start();
MyThread myThread2 = new MyThread("myThreadde2的线程,二号线程");
myThread2.start();
Thread MyThread3 = new Thread(new MyRun(),"run接口的线程,三号线程");
MyThread3.start();
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是" + Thread.currentThread().getName());
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e21zeiew-1604830688322)(E:\day++\day13\设计模式.assets\image-20201107233358421.png)]
5、初涉线程安全
拿到下标——赋值——下标+1
package xinzhi;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest {
public static List<Integer> LIST = new ArrayList<>();
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new MyRun());
thread.start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("——————————————LIST共有" +LIST.size() + "个数据");
}
}
package xinzhi;
public class MyRun implements Runnable {
@Override
public void run() {
System.out.println("添加了一个数据");
for (int i = 0; i < 100; i++) {
ThreadTest.LIST.add(i);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QX19iCtK-1604830688324)(E:\day++\day13\设计模式.assets\image-20201108000217499.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PBXfhPGL-1604830688325)(E:\day++\day13\设计模式.assets\image-20201108000251051.png)]
此时线程不安全
public static List<Integer> LIST = new Vector<>();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4l5LAuN-1604830688327)(E:\day++\day13\设计模式.assets\image-20201108001409893.png)]
此时线程安全
三、初涉异常
1、异常产生的原因及使用原则
在 Java 中一个异常的产生,主要有如下三种原因:
- Java 内部错误发生异常,Java 虚拟机产生的异常。
- 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,一般需要在某些类中集中处理这些异常。
- 通过 throw 语句手动生成的异常,这种异常称为检査的异常,一般用来告知该方法的调用者一些必要的信息。
Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。
我们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常。
Java 异常强制用户考虑程序的强健性和安全性。异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应处理。编写代码处理某个方法可能出现的异常,可遵循如下三个原则:
- 在当前方法声明中使用 try catch 语句捕获异常。
- 一个方法被覆盖时,覆盖它的方法必须拋出相同的异常或异常的子类。
- 如果父类抛出多个异常,则覆盖方法必须拋出那些异常的一个子集,而不能拋出新异常。
2、异常的继承关系:
3、异常的执行流程图:
try{
// 可能产生异常的语句
}catch(Exception1 e1){
// 处理语句1
}catch(Exception2 e2){
// 处理语句2
}
四、计算每个单词出现的次数
package xinzhi;
import java.util.HashMap;
import java.util.Map;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class Test5 {
public static void main(String[] args) {
String content = "aa bb cc Hello aa bb cc World" +
" AA BB CC hello AA BB CC world";
content = content.toLowerCase(); //首先将所有字母大写,以便做统计
String[] words = content.split(" "); //将字符串打乱成数组
Map<String,Integer> result = new HashMap<>(16); //存进hashmap里,给一个初始的长度16
for (String word : words) { //遍历所有单词
if (result.containsKey(word)){ //判断result里是否有这个单词,有就+1
result.put(word,result.get(word) + 1);
}else {
result.put(word,1); //没有就输出这个值
}
}
for (Map.Entry<String,Integer> entry : result.entrySet()){
System.out.println(entry.getKey() + "出现" + entry.getValue() + "次");
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WYepN8sl-1604830688330)(E:\day++\day13\设计模式.assets\image-20201107160329694.png)]
五、归并和效率
package xinzhi;
/**
* 2020/11/7
* @author cqmfx(阡陌飞絮)
*/
public class Study {
public static void main(String[] args) {
int [] arr1 = {1,7,9,12,15,23};
int [] arr2 = {2,8,10,11,12,13};
//把两个有序数组合并成一个数组,还有序
int[] concat = concat (arr1,arr2); //将两个数组用concat拼起来
for (int i : concat){
System.out.println(i + " "); //输出归并后的数组
}
}
private static int[] concat(int[] arr1, int[] arr2) {
int left = 0; //设置arr1的首下标
int right = 0; //设置arr2的首下标
int[] temp = new int[arr1.length + arr2.length]; //设置新数组的长度
for (int i = 0; i < temp.length; i++) { //边进行遍历边进行归并
if (left < arr1.length && right < arr2.length){ //判断边界,超出跳出循环
if (arr1[left] < arr2[right]){ //arr1的下标比arr2的大
temp[i] = arr1[left]; //则将此时arr1的值放到新数组里
left++; //arr1指针left下标往后移
}else { //反之
temp[i] = arr2[right]; //则将此时arr2的值放到新数组里
right++; //arr2指针right下标往后移
}
}else if (left < arr1.length){
temp[i] = arr1[left];
left++;
}else if (right < arr2.length){
temp[i] = arr2[right];
right++;
}
}
return temp; //返回新数组temp
}
}
left++; //arr1指针left下标往后移
}else { //反之
temp[i] = arr2[right]; //则将此时arr2的值放到新数组里
right++; //arr2指针right下标往后移
}
}else if (left < arr1.length){
temp[i] = arr1[left];
left++;
}else if (right < arr2.length){
temp[i] = arr2[right];
right++;
}
}
return temp; //返回新数组temp
}
}