4.3 Stream流-File类

不可变集合

集合的添加,删除,修改的方法,都不能使用了

创建方式:

List.of (E... elements)
Set.of(E... elements)
Map.ofEntries(Map.Entry<? extends K,? extends V>... entries)

Stream流

体验Stream流【理解】

案例需求按照下面的要求完成集合的创建和遍历

  • 创建一个集合,存储多个字符串元素
  • 把集合中所有以”张”开头的元素存储到一个新的集合
  • 把”张”开头的集合中的长度为3的元素存储到一个新的集合
  • 遍历上一步得到的集合

原始方式示例代码

public class MyStream1 {
    public static void main(String[] args) {
        //集合的批量添加
        ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
        //list.add()

        //遍历list1把以张开头的元素添加到list2中。
        ArrayList<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if(s.startsWith("张")){
                list2.add(s);
            }
        }
        //遍历list2集合,把其中长度为3的元素,再添加到list3中。
        ArrayList<String> list3 = new ArrayList<>();
        for (String s : list2) {
            if(s.length() == 3){
                list3.add(s);
            }
        }
        for (String s : list3) {
            System.out.println(s);
        }      
    }
}
public class StreamDemo {
    public static void main(String[] args) {
        //集合的批量添加
        ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));

        //Stream流
        list1.stream().filter(s->s.startsWith("张"))
        .filter(s->s.length() == 3)
        .forEach(s-> System.out.println(s));
    }
}

Stream流的好处

直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印 Stream流把真正的函数式编程风格引入到Java中 代码简洁

Stream流:流水线式操作思想

图片[1]-4.3 Stream流-File类-IT熊技术站

获取Stream流(如何将手里的数据,放在流水线中)

A:集合

  • 单列集合:调用集合对象的stream方法即可
  • 双列集合:间接获取

B:数组

  • Arrays.stream(数组)

C:一堆零散的数据

  • Stream.of(元素, 元素, 元素)…

代码演示:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("张三丰");
    list.add("张无忌");
    list.add("张翠山");
    list.add("王二麻子");
    list.add("张良");
    list.add("谢广坤");
    
    Set<String> set = new HashSet<String>();
    set.add("张三丰");
    set.add("张无忌");
    set.add("张翠山");
    set.add("王二麻子");
    set.add("张良");
    set.add("谢广坤");
    
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("张三丰", 100);
    map.put("张无忌", 35);
    map.put("张翠山", 55);
    map.put("王二麻子", 22);
    map.put("张良", 30);
    map.put("谢广坤", 55);

    list.stream().forEach(s -> System.out.println(s));
    set.stream().forEach(s -> System.out.println(s));
    map.entrySet().stream().forEach(s -> System.out.println(s));
}

中间操作方法(流水线的中间工序)

操作之后, 可以继续进行其他操作

方法名说明
Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
Stream<T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<T> distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤");

    list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
}
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();

    list.add("林青霞");
    list.add("张曼玉");
    list.add("王祖贤");
    list.add("柳岩");
    list.add("张敏");
    list.add("张无忌");

    // 需求1:取前4个数据组成一个流
    Stream<String> s1 = list.stream().limit(4);

    // 需求2:跳过2个数据组成一个流
    Stream<String> s2 = list.stream().skip(2);

    // 需求3:合并需求1和需求2得到的流,并把结果在控制台输出
    // Stream.concat(s1, s2).forEach(s -> System.out.println(s));

    // 需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
    Stream.concat(s1, s2).distinct().forEach(s -> System.out.println(s));
}

终结操作方法(流水线的最后一道工序)

概念终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

常见方法

方法名说明
void forEach(Consumer action)对此流的每个元素执行操作
long count()返回此流中的元素数

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集合中(恶心)

代码演示

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

public class StreamDemo6 {
    /*
        Stream流的收集操作
     */
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        Collections.addAll(list1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10);

        // 需求1 : 将集合中, 偶数元素筛选出来, 收集到 List 集合
        List<Integer> list = list1.stream().filter(s -> s % 2 == 0).collect(Collectors.toList());
        System.out.println(list);

        // 需求2 : 将集合中, 奇数元素筛选出来, 收集到 Set 集合
        Set<Integer> set = list1.stream().filter(s -> s % 2 == 1).collect(Collectors.toSet());
        System.out.println(set);
    }
}
import java.util.ArrayList;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class StreamDemo5 {
    public static void main(String[] args) {
        // 创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
        ArrayList<String> list = new ArrayList<>();
        list.add("zhangsan,23");
        list.add("lisi,24");
        list.add("wangwu,25");

        // 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
        Map<String, Integer> map = list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return Integer.parseInt(s.split(",")[1]) >= 24;
            }
        }).collect(Collectors.toMap(new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s.split(",")[0];
            }
        }, new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s.split(",")[1]);
            }
        }));

        System.out.println(map);
    }
}

