JavaSE进阶——Day08 异常、Lambda表达式、Stream流、File类、递归

JavaSE进阶——Day08 该篇主要讲解Java中的异常、Lambda表达式、Stream流、File类、递归

回顾

logback使用步骤:

  1. 在当前项目下导入logback相关jar文件,并添加到项目工程资源库中
  2. 把logback核心配置文件,复制到当前项目工程的src目录下
  3. 在开发的类中,创建logback对象,使用logback中的API方法记录日志信息

logback日志级别:

  1. trace //追踪
  2. debug //调试(程序有bug,测试bug使用的)
  3. info //关键信息
  4. warn //警告
  5. error //错误

异常

什么是异常?

  • 程序在运行过程中,发生了不正常的情况,造成程序中断向下执行

有异常了怎么办呢?

  • 当前发生异常的代码位置处,有处理异常的代码,那么异常就会被处理掉,程序继续执行
  • 当前发生异常的代码位置处,没有处理异常的代码(程序中没有处理异常的代码),最终异常会抛出给JVM来处理
    • JVM处理异常的方式:
      1. 打印异常的信息(异常的类型、异常发生的位置、异常的原因)
      2. JVM停止

异常体系

image-20240425014443078

异常处理的方式:

  1. 声明:throws
    • 遇到异常发生了,自己不处理,交给别人处理
      • 最终还是需要有一个位置使用try..catch来处理异常
        • 结论:在main方法中,只能使用try..catch
  2. 捕获:try..catch
    • 遇到异常发生了,自己处理

使用声明的方式处理异常:

1
2
3
4
5
//使用声明的方式处理异常,声明是书写在方法定义上
修饰符号 返回值类型 方法名(参数类型 参数,...) throws 异常类1 , 异常类2 , ....
{

}
1
2
3
4
//在定义方法时,使用声明的方式处理异常
public void method(String name) throws NullPointerException {
//
}

image-20240425004947611

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package ex;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/25 00:52
* @Project JavaCode_SE_Advance
* @Theme 异常类型及处理
*/
public class ExceptionDemo2 {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
//1.编译时异常 (编译时异常在编译时就会检查, 所以必须写在方法后面进行显示声明)
try {
mothed1(sdf, "2024-04-24");
} catch (ParseException e) {
System.out.println("时间格式不正确");
}

//2.运行时异常
int[] arr = new int[5];
String str = null;
mothed2(arr, str);
}

private static void mothed1(SimpleDateFormat sdf, String strDate) throws ParseException {
//1.编译时异常, 捕获时间解析异常
//父类: Exception
//子类: ParseException
System.out.println(sdf.parse(strDate));
}

private static void mothed2(int[] arr, String str) throws RuntimeException {
//2.运行时异常
//子类: ArrayIndexOutOfBoundsException
// NullPointerException
//父类: RuntimeException
System.out.println(str.length() + arr[arr.length]);
}

}

Java基础面试题 : throws和throw的区别
  • throws : 声明

  • throw : 抛出 (手动引发异常)

    • 程序员手动创建一个异常对象,并招抛出给调用者
1
2
//把创建的异常类对象抛出给调用者
throw new RuntimeException("参数不能为空");

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package ex;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/25 01:23
* @Project JavaCode_SE_Advance
* @Theme throw抛出异常
*/
public class ExceptionDemo3 {
public static void main(String[] args) {
String name = null;
getName(name); //这里需要对抛出的异常进行捕获
}

private static void getName(String name) {
if (name == null || "".equals(name)){
//当前方法不能够解决该异常时候抛出异常
throw new RuntimeException("name不能为空", new NullPointerException("空指针异常"));
//System.out.println("dadada"); 不可再写
}
System.out.println("dadada");
}
}

异常处理有两种:声明、捕获,在程序开发中到底怎么选择使用哪个呢?

  • 自定义方法(程序员自己写的方法),通常都可以使用:声明

    • 方法体内代码比较清爽(阅读性好)
    • 把异常统一抛出到main方法中,进行统一的处理
  • 捕获的使用场景:

    1. main方法中只能使用捕获

    2. 父类型中的方法不支持throws,在子类重写方法时,重写的方法只能使用:捕获

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Demo  extends Thread{
      //重写方法
      public void run(){

      try {
      Thread.sleep(100);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }
      }

捕获和日志代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package ex;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/25 16:42
* @Project JavaCode_SE_Advance
* @Theme 异常捕获
*/
public class ExceptionDemo4 {
private static final Logger LOGGER = LoggerFactory.getLogger("ExceptionDemo4类");
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("输入你的生日(年-月-日):");
String birthday = sc.nextLine();
try {
mothed(birthday); //需要捕获(调用的方法可能发生异常,需要自己处理)
System.out.println("生日: " + birthday);
} catch (ParseException e) {
System.out.println("开始捕获异常");
LOGGER.error(e.getMessage());
}
}
}

