黑马day08map-stream-File-IOapp

目录

Map

HashMap集合的底层原理

总结:

LinkedHashMap

LinkedHashMap集合原理

TreeMap

TreeMap集合同样也支持两种方式来指定排序规则

总结:

集合的嵌套

JDK8新特性:Stream

Stream流的使用步骤

总结:

1.获取Stream流

2.Stream流常见的中间方法

3.Stream的终结方法

File、IO流(一)

有些数据想要长久的保存起来的方法

File(代表文本)

创建对象

常用方法1:判断文件类型,获取文件信息

常用方法2:创建文件,删除文件

常用方法3:遍历文件夹

总结:

前置知识:方法递归

认识递归的形式

应用、执行流程、算法思想

其他应用:文件搜索

IO流(读写数据)


Map

HashMap集合的底层原理

HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。

实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。

但是它是无序,不能重复,没有索引支持的(由键决定特点)

HashMap的键依赖hashCode方法和equals方法保证键的唯一

如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的。

总结:

LinkedHashMap

由键决定,有序,无重复,无索引

LinkedHashMap集合原理

底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。

实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap.

TreeMap

TreeMap(由键决定特点):按照键的大小默认升序排序、不重复、无索引。

原理:TreeaSet和TreeMap的底层原理一样,都是基于红黑树实现的排序

TreeMap集合同样也支持两种方式来指定排序规则

让类实现Comparable接口,重写比较规则。

TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。

总结:

集合的嵌套

指的是集合中的元素又有一个集合

/**
 * 目标:理解集合的嵌套。
 * 江苏省 = "南京市","扬州市","苏州市“,"无锡市","常州市"
 * 湖北省 = "武汉市","孝感市","十堰市","宜昌市","鄂州市"
 * 河北省 = "石家庄市","唐山市", "邢台市", "保定市", "张家口市"
 */
public class Test {
    public static void main(String[] args) {
        // 1、定义一个Map集合存储全部的省份信息,和其对应的城市信息。
        ArrayList<String> cities1 = new ArrayList<>();
        ArrayList<String> cities2 = new ArrayList<>();
        ArrayList<String> cities3 = new ArrayList<>();
        Collections.addAll(cities1, "南京市","扬州市","苏州市","无锡市","常州市");
//        System.out.println("cities1 = " + cities1);

        Collections.addAll(cities2, "武汉市","孝感市","十堰市","宜昌市","鄂州市");
        Collections.addAll(cities3, "石家庄市","唐山市", "邢台市", "保定市", "张家口市");


        //Map去保存省和对应市的关系
        HashMap<String, ArrayList<String>> provinces = new HashMap<>();
        provinces.put("江苏省", cities1);
        provinces.put("湖北省", cities2);
        provinces.put("河北省", cities3);

        //遍历
        Set<Map.Entry<String, ArrayList<String>>> entries = provinces.entrySet();
        for (Map.Entry<String, ArrayList<String>> entry : entries) {
            String key = entry.getKey();
            ArrayList<String> value = entry.getValue();
            System.out.println(key + " = " + value);
        }
    }
}

JDK8新特性:Stream

什么是Stream:

也叫Stream流,是ldk8开始新增的一套APl (java.util.stream.*),可以用于操作集合或者数组的数据。

优势:Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好。

Stream流的使用步骤

总结:

1.获取Stream流

/**
 * 目标:掌握Stream流的创建。
 *
 * List 和Set集合都是Collection的子类型,都可以直接用stream方法获取流
 * 2.Map双列集合都没有直接获取流的方法,需要转为单列集合
 *  keySet  处理键
 *  values  处理值
 *  entrySet    键和值都要处理
 */
