Java语法进阶
目录:
- Object类、常用API
- Collection、泛型
- List、Set、数据结构、Collections
- Map与斗地主案例
- 异常、线程
- 线程、同步
- 等待与唤醒案例、线程池、Lambda表达式
- File类、递归
- 字节流、字符流
- 缓冲流、转换流、序列化流、Files
- 网络编程 十二、函数式接口
- Stream流、方法引用
一、Object类、常用API
二、Collection、泛型
三、List、Set、数据结构、Collections
四、Map与斗地主案例
五、异常、线程
目标:
1、说出进程的概念
2、说出线程的概念
3、能够理解并发与并行的区别
4、能够开启新线程
4.1 并发与并行
- 并发:指两个或多个事件在同一个时间段内发生。
- 并行:指两个或多个事件在同一时刻发生(同时发生)。
4.2 线程与进程
-
进程:
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。 -
进程:
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程
理解版:
-
进程: 进入到内存的程序,叫作“进程”。
在ROM(永久)存储的应用程序通过点击运行,进入RAM(临时)内存中 -
进程: 点击运行应用程序or功能就会开启一条应用程序到CPU的执行路径,这个路径有个名字,叫作“线程”。
进程:

线程:

线程调度:
-
分时调度:
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。 -
抢占式调度:
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
抢占式调度详解
大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是在同时运行,”感觉这些软件好像在同一时刻运行着“。
实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。
其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。
主线程: 执行主方法(main)的线程
单线程程序:Java程序中只有一个线程,执行从main方法开始,从上到下

4.3 创建线程类之一
Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建并启动多线程的步骤如下:
- 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
- 创建Thread子类的实例,即创建了线程对象
- 调用线程对象的start()方法来启动该线程
第一种方法:
将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。
实现步骤:
1、创建一个Thread的子类(自定一个继承thread的类)。
2、在Thread的子类中重写run方法,设置线程任务(开启线程要做什么)。
3、创建Thread类的对象
4、调用Thread类中的start方法,开启新的线程,执行run方法
void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
结果是两个线程并发地运行;当前线程(main线程)和另一个线程(执行其 run 方法)。
多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。(start完就没了,不能够继续start)Java程序属于抢占式调度,哪个线程优先级高,哪个线程优先执行;同一个优先级,随机选择执行(优先级相等,谁线抢占cpu谁就先执行)。
Demo:
Thread的子类
public class Mythread extends Thread {@Overridepublic void run() {for (int i = 0; i <20 ; i++) {System.out.println("run:"+i);}}
}
测试类
public class MyThread_Demo {public static void main(String[] args) {Mythread run = new Mythread();run.start();for (int i = 0; i < 20; i++) {System.out.println("main:"+i);}}
}
结果:main线程和run线程的执行顺序是随机的,不是固定的。
因为他们的线程优先级是一样的,所以抢占cpu资源的机会是平分的,谁先抢到了,谁就先执行。
六、线程、同步
目标:
- 能够描述Java中多线程运行原理
- 能够使用继承类的方式创建多线程
- 能够使用实现接口的方式创建多线程
- 能够说出实现接口方式的好处
- 能够解释安全问题的出现的原因
- 能够使用同步代码块解决线程安全问题
- 能够使用同步方法解决线程安全问题
- 能够说出线程6个状态的名称
1.1 多线程原理(结合上面的Demo代码)