综合案例

案例需求:

现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

  • 男演员只要名字为3个字的前三人
  • 女演员只要姓林的,并且不要第一个
  • 把过滤后的男演员姓名和女演员姓名合并到一起
  • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

import java.util.ArrayList;
import java.util.stream.Stream;

public class StreamTest {
    public static void main(String[] args) {
        ArrayList<String> manList = new ArrayList<>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");

        ArrayList<String> womanList = new ArrayList<>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");

        // 男演员只要名字为3个字的前三人
        Stream<String> s1 = manList.stream().filter(s -> s.length() == 3).limit(3);

        // 女演员只要姓林的,并且不要第一个
        Stream<String> s2 = womanList.stream().filter(s -> s.startsWith("林")).skip(1);

        // 把过滤后的男演员姓名和女演员姓名合并到一起
        Stream<String> s3 = Stream.concat(s1, s2);

        // 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
        s3.forEach(name -> System.out.println(new Actor(name)));
    }
}

class Actor {
    private String name;

    public Actor() {
    }

    public Actor(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "Actor{name = " + name + "}";
    }
}

File类

File类概述和构造方法【应用】

File类介绍

File类代表操作系统的文件对象(文件、文件夹)

  • 它是文件和目录路径名的抽象表示
  • 文件和目录是可以通过File封装成对象的
  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,它可以是存在的,也可以是不存在的,将来是要通过具体的操作把这个路径的内容转换为具体存在的

File类的构造方法

方法名说明
File(String pathname)根据文件路径创建文件对象
File(String parent, String child)根据父路径名字符串和子路径名字符串创建文件对象
File(File parent, String child)根据父路径对应文件对象和子路径名字符串创建文件对象

示例代码

public class FileDemo01 {
    public static void main(String[] args) {
        //File(String pathname): 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
        File f1 = new File("E:\\itcast\\java.txt");
        System.out.println(f1);

        //File(String parent, String child): 从父路径名字符串和子路径名字符串创建新的 File实例
        File f2 = new File("E:\\itcast","java.txt");
        System.out.println(f2);

        //File(File parent, String child): 从父抽象路径名和子路径名字符串创建新的 File实例
        File f3 = new File("E:\\itcast");
        File f4 = new File(f3,"java.txt");
        System.out.println(f4);
    }
}

绝对路径和相对路径【理解】

  • 从盘符根目录开始,一直到某个具体的文件或文件夹
  • 相对路径是一个简化的路径,相对当前项目下的路径

示例代码

public class FileDemo02 {
    public static void main(String[] args) {
        // 是一个完整的路径,从盘符开始
        File file1 = new File("D:\\itheima\\a.txt");

        // 是一个简化的路径,从当前项目根目录开始
        File file2 = new File("a.txt");
        File file3 = new File("src\\com\\itheima\\day09-code\\a.txt");
    }
}

File类创建功能【应用】

方法分类

方法名说明
public boolean createNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir()创建由此抽象路径名命名的目录
public boolean mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录

示例代码

public class FileDemo02 {
    public static void main(String[] args) throws IOException {
        //需求1:我要在E:\\itcast目录下创建一个文件java.txt
        File f1 = new File("E:\\itcast\\java.txt");
        System.out.println(f1.createNewFile());
        System.out.println("--------");

        //需求2:我要在E:\\itcast目录下创建一个目录JavaSE
        File f2 = new File("E:\\itcast\\JavaSE");
        System.out.println(f2.mkdir());
        System.out.println("--------");

        //需求3:我要在E:\\itcast目录下创建一个多级目录JavaWEB\\HTML
        File f3 = new File("E:\\itcast\\JavaWEB\\HTML");
        //        System.out.println(f3.mkdir());
        System.out.println(f3.mkdirs());
        System.out.println("--------");

        //需求4:我要在E:\\itcast目录下创建一个文件javase.txt
        File f4 = new File("E:\\itcast\\javase.txt");
        //        System.out.println(f4.mkdir());
        System.out.println(f4.createNewFile());
    }
}

File类删除功能【应用】

方法分类

方法名说明
public boolean delete( )删除由此抽象路径名表示的文件或目录(只能删除空的文件夹,不走回收站)