public class StreamTest2 {
    public static void main(String[] args) {
        // 1、如何获取List集合的Stream流?
        List<String> names = new ArrayList<>();
        Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
        Stream<String> stream = names.stream();

        // 2、如何获取Set集合的Stream流?
        Set<String> set = new HashSet<>();
        Collections.addAll(set, "刘德华","张曼玉","蜘蛛精","马德","德玛西亚");
        Stream<String> stream1 = set.stream();
        stream1.filter(s -> s.contains("德")).forEach(s -> System.out.println(s));



        // 3、如何获取Map集合的Stream流?
        Map<String, Double> map = new HashMap<>();
        map.put("古力娜扎", 172.3);
        map.put("迪丽热巴", 168.3);
        map.put("马尔扎哈", 166.3);
        map.put("卡尔扎巴", 168.3);

        //处理键
        map.keySet().stream().forEach(System.out::println);
        //处理值
        map.values().stream().forEach(System.out::println);
        //处理键和值
        map.entrySet().stream().forEach(System.out::println);
        System.out.println("===============");
        map.entrySet().stream().forEach(entry -> {
            System.out.println(entry.getKey() + "-->" + entry.getValue());
        });



        // 4、如何获取数组的Stream流?
        System.out.println("==============");
        String[] names2 = {"张翠山", "东方不败", "唐大山", "独孤求败"};
        //方案一:
        Arrays.stream(names2).forEach(System.out::println);


        //方案二:
        Stream.of(names2).forEach(System.out::println);
    }
}

2.Stream流常见的中间方法

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)

/**
 * 目标:掌握Stream流提供的常见中间方法。
 */
public class StreamTest3 {
    public static void main(String[] args) {
        // 需求1:已知如下数据,找出成绩大于等于60分的数据,并升序后,再输出。
        List<Double> scores = new ArrayList<>();
        Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0);

        scores.stream().filter(score -> score >= 60)
//                .sorted()//默认按照元素的排序规则升序排序
                .sorted((s1,s2) -> s2.compareTo(s1)).forEach(System.out::println);

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


        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);

        // 需求2:已知students学生集合,找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出.
        students.stream()
                .filter(student -> student.getAge() >= 23 && student.getAge() <= 30)
                .sorted((stu1, stu2) -> Integer.compare(stu2.getAge(), stu2.getAge()))
                .forEach(System.out::println);

        System.out.println("=================");
        // 需求3:已知students学生集合,取出身高最高的前3名学生,并输出。
        students.stream()
                .sorted((stu1, stu2) -> Double.compare(stu2.getHeight(), stu2.getHeight()))
                .limit(3).forEach(System.out::println);

        System.out.println("===============");
        // 需求4:取出身高倒数2名学生,并输出学生信息。
        students.stream()
                .sorted((stu1, stu2) -> Double.compare(stu2.getHeight(), stu2.getHeight()))
                .skip(students.size()-2).forEach(System.out::println);

        System.out.println("===============");
        // 需求5:找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出。
        // distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode,equals)
        students.stream().filter(student -> student.getHeight() >= 168)
                .distinct()//去重的是学生对象
                .forEach(System.out::println);

        System.out.println("=============");
        //需求6:把学生集合中所有的名字拿出来,并把重复的名字去重
        students.stream().map((student) -> student.getName())//把流中的学生对象转换为了名字字符串对象
                .distinct()//去重的是字符串
                .forEach(System.out::println);

        System.out.println("=================");
        //需求7:已知第一组的名字和第二组的名字,把两个组生成的流合并为一个流
        Stream<String> stream1 = Stream.of("张三丰", "张无忌", "张翠山");
        Stream<String> stream2 = Stream.of("灭绝师太", "周芷若", "赵敏");

        Stream.concat(stream1, stream2).forEach(System.out::println);
    }
}

3.Stream的终结方法

终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。

收集stream流: 就是把stream流操作后的结果转回到集合或者数组中去返回。

Stream流: 方便操作集合/数组的手段;

集合/数组: 才是开发中的目的。

/**
 * 目标:Stream流的终结方法
 */