private static Date mothed(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(date); //需要声明异常
}
}

Throwable类 //异常的顶层父类型

  • 子类:Error类(错误类) //异常处理无法解决错误

  • 子类:Exception类(异常类)//可以使用异常处理解决(保证程序运行过程中不会中断)

编译时异常:Exception类

运行时异常:RuntimeException类 (继承了Exception)

自定义异常:

  • 程序员自己编写的异常类

  • 解决问题: JDK提供的异常类在命名上做不到见名其知意,通常在开发中程序员会自定义自己的异常类(见名其知意)

  • 使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public 自定义异常类 extends Exception{ //当前自定义异常类为:编译时异常
    public 自定义异常类(){
    //super();//调用父类中的无参构造方法
    }
    public 自定义异常类(String message){
    super(message);
    }
    }

    public 自定义异常类 extends RuntimeException{ //当前自定义异常类为:运行时异常

    }

Lambda

lambda作用:

  • 简化程序中的匿名内部类代码书写

lambda表达式:

  • 前置要求:仅针对函数式接口进行代码编写

    • 函数式接口的特点:接口中仅有一个抽象方法(允许有:静态方法、默认方法、私有方法)
    1
    2
    3
    4
    @FunctionalInterface    //java针对函数式接口,制定了一个注解:@FunctionalInterface
    public interface Comparator<T> {
    .......
    }
  • 标准语法:

    1
    2
    3
    (参数 , ....) -> {
    //方法体代码(要做什么事情)
    }
    • () : 代表的是一个方法
    • -> : 指向要做的事情
    • { } : 功能代码(具体要做事情的代码)

    例:使用Collections对List排序, 要求使用比较器实现降序,用Lambda简化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package lam;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/25 22:15
* @Project JavaCode_SE_Advance
* @Theme 使用Collections对List排序, 要求使用比较器实现降序,用Lambda简化
*/
public class LambdaDemo2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 4, 6, 2, 4, 8);

//1.之前写法
// Collections.sort(list, new Comparator<Integer>() {
// @Override
// public int compare(Integer n1, Integer n2) {
// return n2 - n1;
// }
// });

//2.使用Lambda表达式
Collections.sort(list, (Integer n1, Integer n2) -> {
return n2 - n1;
});

System.out.println(list);
}
}

例:带参和返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Calculator接口
package lam;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/26 00:23
* @Project JavaCode_SE_Advance
* @Theme 代参数与返回值的接口方法
*/
//函数式接口(计算器)
@FunctionalInterface
public interface Calculator {
public abstract int calculator(int n1, int n2);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//CalculatorDemo类
package lam;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/26 00:26
* @Project JavaCode_SE_Advance
* @Theme 带参数与返回值的Lambda
*/
public class CalculatorDemo {
public static void main(String[] args) {
addNum((int n1, int n2) -> {
return n1 + n2;
});
}

private static void addNum(Calculator calculator) {
int res = calculator.calculator(10, 20);
System.out.println(res);

}
}

Lambda表达式的省略模式:

  1. 可以省略参数类型:要么全部省略,要么全部保留
  2. 如果参数仅有一个时,可以省略小括号
  3. 如果代码块中仅有一行代码,可以省略:大括号、分号、return

Stream流

stream流的作用:

  • 针对集合进行功能简化开发

Stream流的使用通常需要Lambda表达式

Stream流方法分类:

  1. 获取方法:获取流(创建一个流水线)
  2. 中间方法:在流水线进行操作(例:过滤、截取)
  3. 终结方法:流水线上的操作结束了,要关闭流水线

获取Stream流对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//单列集合:Collection[ List、Set ]
Stream 流对象 = 单列集合对象.stream();


//双列集合:Map (不能直接获取流对象)
1. 先通过keySet()或entrySet(),获取到Set集合
2. Stream 流对象 = Set集合对象.stream();


//数组
Stream 流对象 = Arrays.stream( 数组 );

//特殊的操作: Stream流中的静态方法: static<T> Stream<T> of( T... args )
Stream 流对象 = Stream.of( 同一种类型元素 ,同一种类型元素,同一种类型元素, ... );

代码案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package stream_demo;

import java.util.*;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/26 20:45
* @Project JavaCode_SE_Advance
* @Theme Stream流
*/


/*
Stream流中三类方法之一 : 获取方法

1 单列集合
可以使用Collection接口中的默认方法stream()生成流
default Stream<E> stream()
2 双列集合
双列集合不能直接获取 , 需要间接的生成流
可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
3 数组
Arrays中的静态方法stream生成流
*/
public class StreamDemo1 {
public static void main(String[] args) {
// 单列集合的获取
method1();

// 双列集合的获取
System.out.println();
method2();

// 数组获取
System.out.println();
method3();

}

private static void method2() {
//注意,双列集合需要用特有方法
Map<Integer, String> map = new HashMap<>();
map.put(1, "Java基础");
map.put(2, "Java进阶");
map.put(3, "MySQL");
map.put(4, "JavaWeb");
map.put(5, "Spring");
map.entrySet().stream().forEach(s -> System.out.print(s + "\t"));
}

private static void method1() {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 3, 6, 2, 4, 7, 3);
list.stream().forEach(s-> System.out.print(s + "\t"));
}

private static void method3() {
int[] arr = {2, 74, 342, 42, 23, 5};
Arrays.stream(arr).forEach(s -> System.out.print(s + "\t"));
}

}

中间方法:

image-20240426142645400

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package stream_demo;

import java.util.ArrayList;
import java.util.Comparator;

/**
* @Author EthanLiu 16693226842@163.com
* @Date 2024/4/26 21:35
* @Project JavaCode_SE_Advance
* @Theme Stream流 中间方法
*/


/*
Stream流中三类方法之一 : 中间方法

1 Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法 : boolean test(T t):对给定的参数进行判断,返回一个布尔值
2 Stream<T> limit(long maxSize):截取指定参数个数的数据
3 Stream<T> skip(long n):跳过指定参数个数的数据
4 static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
5 Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
6 Stream<T> sorted () : 将流中元素按照自然排序的规则排序
7 Stream<T> sorted (Comparator<? super T> comparator) : 将流中元素按照自定义比较器规则排序

*/
public class StreamDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张三丰");
list.add("谢广坤");
list.add("谢广坤");
list.add("赵四");
list.add("刘能");
list.add("小沈阳");
list.add("张良");
list.add("张良");

list.stream()
.filter(name->name.startsWith("谢")) //筛选器, 按照条件筛选
.forEach(-> System.out.println(s));
System.out.println();
list.stream().limit(5).forEach(s-> System.out.println(s)); //只筛选限制的前n个
System.out.println();
list.stream().skip(3).forEach(s-> System.out.println(s)); //跳过前n个
System.out.println();
list.stream().distinct().forEach(s-> System.out.println(s)); //去重
System.out.println();
list.stream().sorted().forEach(s -> System.out.println(s)); //自然排序
System.out.println();
list.stream()
.sorted((str1, str2)-> str1.length() - str2.length()) //重写的Lambda比较器
.forEach(s -> System.out.println(s));

//回顾往期比较器
// list.stream().sorted(new Comparator<String>() {
// @Override
// public int compare(String str1, String str2) {
// int res = str1.length() - str2.length();
// if (res == 0){
// res = str1.compareTo(str2);
// }
// return res;
// }
// });
}
}

终结方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package stream_demo;

import java.util.ArrayList;
import java.util.function.Consumer;

/*
Stream流中三类方法之一 : 终结方法
1 void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
2 long count():返回此流中的元素数

*/
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张三丰");
list.add("谢广坤");

// long count():返回此流中的元素数,终结方法,流不可再用,需重新创建流对象
long count = list.stream().count();
System.out.println(count);
}
// void forEach(Consumer action):对此流的每个元素执行操作
private static void method1(ArrayList<String> list) {
// 把list集合中的元素放在stream流中
// forEach方法会循环遍历流中的数据
// 并循环调用accept方法 , 把数据传给s
// 所以s就代表的是流中的每一个数据
// 我们只要在accept方法中对数据做业务逻辑处理即可
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});

System.out.println("=====================");

list.stream().forEach( (String s) -> {
System.out.println(s);
});

System.out.println("=====================");

list.stream().forEach( s -> { System.out.println(s); });
}

}

Stream流转换

Stream流收集方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package stream_demo;

import java.util.ArrayList;