示例代码

public class FileDemo03 {
    public static void main(String[] args) throws IOException {
        //        File f1 = new File("E:\\itcast\\java.txt");
        //需求1:在当前模块目录下创建java.txt文件
        File f1 = new File("myFile\\java.txt");
        //        System.out.println(f1.createNewFile());

        //需求2:删除当前模块目录下的java.txt文件
        System.out.println(f1.delete());
        System.out.println("--------");

        //需求3:在当前模块目录下创建itcast目录
        File f2 = new File("myFile\\itcast");
        //        System.out.println(f2.mkdir());

        //需求4:删除当前模块目录下的itcast目录
        System.out.println(f2.delete());
        System.out.println("--------");

        //需求5:在当前模块下创建一个目录itcast,然后在该目录下创建一个文件java.txt
        File f3 = new File("myFile\\itcast");
        //        System.out.println(f3.mkdir());
        File f4 = new File("myFile\\itcast\\java.txt");
        //        System.out.println(f4.createNewFile());

        //需求6:删除当前模块下的目录itcast
        System.out.println(f4.delete());
        System.out.println(f3.delete());
    }
}

File类判断和获取功能【应用】

判断功能

方法名说明
public boolean isDirectory( )测试此抽象路径名表示的File是否为目录
public boolean isFile( )测试此抽象路径名表示的File是否为文件
public boolean exists( )测试此抽象路径名表示的File是否存在

获取功能

方法名说明
public String getAbsolutePath( )返回此抽象路径名的绝对路径名字符串
public String getPath( )将此抽象路径名转换为路径名字符串
public String getName( )返回由此抽象路径名表示的文件或目录的名称
public File[ ] listFiles( )返回此抽象路径名表示的目录中的文件和目录的File对象数组
:::tips
  • 当调用者File表示的路径不存在时,返回null
  • 当调用者File表示的路径是文件时,返回null
  • 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
  • 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null ::: | |

示例代码

public class FileDemo04 {
    public static void main(String[] args) {
        //创建一个File对象
        File f = new File("myFile\\java.txt");

        //        public boolean isDirectory():测试此抽象路径名表示的File是否为目录
        //        public boolean isFile():测试此抽象路径名表示的File是否为文件
        //        public boolean exists():测试此抽象路径名表示的File是否存在
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.exists());

        //        public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串
        //        public String getPath():将此抽象路径名转换为路径名字符串
        //        public String getName():返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getPath());
        System.out.println(f.getName());
        System.out.println("--------");

        //        public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File f2 = new File("E:\\itcast");
        File[] fileArray = f2.listFiles();
        for(File file : fileArray) {
            //            System.out.println(file);
            //            System.out.println(file.getName());
            if(file.isFile()) {
                System.out.println(file.getName());
            }
        }
    }
}

File类练习一【应用】

判断用户输入的文件夹路径存不存在,存在输出

import java.io.File;
import java.util.Scanner;

public class FileTest1 {
    public static void main(String[] args) {
        File dir = getDir();
        System.out.println(dir);
    }

    public static File getDir() {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入文件夹路径:");

        while (true) {
            String path = sc.nextLine();
            File dir = new File(path);
            if (!dir.exists()) {
                System.out.print("您输入的文件夹路径不存在,请重新输入:");
            } else if (dir.isFile()) {
                System.out.print("您输入的是一个文件路径,请重新输入:");
            } else {
                return dir;
            }
        }
    }
}

File类练习二【应用】

获取文件名切割后,统计后缀名文件个数

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

public class FileTest2 {
    public static void main(String[] args) {
        File dir = FileTest1.getDir();
        // 准备Map集合,用于统计操作
        HashMap<String, Integer> hm = new HashMap<>();
        // 获取文件夹中所有的文件和文件夹对象
        File[] files = dir.listFiles();
        int count = 0;
        // 遍历数组,获取每一个文件和文件夹对象
        for (File file : files) {
            // 获取文件名
            String fileName = file.getName();
            if (fileName.contains(".")) {
                // 根据 . 进行切割
                String[] sArr = fileName.split("\\.");
                // 获取后缀名
                String type = sArr[sArr.length - 1];
                // 统计
                if (!hm.containsKey(type)) {
                    hm.put(type, 1);
                } else {
                    hm.put(type, hm.get(type) + 1);
                }
            } else {
                // 说明没有后缀名
                count++;
            }
        }
        System.out.println(hm);
        System.out.println("没有后缀名的文件个数为:" + count);
    }
}