public class StreamTest4 {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);

        //已知students集合存储了若干数据

        // 需求1:请计算出身高超过168的学生有几人。
        long count = students.stream().filter(student -> student.getHeight() >= 168)
                .count();
        System.out.println("count = " + count);

        // 需求2:请找出身高最高的学生对象,并输出。
        Student student1 = students.stream().max((stu1, stu2) -> Double.compare(stu1.getHeight(), stu2.getHeight()))
                .get();
        System.out.println("student1 = " + student1);

        // 需求3:请找出身高最矮的学生对象,并输出。
        Student student2 = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
        System.out.println("student2 = " + student2);

        // 需求4:请找出身高超过170的学生对象,并放到一个新集合中去返回。
        List<Student> list = students.stream().filter(student -> student.getHeight() >= 170)
                .collect(Collectors.toList());

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

        // 需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。
        //Map<String,Double>
        Map<String, Double> map = students.stream().filter(student -> student.getHeight() > 170)
                .distinct().collect(Collectors.toMap(Student::getName, student -> student.getHeight()));

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

        //变数组
        Object[] objects = students.stream().filter(student -> student.getHeight() > 170)
                .toArray();
        System.out.println(Arrays.toString(objects));

        //
        Student[] array = students.stream().filter(student -> student.getHeight() > 170).toArray(len -> new Student[len]);
        System.out.println("Arrays.toString(array) = " + Arrays.toString(array));

    }
}

File、IO流(一)

他们都是内存中的数据容器,他们记住的数据会在断电时永久丢失。

有些数据想要长久的保存起来的方法

文件是非常重要的存储方式,在计算机硬盘中。

即便断电,或者程序终止了,存储在硬盘文件中的数据也不会丢失。

File(代表文本)

File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。

注意:

File类只能对文件本身进行操作,不能读写文件里面存储的数据。

创建对象

绝对路径:从盘符开始

相对路径:不带盘符,默认直接到当前工程目录下的目标寻找文件

总结:

常用方法1:判断文件类型,获取文件信息

File提供的判断文件类型、获取文件信息功能

/**
     目标:掌握File提供的判断文件类型、获取文件信息功能
 */
public class FileTest2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // 1.创建文件对象,指代某个文件
        File file1 = new File("D:\\abc\\HelloWord.txt");
        File file2 = new File("D:\\abc");
        File file3 = new File("D:\\abc\\zhuxian.txt");

        // 2、public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
        System.out.println("file1.exists() = " + file1.exists());//T
        System.out.println("file2.exists() = " + file2.exists());//T
        System.out.println("file3.exists() = " + file3.exists());//F


        System.out.println("==================");
        // 3、public boolean isFile() : 判断当前文件对象指代的是否是文件,是文件返回true,反之。
        System.out.println("file1.isFile() = " + file1.isFile());//F
        System.out.println("file2.isFile() = " + file2.isFile());//T
        System.out.println("file3.isFile() = " + file3.isFile());//F

        System.out.println("================");
        // 4、public boolean isDirectory()  : 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
        System.out.println("file1.isDirectory() = " + file1.isDirectory());//F
        System.out.println("file2.isDirectory() = " + file2.isDirectory());//T
        System.out.println("file3.isDirectory() = " + file3.isDirectory());//F

        System.out.println("================");
        // 5.public String getName():获取文件的名称(包含后缀)
        System.out.println("file1.getName() = " + file1.getName());//HelloWord.txt
        System.out.println("file2.getName() = " + file2.getName());//abc
        System.out.println("file3.getName() = " + file3.getName());//zhuxian.txt

        System.out.println("================");
        // 6.public long length():获取文件的大小,返回字节个数
        System.out.println("file1.length() = " + file1.length());
        System.out.println("file2.length() = " + file2.length());
        System.out.println("file3.length() = " + file3.length());

        System.out.println("================");
        // 7.public long lastModified():获取文件的最后修改时间。



        System.out.println("================");
        // 8.public String getPath():获取创建文件对象时,使用的路径
        System.out.println("file1.getPath() = " + file1.getPath());
        System.out.println("file2.getPath() = " + file2.getPath());
        System.out.println("file3.getPath() = " + file3.getPath());


        // 9.public String getAbsolutePath():获取绝对路径
        System.out.println("file1.getAbsolutePath() = " + file1.getAbsolutePath());


    }
}

常用方法2:创建文件,删除文件

File类创建文件的功能

File类删除文件的功能

注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。

/**
 * 目标:掌握File创建和删除文件相关的方法。
 */