-------------------------------------------------------------不明白?那就看一下详细的吧!----------------------------------------------------------------------------
Demo Code:
自定义类
public class MyThread extends Thread{/** 利用继承中的特点* 将线程名称传递 进行设置*/public MyThread(String name){super(name);}/** 重写run方法* 定义线程要执行的代码*/public void run(){for (int i = 0; i < 20; i++) {
//getName()方法 来自父亲System.out.println(getName()+i);}}
}
测试类
public class Demo {public static void main(String[] args) {System.out.println("这里是main线程");MyThread mt = new MyThread("小强");mt.start();//开启了一个新的线程for (int i = 0; i < 20; i++) {System.out.println("旺财:"+i);}}
}
流程图:

说明:
程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用mt的对象的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。
通过这张图我们可以很清晰的看到多线程的执行流程,那么为什么可以完成并发执行呢?我们再来讲一讲原理。

简易版本:

请注意mt.run()与mt.start()的区别。
1.2 Thread类之获取线程名称
Thread的子类
/*获取线程名称:1、使用THread类中的getName方法String getName() 返回该线程的名称。2、可以获取到当前正在执行的线程,使用线程中的方法getName()获取线程名称static Thread currentThread() 返回对当前正在执行的线程对象的引用。 */
//定义一个Thread的子类
public class Mythread extends Thread{//重写Thread中run方法,设置线程任务@Overridepublic void run() {//获取线程名称//第一种:getName方法String name = getName();System.out.println(name);//第二种:currentThread静态方法Thread t = Thread.currentThread();//为什么可以使用类名调用该方法?因为是静态方法System.out.println(t);//第三种:链式编程System.out.println(Thread.currentThread().getName());//currentThread()返回的是线程对象的引用//所以可以调用getName方法}
测试类
/*线程名称:主线程:main新线程:Thread-0、Thread-1、Thread-2*/
public class MyThread_Demo {public static void main(String[] args) {//创建Thread子类的对象Mythread mt = new Mythread();//调用start方法,开启新线程,执行run方法mt.start();//Thread-1//使用匿名对象调用startnew Mythread().start();//Thread[Thread-2,5,main] //start一个就新创建一个线程new Mythread().start();//Thread[Thread-0,5,main]//第三种:链式编程System.out.println(Thread.currentThread().getName());}
}
1.2 Thread类之设置线程名称(了解)
Thread的子类
/*设置线程名称:(了解)1、使用Thread类中的方法setName(名字)void setName(String name) 改变线程名称,使之与参数 name 相同。2、创建一个带参构造方法,参数传递线程的名称;调用父类的带参构造方法,把线程名称传递给父类,让父类(Thread)给子子线程起一个名字Thread(String name) 分配新的 Thread 对象。*/
public class Mythread extends Thread{//方法二:带参构造public Mythread(){};public Mythread(String name){super(name);};//方法一:@Overridepublic void run() {System.out.println(getName());}
}
测试类
public class MyThread_Demo {public static void main(String[] args) {Mythread mt = new Mythread();// 方法一:开启线程mt.setName("小强");mt.start();//方法二:开启线程new Mythread("旺财").start();}
}
1.2 Thread类之常用方法

利用sleep方法制作秒表:
public class MyThread_Demo {public static void main(String[] args) {//模拟秒表for (int i = 1; i < 60; i++) {System.out.println(i);//使用Thread类的sleep方法让程序睡眠1秒try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
1.3 创建线程之二(尽量使用)
采用 java.lang.Runnable 也是非常常见的一种,我们只需要重写run方法即可。
步骤如下:
- 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
- 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。(也就是,让Runnable的实现类对象作为Thread的参数传递进去,这样的Thread才变成线程对象)
- 调用线程对象的start()方法来启动线程。
Runnable实现类
/*创建多线程程序的第二种实现方式:实现Runnable (只有run方法)java.lang.RunnableRunnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。java.lang.ThreadThread(Runnable target) 分配新的 Thread 对象。Thread(Runnable target, String name) 分配新的 Thread 对象。
实现步骤:1-创建一个Runnable接口的实现类2-在实现类中重写Runnable接口的run方法,设置线程任务3-创建一个Runnable接口的实现类对象4-创建Thread类对象,构造方法中传递Runnable接口的实现类对象5-调用Thread类中的start方法,开启新的线程执行run方法*/
public class RunnableDemo implements Runnable{ //1-创建一个Runnable接口的实现类//2-在实现类中重写Runnable接口的run方法,设置线程任务@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName()+"-->"+i);}}
}
测试类
public class Runnable_Demo {public static void main(String[] args) {//3-创建一个Runnable接口的实现类对象RunnableDemo run = new RunnableDemo();//4-创建Thread类对象,构造方法中传递Runnable接口的实现类对象Thread t = new Thread(run,"小强");//5-调用Thread类中的start方法,开启新的线程执行run方法t.start();//主线程for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName()+"-->"+i);}}
}
1.4 Thread和Runnable的区别
实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避免java中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
解释:
1-避免单继承的局限性
一个类只能有一个父类(一个人只有一个亲爸),子类继承了Thread类就不能继承其他类了。
2-增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把【设置线程任务】和【开启新的线程】进行了分离。(解耦)
-
Runnable实现类中,重写了run方法:用来设置线程任务
-
测试类中创建Thread类对象,把不同的Runnable实现类对象作为参数传给Thread对象调用不同的run方法。
一个重写run,另一个调用run,开启新的线程。
扩充:
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进程。
1.5 匿名内部类方式实现线程的创建
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类的作用:简化代码
过程:
-
把【子类继承父类、重写父类的方法、创建子类对象】合一完成
-
把【实现类接口、重写接口中的方法、创建实现类对象】合成完成
内部类的最终产物是【子类/实现类对象】,而这个类没有名字。
格式:
new 父类/接口{
重写父类/接口的方法
};
Demo Dode:
public class Runnable_Demo {public static void main(String[] args) {//线程的父类是Thread//之前是MyThread mt = new MyThread();等于Thread t = new MyThread();也等于Thread t = new Thread();[多态]new Thread() {//重写run,设置线程任务@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName() + "-->" + "我是Thread");}}}.start();//线程的接口是Runnable//Runnable r = new RunnbaleImpl();[同上:多态]Runnable r = new Runnable() {//重写run,设置线程任务@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName() + "-->" + "我是Runnable");}}};new Thread(r).start();//再一次简化Runnable接口的方式new Thread(new Runnable() { //把参数内相当于new Thread(r).start()的r//重写run,设置线程任务@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName() + "-->" + "我是Runnable的加强简化");}}}).start();}
}
2.1 线程安全
线程安全的概述:
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

多线程代码实现
Runnable实现类
public class RunnableImpl implements Runnable {//定义一个多线程共享的票源int ticket = 100;//设置线程任务:卖票@Overridepublic void run() {//死循环,让卖票操作重复运行while (true){//判断是否有票if (ticket>0){//提高安全问题出现的概率,让程序睡眠try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");ticket--;}}}
}
测试类
/*模拟卖票案例创建3个线程,同时开启,对共享的票进行售出*/
public class Demo2Ticket {public static void main(String[] args) {//创建Runnable接口的实现类对象RunnableImpl run = new RunnableImpl();//创建Thread类对象,构造方法中传递Runbable接口的实现类Thread t0 = new Thread(run);Thread t1 = new Thread(run);Thread t2 = new Thread(run);//调用start方法开启多线程t0.start();t1.start();t2.start();}
}
多线程原理

有意思的是,在开始的时候,如果t0抢到了cpu的执行权进入到run方法,遇到sleep也会失去cpu执行权,然后,t1、t2再开始抢夺,到sleep的时候也会陆续失去cpu执行权。当3个线程睡醒了,他们继续开始抢夺执行权。而且,继续执行的时候不是重头开始,而是在哪里睡着了,就在哪里醒来接着跑往下跑。(所以,下面跳过了if判断,出现0,-1)
图中,假设3个线程共享资源为1票,而t2优先抢夺成功并卖票,则资源变成0票,停止循环执行;然后,t1、t2会跟着抢夺执行,执行的时候是以资源为0执行,所以才出现0票和-1票。
怎么会出现开头出现3个线程同时打印3个100,下面都没有重复呢?
因为3个线程同时进入run方法时,从打印输出卖出几张票执行到ticket减减的时候,是需要时间的。
2.2 线程同步
线程同步的3种方式:
- 同步代码块。2. 同步方法。3. 锁机制。
2.3 同步代码块
同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
格式:
synchronized(同步锁){
需要同步操作的代码
}
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
2. 锁对象 可以是任意类型。
3. 多个线程对象 要使用同一把锁。
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。


需要注意的是:
- Object lock = new Object();一定要设置在修改共享资源的外边。(为了只有1个锁对象)
- synchronized设置在哪里
把访问共享资源代码包起来。
同步技术原理

图中,t0抢到了执行权拿到了lock对象,进入sleep的时候,t1、t2再一次进行抢夺,但是发现没有对象锁的时候,只能进入阻塞状态,进行在外面等待t0执行完毕。
2.4 同步方法

Demo Code :


同步方法的对象是this,



静态同步方法:



2.5 Lock锁


还可以配合finally这么玩:不管有没有出现一次,都会释放锁

3.1 线程的状态


3.2 Timed Waiting(计时等待)



3.3 BLOCKED(锁阻塞)

3.4 Waiting(无限等待)




等待唤醒案例的分析:

等待唤醒案例:
等待唤醒案例:线程之间的通信创建一个顾客线程(消费者):告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)创建一个老板线程(生产者):花了5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子注意:顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行同步使用的锁对象必须保证唯一只有锁对象才能调用wait和notify方法Obejct类中的方法
void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void notify()唤醒在此对象监视器上等待的单个线程。会继续执行wait方法之后的代码public class Demo01WaitAndNotify {public static void main(String[] args) {//创建锁对象,保证唯一Object obj = new Object();// 创建一个顾客线程(消费者)new Thread(){@Overridepublic void run() {//一直等着买包子while(true){//保证等待和唤醒的线程只能有一个执行,需要使用同步技术synchronized (obj){System.out.println("告知老板要的包子的种类和数量");//调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}//唤醒之后执行的代码System.out.println("包子已经做好了,开吃!");System.out.println("---------------------------------------");}}}}.start();//创建一个老板线程(生产者)new Thread(){@Overridepublic void run() {//一直做包子while (true){//花了5秒做包子try {Thread.sleep(5000);//花5秒钟做包子} catch (InterruptedException e) {e.printStackTrace();}//保证等待和唤醒的线程只能有一个执行,需要使用同步技术synchronized (obj){System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");//做好包子之后,调用notify方法,唤醒顾客吃包子obj.notify();}}}}.start();}
}
3.5 Object类中wait带参方法和notifyAll方法
进入到TimeWaiting(计时等待)有两种方式
1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable/Blocked状态唤醒的方法:void notify() 唤醒在此对象监视器上等待的单个线程。void notifyAll() 唤醒在此对象监视器上等待的所有线程。public class Demo02WaitAndNotify {public static void main(String[] args) {//创建锁对象,保证唯一Object obj = new Object();// 创建一个顾客线程(消费者)new Thread(){@Overridepublic void run() {//一直等着买包子while(true){//保证等待和唤醒的线程只能有一个执行,需要使用同步技术synchronized (obj){System.out.println("顾客1告知老板要的包子的种类和数量");//调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}//唤醒之后执行的代码System.out.println("包子已经做好了,顾客1开吃!");System.out.println("---------------------------------------");}}}}.start();// 创建一个顾客线程(消费者)new Thread(){@Overridepublic void run() {//一直等着买包子while(true){//保证等待和唤醒的线程只能有一个执行,需要使用同步技术synchronized (obj){System.out.println("顾客2告知老板要的包子的种类和数量");//调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}//唤醒之后执行的代码System.out.println("包子已经做好了,顾客2开吃!");System.out.println("---------------------------------------");}}}}.start();//创建一个老板线程(生产者)new Thread(){@Overridepublic void run() {//一直做包子while (true){//花了5秒做包子try {Thread.sleep(5000);//花5秒钟做包子} catch (InterruptedException e) {e.printStackTrace();}//保证等待和唤醒的线程只能有一个执行,需要使用同步技术synchronized (obj){System.out.println("老板5秒钟之后做好包子,告知顾客,可以吃包子了");//做好包子之后,调用notify方法,唤醒顾客吃包子//obj.notify();//如果有多个等待线程,随机唤醒一个obj.notifyAll();//唤醒所有等待的线程}}}}.start();}
}
3.5 补充知识点

七、等待与唤醒案例、线程池、Lambda表达式
1.1 线程间通信

1.2 等待与唤醒机制
1.3 生产者与消费者问题

2.1 线程池思想概述
2.2 线程池概念

2.3 线程池的使用
线程池:JDK1.5之后提供的
java.util.concurrent.Executors:线程池的工厂类,用来生成线程池
Executors类中的静态方法:static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池参数:int nThreads:创建线程池中包含的线程数量返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程)
java.util.concurrent.ExecutorService:线程池接口用来从线程池中获取线程,调用start方法,执行线程任务submit(Runnable task) 提交一个 Runnable 任务用于执行关闭/销毁线程池的方法void shutdown()
线程池的使用步骤:1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池2.创建一个类,实现Runnable接口,重写run方法,设置线程任务3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行)
3.1 函数式编程思想概
3.2 冗余的Runnable代码
3.3 编程思想转换
3.4 体验Lambda的更优写法
3.5 回顾匿名内部类
3.6 Lambda的格式
Lambda表达式的标准格式:由三部分组成:a.一些参数b.一个箭头c.一段代码格式:(参数列表) -> {一些重写方法的代码};解释说明格式:():接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔->:传递的意思,把参数传递给方法体{}{}:重写接口的抽象方法的方法体
3.7 练习:使用Lambda标准格式(无参无返回)
3.8 Lambda的参数和返回值
3.9 练习:使用Lambda标准格式(有参有返回)
3.10 Lambda省略格式
Lambda表达式:是可推导,可以省略
凡是根据上下文推导出来的内容,都可以省略书写
可以省略的内容:1.(参数列表):括号中参数列表的数据类型,可以省略不写2.(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略3.{一些代码}:如果{}中的代码只有一行,无论是否有返回值,都可以省略({},return,分号)注意:要省略{},return,分号必须一起省略
3.11 练习:使用Lambda省略格式
八、File类、递归
1.1 概述
java.io.File类
文件和目录路径名的抽象表示形式。
java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作
我们可以使用File类的方法创建一个文件/文件夹删除文件/文件夹获取文件/文件夹判断文件/文件夹是否存在对文件夹进行遍历获取文件的大小
File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法重点:记住这三个单词file:文件directory:文件夹/目录path:路径
File类的静态成员:
static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。static char pathSeparatorChar 与系统有关的路径分隔符。static String separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。static char separatorChar 与系统有关的默认名称分隔符。操作路径:路径不能写死了C:developaa.txt windowsC:/develop/a/a.txt linux"C:"+File.separator+"develop"+File.separator+"a"+File.separator+"a.txt"String pathSeparator = File.pathSeparator;System.out.println(pathSeparator);//路径分隔符 windows:分号; linux:冒号:String separator = File.separator;System.out.println(separator);// 文件名称分隔符 windows:反斜杠 linux:正斜杠/
绝对路径和相对路径
路径:绝对路径:是一个完整的路径以盘符(c:,D:)开始的路径c:\a.txtC:\Usersitcast\IdeaProjects\shungyuan\123.txtD:\demo\b.txt相对路径:是一个简化的路径相对指的是相对于当前项目的根目录(C:\Usersitcast\IdeaProjects\shungyuan)如果使用当前项目的根目录,路径可以简化书写C:\Usersitcast\IdeaProjects\shungyuan\123.txt-->简化为: 123.txt(可以省略项目的根目录)注意:1.路径是不区分大小写2.路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
1.2 构造方法
public static void main(String[] args) {/*File类的构造方法*///show02("c:\","a.txt");//c:a.txt//show02("d:\","a.txt");//d:a.txtshow03();File f = new File("C:\Users\itcast\IdeaProjects\shungyuan");long length = f.length();System.out.println(length);
}/*File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。参数:把路径分成了两部分File parent:父路径String child:子路径好处:父路径和子路径,可以单独书写,使用起来非常灵活;父路径和子路径都可以变化父路径是File类型,可以使用File的方法对路径进行一些操作,再使用路径创建对象*/
private static void show03() {File parent = new File("c:\");File file = new File(parent,"hello.java");System.out.println(file);//c:hello.java
}/*File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。参数:把路径分成了两部分String parent:父路径String child:子路径好处:父路径和子路径,可以单独书写,使用起来非常灵活;父路径和子路径都可以变化*/
private static void show02(String parent, String child) {File file = new File(parent,child);System.out.println(file);//c:a.txt
}/*File(String pathname) 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。参数:String pathname:字符串的路径名称路径可以是以文件结尾,也可以是以文件夹结尾路径可以是相对路径,也可以是绝对路径路径可以是存在,也可以是不存在创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况*/
private static void show01() {File f1 = new File("C:\Users\itcast\IdeaProjects\shungyuan\a.txt");System.out.println(f1);//重写了Object类的toString方法 C:UsersitcastIdeaProjectsshungyuana.txtFile f2 = new File("C:\Users\itcast\IdeaProjects\shungyuan");System.out.println(f2);//C:UsersitcastIdeaProjectsshungyuanFile f3 = new File("b.txt");System.out.println(f3);//b.txt
}
}
1.3 常用方法
创建删除的方法
/*
File类判断功能的方法- public boolean exists() :此File表示的文件或目录是否实际存在。- public boolean isDirectory() :此File表示的是否为目录。- public boolean isFile() :此File表示的是否为文件。*/public class Demo04File {public static void main(String[] args) {show02();}/*public boolean isDirectory() :此File表示的是否为目录。用于判断构造方法中给定的路径是否以文件夹结尾是:true否:falsepublic boolean isFile() :此File表示的是否为文件。用于判断构造方法中给定的路径是否以文件结尾是:true否:false注意:电脑的硬盘中只有文件/文件夹,两个方法是互斥这两个方法使用前提,路径必须是存在的,否则都返回false*/
private static void show02() {File f1 = new File("C:\Users\itcast\IdeaProjects\shung");//不存在,就没有必要获取if(f1.exists()){System.out.println(f1.isDirectory());System.out.println(f1.isFile());}File f2 = new File("C:\Users\itcast\IdeaProjects\shungyuan");if(f2.exists()){System.out.println(f2.isDirectory());//trueSystem.out.println(f2.isFile());//false}File f3 = new File("C:\Users\itcast\IdeaProjects\shungyuan\shungyuan.iml");if(f3.exists()){System.out.println(f3.isDirectory());//falseSystem.out.println(f3.isFile());//true}
}/*public boolean exists() :此File表示的文件或目录是否实际存在。用于判断构造方法中的路径是否存在存在:true不存在:false*/
private static void show01() {File f1 = new File("C:\Users\itcast\IdeaProjects\shungyuan");System.out.println(f1.exists());//trueFile f2 = new File("C:\Users\itcast\IdeaProjects\shung");System.out.println(f2.exists());//falseFile f3 = new File("shungyuan.iml");//相对路径 C:UsersitcastIdeaProjectsshungyuanshungyuan.imlSystem.out.println(f3.exists());//trueFile f4 = new File("a.txt");System.out.println(f4.exists());//false}
}
File类的创建删除方法
/*
File类创建删除功能的方法
- public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
- public boolean delete() :删除由此File表示的文件或目录。
- public boolean mkdir() :创建由此File表示的目录。
- public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
*/
public class Demo05File {public static void main(String[] args) throws IOException {show03();}/*public boolean delete() :删除由此File表示的文件或目录。此方法,可以删除构造方法路径中给出的文件/文件夹返回值:布尔值true:文件/文件夹删除成功,返回truefalse:文件夹中有内容,不会删除返回false;构造方法中路径不存在false注意:delete方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎*/
private static void show03() {File f1 = new File("08_FileAndRecursion\新建文件夹");boolean b1 = f1.delete();System.out.println("b1:"+b1);File f2 = new File("08_FileAndRecursion\abc.txt");System.out.println(f2.delete());
}/*public boolean mkdir() :创建单级空文件夹public boolean mkdirs() :既可以创建单级空文件夹,也可以创建多级文件夹创建文件夹的路径和名称在构造方法中给出(构造方法的参数)返回值:布尔值true:文件夹不存在,创建文件夹,返回truefalse:文件夹存在,不会创建,返回false;构造方法中给出的路径不存在返回false注意:1.此方法只能创建文件夹,不能创建文件*/
private static void show02() {File f1 = new File("08_FileAndRecursion\aaa");boolean b1 = f1.mkdir();System.out.println("b1:"+b1);File f2 = new File("08_FileAndRecursion\111\222\333\444");boolean b2 = f2.mkdirs();System.out.println("b2:"+b2);File f3 = new File("08_FileAndRecursion\abc.txt");boolean b3 = f3.mkdirs();//看类型,是一个文件System.out.println("b3:"+b3);File f4 = new File("08_F\ccc");boolean b4 = f4.mkdirs();//不会抛出异常,路径不存在,不会创建System.out.println("b4:"+b4);
}/*public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。创建文件的路径和名称在构造方法中给出(构造方法的参数)返回值:布尔值true:文件不存在,创建文件,返回truefalse:文件存在,不会创建,返回false注意:1.此方法只能创建文件,不能创建文件夹2.创建文件的路径必须存在,否则会抛出异常public boolean createNewFile() throws IOExceptioncreateNewFile声明抛出了IOException,我们调用这个方法,就必须的处理这个异常,要么throws,要么trycatch*/
private static void show01() throws IOException {File f1 = new File("C:\Users\itcast\IdeaProjects\shungyuan\08_FileAndRecursion\1.txt");boolean b1 = f1.createNewFile();System.out.println("b1:"+b1);File f2 = new File("08_FileAndRecursion\2.txt");System.out.println(f2.createNewFile());File f3 = new File("08_FileAndRecursion\新建文件夹");System.out.println(f3.createNewFile());//不要被名称迷糊,要看类型File f4 = new File("08_FileAndRecursi\3.txt");System.out.println(f4.createNewFile());//路径不存在,抛出IOException}
}
1.4 遍历文件夹(目录)功能
/*File类遍历(文件夹)目录功能public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。注意:list方法和listFiles方法遍历的是构造方法中给出的目录如果构造方法中给出的目录的路径不存在,会抛出空指针异常如果构造方法中给出的路径不是一个目录,也会抛出空指针异常public class Demo06File {public static void main(String[] args) {show02();}/*public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹,把文件/文件夹封装为File对象,多个File对象存储到File数组中*/
private static void show02() {File file = new File("C:\Users\itcast\IdeaProjects\shungyuan\08_FileAndRecursion");File[] files = file.listFiles();for (File f : files) {System.out.println(f);}
}/*public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。遍历构造方法中给出的目录,会获取目录中所有文件/文件夹的名称,把获取到的多个名称存储到一个String类型的数组中*/
private static void show01() {//File file = new File("C:\Users\itcast\IdeaProjects\shungyuan\08_FileAndRecursion\1.txt");//NullPointerException//File file = new File("C:\Users\itcast\IdeaProjects\shungyuan\08_Fi");//NullPointerExceptionFile file = new File("C:\Users\itcast\IdeaProjects\shungyuan\08_FileAndRecursion");String[] arr = file.list();for (String fileName : arr) {System.out.println(fileName);}}
}
2.1 递归概念&分类&注意事项
/*递归:方法自己调用自己- 递归的分类:- 递归分为两种,直接递归和间接递归。- 直接递归称为方法自身调用自己。- 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。- 注意事项:- 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。- 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。 - 构造方法,禁止递归递归的使用前提:当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递
归*/public class Demo01Recurison {public static void main(String[] args) {//a();b(1);}/*构造方法,禁止递归编译报错:构造方法是创建对象使用的,一直递归会导致内存中有无数多个对象,直接编译报错*/
public Demo01Recurison() {//Demo01Recurison();
}/*在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。11157Exception in thread "main" java.lang.StackOverflowError*/
private static void b(int i) {System.out.println(i);if(i==20000){return; //结束方法}b(++i);
}/*递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。Exception in thread "main" java.lang.StackOverflowError*/
private static void a() {System.out.println("a方法!");a();
}
}
九、字节流、字符流
第二章 字节流
------------------------------字节输出流
/* java.io.OutputStream:字节输出流此抽象类是表示输出字节流的所有类的超类。定义了一些子类共性的成员方法:- public void close() :关闭此输出流并释放与此流相关联的任何系统资源。- public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。- public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。- public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。- public abstract void write(int b) :将指定的字节输出流。java.io.FileOutputStream extends OutputStream
FileOutputStream:文件字节输出流
作用:把内存中的数据写入到硬盘的文件中构造方法:FileOutputStream(String name)创建一个向具有指定名称的文件中写入数据的输出文件流。FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。参数:写入数据的目的String name:目的地是一个文件的路径File file:目的地是一个文件构造方法的作用:1.创建一个FileOutputStream对象2.会根据构造方法中传递的文件/文件路径,创建一个空的文件3.会把FileOutputStream对象指向创建好的文件写入数据的原理(内存-->硬盘)java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据写入到文件中字节输出流的使用步骤(重点):1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地2.调用FileOutputStream对象中的方法write,把数据写入到文件中3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)*/
Demo :
public class Demo01OutputStream {public static void main(String[] args) throws IOException {//1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地FileOutputStream fos = new FileOutputStream("09_IOAndProperties\a.txt");//2.调用FileOutputStream对象中的方法write,把数据写入到文件中//public abstract void write(int b) :将指定的字节输出流。fos.write(97);//3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)//fos.close();}
}
一次读取一个字节:
package com.itheima.demo01.OutputStream;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;/*一次写多个字节的方法:- public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。- public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。*/
public class Demo02OutputStream {public static void main(String[] args) throws IOException {//创建FileOutputStream对象,构造方法中绑定要写入数据的目的地FileOutputStream fos = new FileOutputStream(new File("09_IOAndProperties\b.txt"));//调用FileOutputStream对象中的方法write,把数据写入到文件中//在文件中显示100,写个字节fos.write(49);fos.write(48);fos.write(48);/*public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。一次写多个字节:如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)*/byte[] bytes = {65,66,67,68,69};//ABCDE//byte[] bytes = {-65,-66,-67,68,69};//烤紻Efos.write(bytes);/*public void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中int off:数组的开始索引int len:写几个字节*/fos.write(bytes,1,2);//BC/*写入字符的方法:可以使用String类中的方法把字符串,转换为字节数组byte[] getBytes() 把字符串转换为字节数组*/byte[] bytes2 = "你好".getBytes();System.out.println(Arrays.toString(bytes2));//[-28, -67, -96, -27, -91, -67]fos.write(bytes2);//释放资源fos.close();}
}

一次读取一个字节:
注意:
1、new FileInputStream()之后会指向文件源,而且指针是指向文件的第1个字节,也就是a
2、调用fis.read()方法后,原本指向a的指针会往后跑1个字节,也就是跑到b
其中,read方法找JVM,JVM找OS,OS调用方法把a传给JVM,JVM再返回给read()
一次性读取多字节:
注意:
1:new FileInputStream()指向文件源,且指针指向文件源中第1个字节
2:创建了1个长度为2的空字节数组
3:read(bytes)读取的字节存入数组中,存进2个字节,即“A,B”,
再调用获取的是下2个(C,D),这时候ABCDE中只有E没有获取
再调用获取的是E,就是单单的E,至于为什么输出的时候是ED
是因为重复调用read(bytes)获取是把新的字符覆盖掉已存有的字节。
图中,获取C、D之后,只剩E,再调用获取,E只是把C给覆盖了,D没有被覆盖,所以还是存在,所以打印的时候输出E、D
补充:window系统在文件系统会有一个结束标记(看不见的),当指针指向“结束标记”的时候,就返回-1,返回-1后,read()方法执行结束
数据追加续写
追加写/续写:使用两个参数的构造方法
FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
参数:
String name,File file:写入数据的目的地
boolean append:追加写开关
true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖源文件
写换行:写换行符号
windows:
linux:/n
mac:/r
Demo:
public class Demo03OutputStream {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("09_IOAndProperties\c.txt",true);for (int i = 1; i <=10 ; i++) {fos.write("你好".getBytes());fos.write("
".getBytes());}fos.close();}
}
----------------------------------字节输入流
java.io.InputStream:字节输入流此抽象类是表示字节输入流的所有类的超类。定义了所有子类共性的方法:int read()从输入流中读取数据的下一个字节。int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。void close() 关闭此输入流并释放与该流关联的所有系统资源。java.io.FileInputStream extends InputStream
FileInputStream:文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用构造方法:FileInputStream(String name)FileInputStream(File file)参数:读取文件的数据源String name:文件的路径File file:文件构造方法的作用:1.会创建一个FileInputStream对象2.会把FileInputStream对象指定构造方法中要读取的文件读取数据的原理(硬盘-->内存)java程序-->JVM-->OS-->OS读取数据的方法-->读取文件字节输入流的使用步骤(重点):1.创建FileInputStream对象,构造方法中绑定要读取的数据源2.使用FileInputStream对象中的方法read,读取文件3.释放资源
一次读取多个字节
字节输入流一次读取多个字节的方法:int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
明确两件事情:1.方法的参数byte[]的作用?起到缓冲作用,存储每次读取到的多个字节数组的长度一把定义为1024(1kb)或者1024的整数倍2.方法的返回值int是什么?每次读取的有效字节个数String类的构造方法String(byte[] bytes) :把字节数组转换为字符串String(byte[] bytes, int offset, int length) 把字节数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数
文件复制
文件复制练习:一读一写明确:数据源: c:\1.jpg数据的目的地: d:\1.jpg文件复制的步骤:1.创建一个字节输入流对象,构造方法中绑定要读取的数据源2.创建一个字节输出流对象,构造方法中绑定要写入的目的地3.使用字节输入流对象中的方法read读取文件4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中5.释放资源
第三章 字符流
----------------------------输入流
java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类共性的成员方法:int read() 读取单个字符并返回。int read(char[] cbuf)一次读取多个字符,将字符读入数组。void close() 关闭该流并释放与之关联的所有资源。java.io.FileReader extends InputStreamReader extends Reader
FileReader:文件字符输入流
作用:把硬盘文件中的数据以字符的方式读取到内存中构造方法:FileReader(String fileName)FileReader(File file)参数:读取文件的数据源String fileName:文件的路径File file:一个文件FileReader构造方法的作用:1.创建一个FileReader对象2.会把FileReader对象指向要读取的文件
字符输入流的使用步骤:1.创建FileReader对象,构造方法中绑定要读取的数据源2.使用FileReader对象中的方法read读取文件3.释放资源public class Demo02Reader {public static void main(String[] args) throws IOException {//1.创建FileReader对象,构造方法中绑定要读取的数据源FileReader fr = new FileReader("09_IOAndProperties\c.txt");//2.使用FileReader对象中的方法read读取文件//int read() 读取单个字符并返回。/*int len = 0;while((len = fr.read())!=-1){System.out.print((char)len);}*///int read(char[] cbuf)一次读取多个字符,将字符读入数组。char[] cs = new char[1024];//存储读取到的多个字符int len = 0;//记录的是每次读取的有效字符个数while((len = fr.read(cs))!=-1){/*String类的构造方法String(char[] value) 把字符数组转换为字符串String(char[] value, int offset, int count) 把字符数组的一部分转换为字符串 offset数组的开始索引 count转换的个数*/System.out.println(new String(cs,0,len));}//3.释放资源fr.close();}
}
----------------------------输入出
java.io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类共性的成员方法:- void write(int c) 写入单个字符。- void write(char[] cbuf)写入字符数组。- abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。- void write(String str)写入字符串。- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。- void flush()刷新该流的缓冲。- void close() 关闭此流,但要先刷新它。java.io.FileWriter extends OutputStreamWriter extends Writer
FileWriter:文件字符输出流
作用:把内存中字符数据写入到文件中构造方法:FileWriter(File file)根据给定的 File 对象构造一个 FileWriter 对象。FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。参数:写入数据的目的地String fileName:文件的路径File file:是一个文件构造方法的作用:1.会创建一个FileWriter对象2.会根据构造方法中传递的文件/文件的路径,创建文件3.会把FileWriter对象指向创建好的文件字符输出流的使用步骤(重点):1.创建FileWriter对象,构造方法中绑定要写入数据的目的地2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
Flush与close区别
flush方法和close方法的区别- flush :刷新缓冲区,流对象可以继续使用。- close: 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
Demo :
public class Demo02CloseAndFlush {public static void main(String[] args) throws IOException {//1.创建FileWriter对象,构造方法中绑定要写入数据的目的地FileWriter fw = new FileWriter("09_IOAndProperties\e.txt");//2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)//void write(int c) 写入单个字符。fw.write(97);//3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中fw.flush();//刷新之后流可以继续使用fw.write(98);//4.释放资源(会先把内存缓冲区中的数据刷新到文件中)fw.close();//close方法之后流已经关闭了,已经从内存中消失了,流就不能再使用了fw.write(99);//IOException: Stream closed}
}
字节输出流的其他方法
字符输出流写数据的其他方法- void write(char[] cbuf)写入字符数组。- abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。- void write(String str)写入字符串。- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
Demo:
public class Demo03Writer {public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("09_IOAndProperties\f.txt");char[] cs = {'a','b','c','d','e'};//void write(char[] cbuf)写入字符数组。fw.write(cs);//abcde//void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。fw.write(cs,1,3);//bcd//void write(String str)写入字符串。fw.write("传智播客");//传智播客//void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。fw.write("黑马程序员",2,3);//程序员fw.close();}
}
数据追加续写:
续写和换行
续写,追加写:使用两个参数的构造方法FileWriter(String fileName, boolean append)FileWriter(File file, boolean append)参数:String fileName,File file:写入数据的目的地boolean append:续写开关 true:不会创建新的文件覆盖源文件,可以续写; false:创建新的文件覆盖源文件换行:换行符号windows:linux:/nmac:/rpublic class Demo04Writer {public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("09_IOAndProperties\g.txt",true);for (int i = 0; i <10 ; i++) {fw.write("HelloWorld"+i+"
");}fw.close();}
}
第四章 IO异常的处理
JDK7前
在jdk1.7之前使用try catch finally 处理流中的异常格式:try{可能会产出异常的代码}catch(异常类变量 变量名){异常的处理逻辑}finally{一定会指定的代码资源释放}---------------------------------------------------------------public class Demo01TryCatch {public static void main(String[] args) {//提高变量fw的作用域,让finally可以使用//变量在定义的时候,可以没有值,但是使用的时候必须有值//fw = new FileWriter("09_IOAndProperties\g.txt",true); 执行失败,fw没有值,fw.close会报错FileWriter fw = null;try{//可能会产出异常的代码fw = new FileWriter("w:\09_IOAndProperties\g.txt",true);for (int i = 0; i <10 ; i++) {fw.write("HelloWorld"+i+"
");}}catch(IOException e){//异常的处理逻辑System.out.println(e);}finally {//一定会指定的代码//创建对象失败了,fw的默认值就是null,null是不能调用方法的,会抛出NullPointerException,需要增加一个判断,不是null在把资源释放if(fw!=null){try {//fw.close方法声明抛出了IOException异常对象,所以我们就的处理这个异常对象,要么throws,要么try catchfw.close();} catch (IOException e) {e.printStackTrace();}}}}
}
JDK7后
JDK7的新特性在try的后边可以增加一个(),在括号中可以定义流对象那么这个流对象的作用域就在try中有效try中的代码执行完毕,会自动把流对象释放,不用写finally格式:try(定义流对象;定义流对象....){可能会产出异常的代码}catch(异常类变量 变量名){异常的处理逻辑}
----------------------------------------------------------------
public class Demo02JDK7 {public static void main(String[] args) {try(//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源FileInputStream fis = new FileInputStream("c:\1.jpg");//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地FileOutputStream fos = new FileOutputStream("d:\1.jpg");){//可能会产出异常的代码//一次读取一个字节写入一个字节的方式//3.使用字节输入流对象中的方法read读取文件int len = 0;while((len = fis.read())!=-1){//4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中fos.write(len);}}catch (IOException e){//异常的处理逻辑System.out.println(e);}}
}
JDK9后
JDK9新特性try的前边可以定义流对象在try后边的()中可以直接引入流对象的名称(变量名)在try代码执行完毕之后,流对象也可以释放掉,不用写finally格式:A a = new A();B b = new B();try(a,b){可能会产出异常的代码}catch(异常类变量 变量名){异常的处理逻辑}public class Demo03JDK9 {public static void main(String[] args) throws IOException {//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源FileInputStream fis = new FileInputStream("c:\1.jpg");//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地FileOutputStream fos = new FileOutputStream("d:\1.jpg");try(fis;fos){//一次读取一个字节写入一个字节的方式//3.使用字节输入流对象中的方法read读取文件int len = 0;while((len = fis.read())!=-1){//4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中fos.write(len);}}catch (IOException e){System.out.println(e);}//fos.write(1);//Stream Closed}
}
第五章 属性集
---------------------------------------------------------------------------------java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。Properties集合是一个唯一和IO流相结合的集合可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用属性列表中每个键及其对应值都是一个字符串。Properties集合是一个双列集合,key和value默认都是字符串
---------------------------------------------------------------------------------
public class Demo01Properties {public static void main(String[] args) throws IOException {show03();}/*可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用void load(InputStream inStream)void load(Reader reader)参数:InputStream inStream:字节输入流,不能读取含有中文的键值对Reader reader:字符输入流,能读取含有中文的键值对使用步骤:1.创建Properties集合对象2.使用Properties集合对象中的方法load读取保存键值对的文件3.遍历Properties集合注意:1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取3.存储键值对的文件中,键与值默认都是字符串,不用再加引号*/private static void show03() throws IOException {//1.创建Properties集合对象Properties prop = new Properties();//2.使用Properties集合对象中的方法load读取保存键值对的文件prop.load(new FileReader("09_IOAndProperties\prop.txt"));//prop.load(new FileInputStream("09_IOAndProperties\prop.txt"));//3.遍历Properties集合Set<String> set = prop.stringPropertyNames();for (String key : set) {String value = prop.getProperty(key);System.out.println(key+"="+value);}}---------------------------------------------------------------------------------可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储void store(OutputStream out, String comments)void store(Writer writer, String comments)参数:OutputStream out:字节输出流,不能写入中文Writer writer:字符输出流,可以写中文String comments:注释,用来解释说明保存的文件是做什么用的不能使用中文,会产生乱码,默认是Unicode编码一般使用""空字符串使用步骤:1.创建Properties集合对象,添加数据2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储4.释放资源
---------------------------------------------------------------------------------private static void show02() throws IOException {//1.创建Properties集合对象,添加数据Properties prop = new Properties();prop.setProperty("赵丽颖","168");prop.setProperty("迪丽热巴","165");prop.setProperty("古力娜扎","160");//2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地//FileWriter fw = new FileWriter("09_IOAndProperties\prop.txt");//3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储//prop.store(fw,"save data");//4.释放资源//fw.close();prop.store(new FileOutputStream("09_IOAndProperties\prop2.txt"),"");}---------------------------------------------------------------------------------使用Properties集合存储数据,遍历取出Properties集合中的数据Properties集合是一个双列集合,key和value默认都是字符串Properties集合有一些操作字符串的特有方法Object setProperty(String key, String value) 调用 Hashtable 的方法 put。String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法Set<String> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
---------------------------------------------------------------------------------private static void show01() {//创建Properties集合对象Properties prop = new Properties();//使用setProperty往集合中添加数据prop.setProperty("赵丽颖","168");prop.setProperty("迪丽热巴","165");prop.setProperty("古力娜扎","160");//prop.put(1,true);//使用stringPropertyNames把Properties集合中的键取出,存储到一个Set集合中Set<String> set = prop.stringPropertyNames();//遍历Set集合,取出Properties集合的每一个键for (String key : set) {//使用getProperty方法通过key获取valueString value = prop.getProperty(key);System.out.println(key+"="+value);}}
}
十、缓冲流、转换流、序列化流、Files
十一、网络编程
十二、函数式接口
十三、Stream流、方法引用
相关文章:
Java语法进阶
目录: Object类、常用APICollection、泛型List、Set、数据结构、CollectionsMap与斗地主案例异常、线程线程、同步等待与唤醒案例、线程池、Lambda表达式File类、递归字节流、字符流缓冲流、转换流、序列化流、Files网络编程 十二、函数式接口Stream流、方法引用 一…...
UNI-MOL: A UNIVERSAL 3D MOLECULAR REPRESENTATION LEARNING FRAMEWORK
UNI-MOL: A UNIVERSAL 3D MOLECULAR REPRESENTATION LEARNING FRAMEWORK Neurips23 推荐指数:#paper/⭐⭐⭐#(工作量不小) 动机 在大多数分子表征学习方法中,分子被视为 1D 顺序标记或2D 拓扑图,这限制了它们为下游任务整合…...
笔记day7
文章目录 1 分页功能实现2 分页器的展示需要哪些数据(条件)?3 自定义分页器4 分页器存在问题5 分页器动态展示6 开发某一个商品的详情页面 1 分页功能实现 为什么很多项目采用分页功能,比如电商平台同时展示的数据有很多…...
106,【6】 buuctf web [SUCTF 2019]CheckIn
进入靶场 文件上传 老规矩,桌面有啥传啥 过滤了<? 寻找不含<?的一句话木马 文件名 123(2).php.jpg 文件内容 GIF89a? <script language"php">eval($_GET[123]);</script> 123即密码,可凭借个人喜好更换 再上传一个文…...
基于Ubuntu2404搭建Zabbix7.2
Zabbix 搭建zabbix zabbix7.2已推出:官网 增加的新功能如下: 1.使用新的热门商品小部件全面概览指标 数据概览小部件已转换为热门项目小部件使用项目模式可以实现细粒度的项目选择利用条形图、指标和迷你图来可视化您的数据定义价值阈值以动态地可视化…...
OPENGLPG第九版学习 - 着色器基础
文章目录 2.1 着色器与OpenGL2.2 0penGL的可编程管线2.3 OpenGL着色语言GLSL概述2.3.1 使用GLSL构建着色器变量的声明变量的作用域变量的初始化构造函数 、 类型转换聚合类型访问向量和矩阵中的元素结构体数组多维数组 2.3.2 存储限制符const 存储限制符in 存储限制符out 存储限…...
Android 使用ExpandableListView时,需要注意哪些细节
1. 布局属性设置 尺寸属性 宽度和高度:要合理设置 android:layout_width 和 android:layout_height 属性。如果设置为 match_parent,它会填满父容器;设置为 wrap_content,则会根据内容自动调整大小。例如,若想让 Exp…...
redis简介及应用
文章目录 1.redis简介2.安装配置2.1 单机部署2.2 配置 3 主从部署4 哨兵部署5.集群部署6.客户端工具 1.redis简介 某些网站出现的问题,如12306、淘宝等… 2.安装配置 2.1 单机部署 安装gcc、关闭防火墙、关闭selinux等 #安装gcc yum -y install gcc #关闭防火墙…...
Electron使用WebAssembly实现CRC-8 MAXIM校验
Electron使用WebAssembly实现CRC-8 MAXIM校验 将C/C语言代码,经由WebAssembly编译为库函数,可以在JS语言环境进行调用。这里介绍在Electron工具环境使用WebAssembly调用CRC-8 MAXIM格式校验的方式。 CRC-8 MAXIM校验函数WebAssembly源文件 C语言实现C…...
人工智能赋能企业系统架构设计:以ERP与CRM系统为例
一、引言 1.1 研究背景与意义 在数字化时代,信息技术飞速发展,人工智能(Artificial Intelligence, AI)作为一项具有变革性的技术,正深刻地影响着各个领域。近年来,AI 在技术上取得了显著突破,…...
NacosRce到docker逃逸实战
NacosRce到docker逃逸实战 1、Nacos Derby Rce打入内存马 这个漏洞的原理大家应该都知道, 2.3.2 < Nacos < 2.4.0版本默认derby接口未授权访问,攻击者可利用未授权访问执行SQL语句加载构造恶意的JAR包导致出现远程代码执行漏洞。 在日常的漏洞挖…...
Linux:文件系统(软硬链接)
目录 inode ext2文件系统 Block Group 超级块(Super Block) GDT(Group Descriptor Table) 块位图(Block Bitmap) inode位图(Inode Bitmap) i节点表(inode Tabl…...
在Spring Cloud中将Redis共用到Common模块
前言 在分布式系统中,共用组件的设计可以极大地提升代码复用性和维护性。Spring Cloud中将Redis共用到一个公共模块(common模块)是一个常见的设计实践,这样可以让多个微服务共享相同的Redis配置和操作逻辑。本文将详细介绍如何在…...
如何解决 Vue 应用中的内存泄漏
如何解决 Vue 应用中的内存泄漏 如何解决 Vue 应用中的内存泄漏常见的内存泄漏原因1. 组件生命周期管理不善2. 闭包引起的引用3. 数据订阅与发布系统4. 第三方库的内存泄漏5. 路由缓存和组件实例堆积排查内存泄漏的工具1. **Chrome DevTools**2. **Firefox Developer Tools**3.…...
什么是物理地址,什么是虚拟地址?
摘要 什么是物理地址,什么是虚拟地址? 如果处理器没有MMU或未启用,CPU执行单元发出的内存地址直接传到芯片引脚上,被内存芯片接受,这称为物理地址(Physical Addraress) 如果处理器启用了MMU&a…...
find 和 filter 都是 JavaScript 数组的常用方法
find 和 filter 都是 JavaScript 数组的常用方法,用来查找符合条件的元素,但它们有一些关键的区别: 1. find 方法 返回值:find 方法返回数组中 第一个符合条件的元素,如果没有找到符合条件的元素,返回 un…...
MVC、MVP和MVVM模式
MVC模式中,视图和模型之间直接交互,而MVP模式下,视图与模型通过Presenter进行通信,MVVM则采用双向绑定,减少手动同步视图和模型的工作。每种模式都有其优缺点,适合不同规模和类型的项目。 ### MVVM 与 MVP…...
基于RTOS的STM32游戏机
1.游戏机的主要功能 所有游戏都来着B站JL单片机博主开源 这款游戏机具备存档与继续游戏功能,允许玩家在任何时候退出当前游戏并保存进度,以便日后随时并继续之前的冒险。不仅如此,游戏机还支持多任务处理,玩家可以在退出当前游戏…...
【CPP】CPP经典面试题
文章目录 引言1. C 基础1.1 C 中的 const 关键字1.2 C 中的 static 关键字 2. 内存管理2.1 C 中的 new 和 delete2.2 内存泄漏 3. 面向对象编程3.1 继承和多态3.2 多重继承 4. 模板和泛型编程4.1 函数模板4.2 类模板 5. STL 和标准库5.1 容器5.2 迭代器 6. 高级特性6.1 移动语义…...
WPF基础03——InitializeComponent()函数解释
总述 InitializeComponent(),是MainWindow中的构造函数,实际写项目过程中,多多少少都会碰到该函数报错的情况,现在对InitializeComponent()做一些理解和说明。 在 WPF 中,XAML 文件和代码后台…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