/*
Stream流的收集操作 : 第一部分

需求:过滤元素并遍历集合
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
将集合中的奇数删除,只保留偶数。
遍历集合得到2,4,6,8,10

结论:在Stream流中无法直接修改集合,数组等数据源中的数据。
*/
public class StreamDemo5 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();

for (int i = 1; i <= 10; i++) {
list.add(i);
}

list.stream().filter(num -> num % 2 == 0).forEach(num -> System.out.println(num));

System.out.println("=============");

// 结论:在Stream流中无法直接修改集合,数组中的数据。
System.out.println(list);
}
}

结论:在Stream流中无法直接修改集合,数组中的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package stream_demo;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/*

Stream流的收集操作 : 第二部分

使用Stream流的方式操作完毕之后,我想把流中的数据起来,该怎么办呢?

Stream流的收集方法
R collect(Collector collector) : 此方法只负责收集流中的数据 , 创建集合添加数据动作需要依赖于参数

工具类Collectors提供了具体的收集方式
public static <T> Collector toList():把元素收集到List集合中
public static <T> Collector toSet():把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中


需求 :
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
将集合中的奇数删除,只保留偶数。
遍历集合得到2,4,6,8,10
*/
public class StreamDemo6 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
list.add(10);
list.add(10);
list.add(10);
list.add(10);
list.add(10);

// collect只负责收集流中的数据
// Collectors.toList()会负责在底层创建list集合 ,并把数据添加到集合中 , 返回集合对象
List<Integer> list2 = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toList());
System.out.println(list2);

Set<Integer> set = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toSet());
System.out.println(set);

}
}

image-20240427104636356

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package stream_demo;

import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;

/*
Stream流的收集操作 : 第三部分

1 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
"zhangsan,23"
"lisi,24"
"wangwu,25"
2 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

收集方法 :
public static Collector toMap(Function keyMapper , Function valueMapper):把元素收集到Map集合中
*/
public class StreamDemo7 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");

// collect 只负责收集数据
// Collectors.toMap负责在底层创建集合对象 , 添加元素
// toMap方法中的s就是代表的是集合中的每一个元素
// 第一个参数 : 如何获取map集合中的键
// 第二个参数 : 如何获取map集合中的值
Map<String, String> map = list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) > 23).collect(
Collectors.toMap(
(String s) -> {
return s.split(",")[0];
}
,
(String s) -> {
return s.split(",")[1];
}
)
);
System.out.println(map);
}
}

Optional类判空

  • jdk统一非空对象的判断的工具类
1
2
3
4
5
6
7
8
9
10
boolean res = Optional.ofNullable(对象).is对象所属类();


//拆分
Optional<类> optional对象 = Optional.ofNullable(对象)
if (optional对象.is对象所属类()){
....
}else{
....
}

File类

File类的介绍

  • java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作

构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package file_demo;

import java.io.File;