File类练习三【应用】

使用递归,获取文件下所有.java文件

import java.io.File;

public class FileTest3 {
    public static void main(String[] args) {
        File dir = FileTest1.getDir();
        printJavaFile(dir);
    }

    public static void printJavaFile(File dir) {
        // 1. 获取该文件夹下所有的文件和文件夹对象
        File[] files = dir.listFiles();
        // 2. 遍历数组,获取每一个文件和文件夹对象
        for (File file : files) {
            // 3. 判断当前对象,是否是文件
            if (file.isFile() && file.getName().endsWith(".java")) {
                System.out.println(file);
            } else if (file.isDirectory()) {
                // 4. 进入文件夹中,打印java文件
                // 思路:自己这个方法,就是进入文件夹找java文件的,递归调用即可
                if (file.listFiles() != null) {
                    printJavaFile(file);
                }
            }
        }
    }
}

File类练习四【应用】

案例需求删除一个多级文件夹 实现步骤

  • 定义一个方法,接收一个File对象
  • 遍历这个File对象,获取它下边的每个文件和文件夹对象
  • 判断当前遍历到的File对象是文件还是文件夹
  • 如果是文件,直接删除
  • 如果是文件夹,递归调用自己,将当前遍历到的File对象当做参数传递
  • 参数传递过来的文件夹File对象已经处理完成,最后直接删除这个空文件夹

代码实现

public class Test2 {
    public static void main(String[] args) {
        //练习四:删除一个多级文件夹
        //delete方法
        //只能删除文件和空文件夹.
        //如果现在要删除一个有内容的文件夹?
        //先删掉这个文件夹里面所有的内容.
        //最后再删除这个文件夹

        File src = new File("C:\\Users\\apple\\Desktop\\src");
        deleteDir(src);
    }

    //1.定义一个方法,接收一个File对象
    private static void deleteDir(File src) {
        //先删掉这个文件夹里面所有的内容.
        //递归 方法在方法体中自己调用自己.
        //注意: 可以解决所有文件夹和递归相结合的题目
        //2.遍历这个File对象,获取它下边的每个文件和文件夹对象
        File[] files = src.listFiles();
        //3.判断当前遍历到的File对象是文件还是文件夹
        for (File file : files) {
            //4.如果是文件,直接删除
            if(file.isFile()){
                file.delete();
            }else{
                //5.如果是文件夹,递归调用自己,将当前遍历到的File对象当做参数传递
                deleteDir(file);//参数一定要是src文件夹里面的文件夹File对象
            }
        }
        //6.参数传递过来的文件夹File对象已经处理完成,最后直接删除这个空文件夹
        src.delete();
    }

}

File类练习五【应用】

需求: 设计一个方法, 统计文件夹字节大小

import java.io.File;

public class FileTest5 {
    public static void main(String[] args) {
        long length = getLength(new File("D:\\Develop"));
        System.out.println(length);
    }

    public static long getLength(File dir) {
        long sumLength = 0;
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                sumLength += file.length();
            } else {
                if (file.listFiles() != null) {
                    sumLength += getLength(file);
                }
            }

        }
        return sumLength;
    }
}

File类练习六【应用】

使用递归统计文件里的文件类型个数

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

public class FileTest6 {
    static HashMap<String, Integer> hm = new HashMap<>();
    static int count = 0;

    public static void main(String[] args) {
        File dir = new File("E:\\Windows11 Penetration Suite Toolkit v2.1");
        getCount(dir);
        System.out.println(hm);
        System.out.println("没有后缀名的文件个数为:" + count);
    }

    public static void getCount(File dir) {
        // 获取文件夹中所有的文件和文件夹对象
        File[] files = dir.listFiles();
        // 遍历数组,获取每一个文件和文件夹对象
        for (File file : files) {
            if (file.isFile()) {
                // 获取文件名
                String fileName = file.getName();
                if (fileName.contains(".")) {
                    // 根据 . 进行切割
                    String[] sArr = fileName.split("\\.");
                    // 获取后缀名
                    String type = sArr[sArr.length - 1];
                    // 统计
                    if (!hm.containsKey(type)) {
                        hm.put(type, 1);
                    } else {
                        hm.put(type, hm.get(type) + 1);
                    }
                } else {
                    count++;
                }
            } else {
                if (file.listFiles() != null) {
                    getCount(file);
                }
            }
        }
    }
}
© 版权声明
THE END
喜欢就支持一下吧
点赞579赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容