public class FileTest3 {
    public static void main(String[] args) throws Exception {
        // 1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File file = new File("D:\\abc");
        //如果文件所在的父路径不存在就会报错
        //如果文件存在,再次创建会返回false
        System.out.println(file.createNewFile());

        // 2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
        File file2 = new File("D:\\abc\\music");
        System.out.println("file2.mkdir() = " + file2.mkdir());

        // 3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File file3 = new File("D:\\abc\\movie\\周星驰");
        System.out.println("file3.mkdirs() = " + file3.mkdirs());

        // 3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
        File file4 = new File("D:\\abc\\HelloWord.txt");
        System.out.println("file4.delete() = " + file4.delete());
        //删除文件夹(文件夹需要是空的)
        File file5 = new File("D:\\abc\\music");
        System.out.println("file5.delete() = " + file5.delete());
    }
}

常用方法3:遍历文件夹

/**
 * 目标:掌握File提供的遍历文件夹的方法。
 */
public class FileTest4 {
    public static void main(String[] args) {
        // 1、public String[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
        File file = new File("day08map-stream-app/src/com/itheima/d4_file");
        System.out.println("file.exists() = " + file.exists());

        String[] list = file.list();
        Stream.of(list).forEach(System.out::println);

        // 2、public File[] listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = file.listFiles();
        Stream.of(files).forEach(file1 -> System.out.println(file.getAbsolutePath()));


        //当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
        File file2 = new File("xxxx");
        File file3 = new File("day08map-stream-app/itheima/d4_file");
        System.out.println("file2.listFiles() = " + file2.listFiles());//null
        System.out.println("file3.listFiles() = " + file3.listFiles());//null

    }
}

使用listFiles方法时的注意事项:

当主调是文件,或者路径不存在时,返回null

当主调是空文件夹时,返回一个长度为0的数组

当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回

当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件

当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

总结:

前置知识:方法递归

认识递归的形式

什么是方法递归?

递归是一种算法,在程序设计语言中广泛应用。

从形式上说:方法调用自身的形式称为方法递归( recursion)。

递归的形式

直接递归:方法自己调用自己。

间接递归:方法调用其他方法,其他方法又回调方法自己

使用方法递归时需要注意的问题:

递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。

应用、执行流程、算法思想

    public static long f(int n) {
        if (n == 1) {
            return 1;
        } else {
            return f(n - 1) * n;
        }
    }

递归算法三要素:

递归公式:f(n) = f(n - 1) * n

递归的终结点:f(1)

递归的方向必须走向终结点

public static long sum(int n) {
        if (n == 1) {
            return 1;
        } else {
            return sum(n - 1) + n;
        }
    }

总结:

其他应用:文件搜索

/**
 * 目标:掌握文件搜索的实现。
 */
public class RecursionTest3 {
    public static void main(String[] args) {
        //查找
//        findFile(new File("day01oop-app1"), "HelloWord.java");

        //删除
        deleteFile(new File("day08map-stream-app\\movie"));
    }

    /**
     * @param dir      所在的文件夹
     * @param fileName 要查找的文件名
     */

    public static void findFile(File dir, String fileName) {
        //1.判断路径的合法性
        if (dir.isDirectory()) {
            //合法目录
            //2.遍历该文件夹中所有的子文件
            File[] files = dir.listFiles();
            //3.遍历文件夹中每一个文件对象 判断是不是为文件
            for (File file : files) {
                if (file.isFile()) {
                    //是一个文件,判断是不是我要找的文件
                    if (file.getName().equals(fileName)) {
                        //找到了
                        System.out.println("找到了" + file.getAbsolutePath());
                    }
                } else if (file.isDirectory()) {
                    //文件夹
                    //递归调用自身
                    findFile(file, fileName);
                }
            }
        } else {
            throw new RuntimeException("不是合法的文件夹");
        }
    }

    public static void deleteFile(File file) {
        //1.判断文件的合法性
        if (file.exists()) {
            if (file.isFile()) {
                System.out.println("删除了文件:" + file.getPath());
                file.delete();
            } else {
                //先删除文件夹的子文件
                File[] children = file.listFiles();
                for (File child : children) {
                    //递归调用
                    deleteFile(child);
                }

                //在删除当前文件家

                System.out.println("删除了文件:" + file.getPath());
                file.delete();
            }
        } else {
            throw new RuntimeException("删除的文件或文件夹不存在");
        }
    }
}

IO流(读写数据)

用于读写数据的(可以读写文件,或网络中的数据...)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值