/*
File:它是文件和目录路径名的抽象表示
文件和目录可以通过File封装成对象
File封装的对象仅仅是一个路径名。它可以是存在的,也可以是不存在的。
构造方法 :
1 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
2 File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
3 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
*/
public class FileDemo1 {
public static void main(String[] args) {
// 1 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File f1 = new File("~/Desktop/abc.txt");
System.out.println(f1);
// 2 File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
File f2 = new File("~/Desktop/aaa", "bbb.txt");
System.out.println(f2);

// 3 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
File f3 = new File(new File(~/Desktop/aaa"), "bbb.txt");
System.out.println(f3);
}
}

File类的创建功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package file_demo;


import java.io.File;
import java.io.IOException;

/*
File类的创建功能 :
1 public boolean createNewFile() : 创建一个新的空的文件
2 public boolean mkdir() : 创建一个单级文件夹
3 public boolean mkdirs() : 创建一个多级文件夹
*/
public class FileDemo2 {
public static void main(String[] args) throws IOException {
File f1 = new File("~/Desktop/a.txt");
// 1 public boolean createNewFile() : 创建一个新的空的文件
System.out.println(f1.createNewFile());

File f2 = new File("day10_demo/aaa");
// 2 public boolean mkdir() : 创建一个单级文件夹
System.out.println(f2.mkdir());

File f3 = new File("day10_demo/bbb/ccc");
// 3 public boolean mkdirs() : 创建一个多级文件夹
System.out.println(f3.mkdirs());
}
}

File类的删除功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package file_demo;

import java.io.File;
import java.io.IOException;

/*
File类删除功能 :
public boolean delete() 删除由此抽象路径名表示的文件或目录

注意 :
1 delete方法直接删除不走回收站。
2 如果删除的是一个文件,直接删除。
3 如果删除的是一个文件夹,需要先删除文件夹中的内容,最后才能删除文件夹
*/
public class FileDemo3 {

public static void main(String[] args) throws IOException {
File f1 = new File("~/Desktop/a.txt");
// 1 public boolean createNewFile() : 创建一个新的空的文件
System.out.println(f1.delete());

File f2 = new File("day10_demo/aaa");
// 2 public boolean mkdir() : 创建一个单级文件夹
System.out.println(f2.delete());

File f3 = new File("day10_demo/bbb");
// 3 public boolean mkdirs() : 创建一个多级文件夹
System.out.println(f3.delete());
}
}

File类的判断和获取功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package file_demo;

import java.io.File;

/*
File类判断和获取功能
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件或目录的名称
*/
public class FileDemo4 {
public static void main(String[] args) {
File f1 = new File("day10_demo/aaa");
File f2 = new File("day10_demo/a.txt");

// public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
System.out.println(f1.isDirectory());
System.out.println(f2.isDirectory());

// public boolean isFile() 测试此抽象路径名表示的File是否为文件
System.out.println(f1.isFile());
System.out.println(f2.isFile());

// public boolean exists() 测试此抽象路径名表示的File是否存在
System.out.println(f1.exists());

// public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
System.out.println(f1.getAbsolutePath());

// public String getPath() 将此抽象路径名转换为路径名字符串
System.out.println(f1.getPath());

// public String getName() 返回由此抽象路径名表示的文件或目录的名称
System.out.println(f2.getName());
}
}

File类高级获取功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package file_demo;

import java.io.File;

/*
File类高级获取功能
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组

listFiles方法注意事项:
1 当调用者不存在时,返回null
2 当调用者是一个文件时,返回null
3 当调用者是一个空文件夹时,返回一个长度为0的数组
4 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
5 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
*/
public class FileDemo5 {
public static void main(String[] args) {
File file = new File("day10_demo/bbb/ccc");

// 返回此抽象路径名表示的目录中的文件和目录的File对象数组
File[] files = file.listFiles();

// 遍历File类的数组
for (File f : files) {
// 拿到每一个文件的文字
System.out.println(f.getName());
}
}
}

练习 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package file_demo;

import java.io.File;
import java.util.HashMap;

/*
练习二 :统计一个文件夹中每种文件的个数并打印。

打印格式如下:
txt:3个
doc:4个
jpg:6个

*/
public class FileTest2 {
public static void main(String[] args) {
File file = new File("day10_demo/统计文件个数文件夹");

getFileCount(file);
}

public static void getFileCount(File f) {

HashMap<String, Integer> hm = new HashMap<>();

// 是文件夹在获取所有的子文件
if (f.isDirectory()) {
File[] files = f.listFiles();
// 遍历数组
for (File file : files) {
String fileName = file.getName();
String name = fileName.split("\\.")[1];
if (hm.containsKey(name)) {
hm.put(name, hm.get(name));
} else {
hm.put(name, 1);
}
}
}

System.out.println(hm);
}
}

递归

概述

  • 递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象

好处

  • 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
    小的问题解决 , 大的问题也会逐一进行解决

注意

  • 递归出口:否则会出现内存溢出
  • 递归规则:需要找到与原问题相似的规模较小的问题

案例

  • ```java
    package com.itheima.recursion_demo;

/*
需求:用递归求5的阶乘,并把结果在控制台输出

      思路:
          1 定义一个方法,用于递归求阶乘,参数为一个int类型的变量
          2 在方法内部判断该变量的值是否是1
              是:返回1
              不是:返回n*(n-1)!
          3 调用方法
          4 输出结果

*/
public class Demo1 {
public static void main(String[] args) {
int result = jc(5);
System.out.println(“5的阶乘是:” + result);
}

  private static int jc(int n) {
      if (n == 1) {
          return 1;
      }
      return n * jc(n - 1);
  }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37



- ```java
package com.itheima.recursion_demo;

import java.io.File;

/*
需求 : 使用递归删除计算机中指定的文件夹

删除D盘中的aaa文件夹!

*/
public class Demo2 {
public static void main(String[] args) {
File f = new File("D:\\aaa");
deleteFiles(f);
}

private static void deleteFiles(File f) {

File[] files = f.listFiles();

for (File file : files) {
if (file.isDirectory()) {
// 递归
deleteFiles(file);
} else {
// 删除文件
file.delete();
}
}
// 删除当前文件夹
f.delete();
}
}