Java之深入探究IO流操作与Lambda表达式

news2024/12/28 21:50:42

深入探究Java IO流操作与Lambda表达式的优雅结合

  • 1. IO流
    • 1.1 IO流的概念
    • 1.2 IO流的分类
    • 1.3 常见的IO流操作
      • 1.3.1 字节流操作
      • 1.3.2 字符流操作
      • 1.3.3 缓冲流
  • 2. Lambda表达式
    • 2.1 Lambda 表达式使用条件
    • 2.2 Lambda 表达式的分类
    • 2.3 Lambda 表达式在 IO 流操作中的应用
    • 2.4 常见的 IO 流和 Lambda 表达式使用场景
  • 3. 流式操作
    • 3.1 流操作的概念
    • 3.2 流操作的分类
    • 3.3 常用流操作的API
    • 3.4 案例
  • 4. 结语

欢迎来到本文,今天我们将一同探讨Java中关于IO流操作和Lambda表达式的精妙结合。随着JDK8的到来,Java语言引入了Lambda表达式,使得代码编写更加简洁、优雅。而在IO流操作中,这种简洁的编程风格同样能够发挥出色的作用。让我们一起深入了解,如何将Lambda表达式融入IO操作,使得我们的代码更加高效、易读。

1. IO流

1.1 IO流的概念


在开始讨论Lambda表达式的应用之前,我们首先需要理解IO流操作的基础概念。IO流(Input/Output Stream)是一种数据传输方式,用于在程序与外部资源(如文件、网络等)之间进行数据交换。IO流分为字符流和字节流两种,字符流适用于处理字符数据,而字节流则用于处理二进制数据。

1.2 IO流的分类


  • 根据数据处理的不同类型分为:字节流和字符流
  • 根据数据流向不同分为:输入流和输出流
  • 根据流的角色来分:节点流和处理流
    • 节点流:可以从一个特定的IO设备(如磁盘、网路)读/写数据的流。也被称为低级流。节点流的另一端是明确的,是实际读写数据的流,读写一定是建立在节点流基础上进行的。
    • 处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。也称为高级流。处理流不能独立存在,必须连接在其他流上,目的是当数据流经过当前流时对数据进行加工处理来简化我们对数据的操作。

在这里插入图片描述

  • 字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的流对象,本质上其实就是对于字节流的读取时,去查了指定的码表。
  • 字节流和字符流的区别
    • 读写单位的不同:字节流以字节(8bit)为单位。字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
    • 处理对象不同:字节流可以处理任何类型的数据,如图片、avi等,而字符流只能处理字符流类型的数据。

1.3 常见的IO流操作

1.3.1 字节流操作


字节流适用于处理图片、音频、视频等二进制文件,常见的字节流类包括InputStreamOutputStream。例如,通过FileInputStream读取二进制文件,通过FileOutputStream写入二进制文件。

  1. 文件操作字节输入流

    public class TestFileInputStream {
        public static void main(String[] args) throws IOException {
            readFile2();
        }
    
        public static void readFile() throws IOException {
            // 1. 确定文件
            String filePath = "D:/test/a.txt";
    
            // 2. 开启FileInputStream通道
            FileInputStream fis = new FileInputStream(filePath);
    
            // 3. 读取数据,需要准备一个byte类型数组 当前缓冲数组的容量为8kb
            byte[] buf = new byte[1024 * 8];
            int length = -1;
            while ((length = fis.read(buf)) != -1) {
                // 将读取到的数据,转换成一个String字符串
                System.out.println(new String(buf, 0, length));
            }
    
            // 4. 关闭资源
            fis.close();
        }
    
        public static void readFile2() throws IOException {
            // 1. 确定文件
            String filePath = "D:/test/a.txt";
    
            // 2. 开启FileInputStream通道
            FileInputStream fis = new FileInputStream(filePath);
    
            int content = -1;
            while ((content = fis.read()) != -1) {
                System.out.println((char) content);
            }
    
            // 4. 关闭资源
            fis.close();
        }
    }
    
  2. 文件操作字节输出流

    public class TestFileOutputStream {
        public static void main(String[] args) throws IOException {
            writeFile();
        }
    
        public static void writeFile() throws IOException {
            // 1. 确定文件位置
            String filePath = "D:/test/a.txt";
    
            // 2. 创建FileOutputStream流管道
            FileOutputStream fos = new FileOutputStream(filePath);
    
            // 3. 写入数据
            fos.write(550);
            fos.write("ABCDEFG".getBytes("UTF-8"));
            fos.write("ABCDEFG".getBytes("UTF-8"), 2, 5);
    
            // 4. 关闭资源
            fos.close();
        }
    }
    
  3. 字节流拷贝文件

    public class TestCopyFile {
        public static void main(String[] args) throws IOException {
            long begin = System.currentTimeMillis();
            // 1. 创建FileInputStream 对象
            FileInputStream fis = new FileInputStream("D:/test/a.txt");
    
            // 2. 创建FileOutputStream对象
            FileOutputStream fos = new FileOutputStream("D:/test/b.txt");
    
            // 3. 准备缓冲数组
            byte[] buf = new byte[1024 * 8];
            int length = -1;
    
            // 4. 读取数据,写入数据
            while ((length = fis.read(buf)) != -1) {
                fos.write(buf, 0, length);
            }
    
            // 5. 关闭资源,先开后关,后开先关
            fos.close();
            fis.close();
            long end = System.currentTimeMillis();
            System.out.println("time: " + (end - begin));
        }
    }
    

1.3.2 字符流操作


字符流适合处理文本文件,常见的字符流类包括ReaderWriter。例如,通过FileReader读取文本文件,通过BufferedWriter写入文本文件,可以有效地提高IO效率。

字符流操作限制

  1. 操作对应的文件有且只能是记事本可以打开的可视化文本文件。
  2. 要求操作过程中,文件对应的编码集和当前程序对应编码集一致。
  1. 文件操作字符输入流
    public class TestFileReader {
        public static void main(String[] args) throws IOException {
            // 1. 创建文件字符流对象
            Reader reader = new FileReader("D:/test/a.txt");
    
            // 2. 读取数据
            char[] buf = new char[1024 * 8];
            int length = -1;
            while ((length = reader.read(buf)) != -1) {
                System.out.println(new String(buf, 0, length));
            }
    
            // 3. 关闭资源
            reader.close();
        }
    }
    
  2. 文件操作字符输出流
    public class TestFileWriter {
        public static void main(String[] args) throws IOException {
            // 1. 创建文件字符输出流 第二个参数为append,true表示在文件中追加内容,false不追加,直接覆盖
            FileWriter fileWriter = new FileWriter("D:/test/a.txt", true);
    
            // 2. 写入数据
            fileWriter.write("== 张三真好");
    
            // 3. 关闭资源
            fileWriter.close();
        }
    }
    
  3. 字符流拷贝文件
    public class TestCopyFileByString {
        public static void main(String[] args) throws IOException {
            long begin = System.currentTimeMillis();
            // 1. 创建文件字符输入流
            FileReader fr = new FileReader("D:/test/a.txt");
            // 2. 创建文件字符输出流
            FileWriter fw = new FileWriter("D:/test/c.txt");
    
            // 3. 拷贝数据
            char[] buf = new char[1024 * 8];
            int length = -1;
            while ((length = fr.read(buf)) != -1) {
                fw.write(buf, 0, length);
            }
    
            // 4. 关闭资源
            fw.close();
            fr.close();
            long end = System.currentTimeMillis();
            System.out.println("Time : " + (end - begin) + "ms");
        }
    }
    

1.3.3 缓冲流


为了提高IO效率,Java提供了缓冲流,如BufferedReaderBufferedWriter。它们可以减少实际IO操作次数,从而提高读写效率。

  1. 字节缓冲流控制输入输出

    public class TestBufferCharStream {
        public static void main(String[] args) throws IOException {
            bufferWrite();
            bufferRead();
        }
    
        public static void bufferWrite() throws IOException {
            long begin = System.currentTimeMillis();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/test/a.txt"));
    
            String str = "如何学好Java\n";
    
            int num = 1000000;
            while (num > 0) {
                bos.write(str.getBytes());
                num--;
            }
    
            bos.close();
            long end = System.currentTimeMillis();
            // 118ms
            System.out.println(end - begin + "ms");
        }
    
        public static void bufferRead() throws IOException {
            long begin = System.currentTimeMillis();
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/test/a.txt"));
    
            byte[] buf = new byte[1024 * 8];
            int length = -1;
            while ((length = bis.read(buf)) != -1) {
                // System.out.println(new String(buf, 0, length));
            }
    
            bis.close();
    
            long end = System.currentTimeMillis();
            // 9ms
            System.out.println((end - begin) + "ms");
        }
    }
    
  2. 字符缓冲流控制输入输出

    public class TestBufferStringStream {
        public static void main(String[] args) throws IOException {
            // bufferWrite();
            bufferRead();
        }
    
        public static void bufferWrite() throws IOException {
            long begin = System.currentTimeMillis();
            BufferedWriter bos = new BufferedWriter(new FileWriter("D:/test/a.txt"));
    
            String str = "如何学好Java\n";
    
            int num = 1000000;
            while (num > 0) {
                bos.write(str);
                num--;
            }
    
            bos.close();
            long end = System.currentTimeMillis();
            // 71ms
            System.out.println(end - begin + "ms");
        }
    
        public static void bufferRead() throws IOException {
            long begin = System.currentTimeMillis();
            BufferedReader bis = new BufferedReader(new FileReader("D:/test/a.txt"));
    
            char[] buf = new char[1024 * 8];
            int length = -1;
            while ((length = bis.read(buf)) != -1) {
                // System.out.println(new String(buf, 0, length));
            }
    
            bis.close();
    
            long end = System.currentTimeMillis();
            // 55ms
            System.out.println((end - begin) + "ms");
        }
    }
    

2. Lambda表达式

在JDK8之后,Lambda表达式成为了Java的一个重要特性,它可以让我们以更简洁的方式实现函数式编程。Lambda表达式的语法形式是 (参数列表) -> 表达式或代码块。结合Lambda表达式,我们可以以更紧凑的代码来完成各种操作。

2.1 Lambda 表达式使用条件


  1. 存在接口
  2. 接口中有且只有一个未实现的方法,该接口可以认为是[函数式接口]。在源码中存在使用注解 @FunctionalInterface来约束当前接口
  3. Lambda 表达式用于方法中,要求当前方法的参数是接口,需要为接口的实现类对象。

2.2 Lambda 表达式的分类


  1. 无参无返回值
    /*
     * @FunctionalInterface 函数式接口注解,要求当前接口中有且只有一个未实现方法
     */
    @FunctionalInterface
    interface A {
        void test();
    }
    
    public class TestNoArgsVoid {
        public static void main(String[] args) {
            testLambda(() -> {
                System.out.println("无参无返回值Lambda表达式");
            });
            // 当Lambda表达式有且只有一行,可以省略大括号
            testLambda(() -> System.out.println("当Lambda表达式有且只有一行,推荐这样写"));
        }
    
        public static void testLambda(A a) {
            a.test();
        }
    }
    
  2. 有参无返回值
    @FunctionalInterface
    interface Consumer<T> {
        // 接口数据方法 需要的类型是泛型
        void accept(T t);
    }
    
    public class TestAllArgsVoid {
    
        public static void main(String[] args) {
            testLambda("让我看到你的眼睛!!!",
                    // 脑补数据类型 t ===> String 类型 t会成为当前Lambda表达式对应代码块中的局部变量参数
                    (str) -> System.out.println(str));
    
            ArrayList<String> list = new ArrayList<>();
            list.add("雪碧");
            list.add("芬达");
            list.add("可乐");
            list.add("王老吉");
            testLambda(list, (scopeList) -> {
                for (String str : scopeList) {
                    System.out.println(str);
                }
            });
    
            testLambda(10, (i) -> System.out.println("low : " + i));
        }
    
        /**
         * 当前方法带有自定义泛型,泛型对应的具体数据类型,通过第一个参数约束
         *
         * @param <T>      自定义泛型
         * @param t        用于约束当前泛型对应具体数据类型的参数
         * @param consumer 消费处理数据的接口
         */
        public static <T> void testLambda(T t, Consumer<T> consumer) {
            consumer.accept(t);
        }
    }
    
  3. 无参有返回值
    interface Supplier<T> {
        T get();
    }
    
    public class TestNoArgs {
        public static void main(String[] args) {
            String str = "张三去上网";
    
            // 方法中使用的Lambda表达式是可以在当前大括号范围以内使用对应的局部变量
            String reverseStr = testLambda(str, () -> new StringBuilder(str).reverse().toString());
            System.out.println(reverseStr);
    
            int[] arr = {2, 3, 4, 12, 13, 56, 71, 1};
            int maxValue = testLambda2(arr, () -> {
                int max = arr[0];
                for (int i = 1; i < arr.length - 1; i++) {
                    if (arr[i-1] < arr[i]) {
                        max = arr[i];
                    }
                }
                return max;
            });
            System.out.println(maxValue);
        }
    
        public static <T> T testLambda(T t, Supplier<T> supplier) {
            return supplier.get();
        }
    
        public static int testLambda2(int[] arr, Supplier<Integer> supplier) {
            return supplier.get();
        }
    }
    
  4. 有参有返回值
    interface Function<T, R> {
        R apply(T t);
    }
    
    public class TestAllArgs {
    
        public static void main(String[] args) {
            Student[] students = new Student[10];
            for (int i = 0; i < students.length; i++) {
                int id = i + 1;
                String name = "荀彧" + (i + 1);
                int age = (int) (Math.random() * 17);
                char gender = '男';
                students[i] = new Student(id, name, age, gender);
            }
    
            Arrays.sort(students, (stu1, stu2) -> stu1.getAge() - stu2.getAge());
    
            for (Student student : students) {
                System.out.println(student.toString());
            }
    
            System.out.println();
            // 字符串转Student对象
            String str = "11,张三,99,X";
            Student transformStu = transform(str, Student.class, (info) -> {
                String[] split = info.split(",");
                int id = Integer.parseInt(split[0]);
                String name = split[1];
                int age = Integer.parseInt(split[2]);
                char gender = split[3].charAt(0);
                return new Student(id, name, age, gender);
            });
            System.out.println(transformStu.toString());
        }
    
        public static <T, R> R transform(T t, Class<R> cls, Function<T, R> fun) {
            return fun.apply(t);
        }
    
    }
    
    class Student {
        int id;
        String name;
        int age;
        char gender;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public char getGender() {
            return gender;
        }
    
        public void setGender(char gender) {
            this.gender = gender;
        }
    
        public Student(int id, String name, int age, char gender) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    '}';
        }
    }
    

2.3 Lambda 表达式在 IO 流操作中的应用


让我们看看如何将Lambda表达式与IO流操作相结合,提升代码的可读性和简洁性。

  • 文件读取操作
    传统的文件读取方式可能需
    要一些繁琐的代码,如文件的打开、关闭等。然而,结合Lambda表达式,我们可以通过Files类中的lines()方法,更加轻松地读取文件内容。

    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.stream.Stream;
    
    public class FileReadWithLambda {
        public static void main(String[] args) {
            String filePath = "example.txt";
            try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
                lines.forEach(line -> System.out.println(line));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 文件写入操作
    同样地,Lambda表达式也可以在文件写入操作中大显身手。通过Files类中的write()方法,我们可以更加简洁地将内容写入文件。

    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.List;
    
    public class FileWriteWithLambda {
        public static void main(String[] args) {
            String filePath = "output.txt";
            List<String> content = List.of("Hello", "Lambda", "IO");
            try {
                Files.write(Paths.get(filePath), content);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

2.4 常见的 IO 流和 Lambda 表达式使用场景


  • 字符流读取文本文件:使用Files.lines()结合Lambda表达式,轻松地读取文本文件的每一行内容。

  • 字节流复制二进制文件:通过Files.copy()方法,将一个二进制文件复制到另一个位置。结合Lambda表达式,可以在复制的同时进行一些处理。

  • 基于Lambda的过滤和转换:在读取文件时,结合Lambda表达式可以轻松实现过滤、转换等操作,如过滤掉某些行或对每行进行处理。

  • 使用Lambda表达式处理异常:在IO操作中,异常处理是必不可少的。Lambda表达式可以在代码块中直接处理异常,使代码更加紧凑。

3. 流式操作

3.1 流操作的概念


Stream 中文成为“流”,通过将集合转换为这么一种叫做“流”的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作。

3.2 流操作的分类


在这里插入图片描述

3.3 常用流操作的API


  • 中间操作:
    • filter():对元素进行过滤
    • map():元素映射
    • sorted():对元素排序
    • distinct():去除重复的元素
  • 最终操作:
    • forEach():遍历每个元素
    • findFirst():找到第一个符合要求的元素
    • reduce():把 Stream 元素组合起来。例如,字符串拼接,数值的sum、min、max、average 都是特殊的 reduce
    • collect():返回一个新的数据结构,基于 Collectors 有丰富的处理方法
    • min():找到最小值
    • max():找到最大值
  • 中间操作:中间操作包括去重、过滤、映射等操作,值得说明的是,如果没有为流定义终端操作,为了避免无所谓的计算, 中间操作也不会执行
  • 终端操作:终端产生最终的执行结果,并中断式编程的衔接链,因此结束操作是最后一个操作

3.4 案例


public class Client {
    public static void main(String[] args) {
        List<DemoVo> list = initList();
        testFilter(list); // [{"key":"a","value":"str-a"}]
        listToMap(list); // {"a":{"key":"a","value":"str-a"},"b":{"key":"b","value":"str-b"},"c":{"key":"c","value":"str-c"}}
        testSorted(list); // [{"key":"a","value":"str-a"},{"key":"b","value":"str-b"},{"key":"c","value":"str-c"}]

        // 添加一条重复数据
        DemoVo demo4 = new DemoVo("c", "str-c");
        list.add(demo4);
        testDistinct(list); // [{"key":"a","value":"str-a"},{"key":"b","value":"str-b"},{"key":"c","value":"str-c"},{"key":"c","value":"str-c"}]
        convertToList(list); // ["str-a","str-b","str-c","str-c"]
    }

    private static List<DemoVo> initList() {
        List<DemoVo> list = new ArrayList<>();
        DemoVo demoVo1 = new DemoVo("a", "str-a");
        DemoVo demoVo2 = new DemoVo("b", "str-b");
        DemoVo demoVo3 = new DemoVo("c", "str-c");
        list.add(demoVo1);
        list.add(demoVo2);
        list.add(demoVo3);
        return list;
    }

    // filter过滤
    private static void testFilter(List<DemoVo> list) {
        List<DemoVo> listNew = list.stream().filter(item -> item.getKey().equals("a")).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(listNew));
    }

    // Map映射
    private static void listToMap(List<DemoVo> list) {
        Map<String, DemoVo> demoMap1 = list.stream().collect(Collectors.toMap(DemoVo::getKey, Function.identity()));
        // 当出现同名key时,用后者替换前者,toMap跟进源码可以看到使用了binaryOperator类作为参数,BinaryOperator接收两个同样类型的实参,返回和参数同样类型的结果类型
        Map<String, DemoVo> demoMap2 = list.stream().collect(Collectors.toMap(DemoVo::getKey, Function.identity(), (key1, key2) -> key2));
        System.out.println(JSON.toJSONString(demoMap1));
    }

    // sorted排序
    private static void testSorted(List<DemoVo> list) {
        // 自然排序,先对key进行排序,再对value进行排序
        List<DemoVo> collect = list.stream().sorted(Comparator.comparing(DemoVo::getKey).thenComparing(DemoVo::getValue)).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect));
        // 先对value排序,再对key排序
        collect = list.stream().sorted(Comparator.comparing(DemoVo::getValue).thenComparing(DemoVo::getKey)).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect));
    }


    // distinct 去重
    private static void testDistinct(List<DemoVo> list) {
        List<DemoVo> collect = list.stream().distinct().collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect));
    }


    // List转List 只取value
    private static void convertToList(List<DemoVo> list) {
        List<String> collect = list.stream().map(DemoVo::getValue).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect));
    }
}

class DemoVo {
    String key;
    String value;

    public DemoVo(String key, String value) {
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "DemoVo{" +
                "key='" + key + '\'' +
                ", value='" + value + '\'' +
                '}';
    }
}

4. 结语


通过本文,我们深入了解了Java中IO流操作的基础知识,并且展示了如何巧妙地将Lambda表达式应用于各种IO操作中,最后通过流式操作的讲解也让我们学会了如何在业务中引用流式操作。这种组合不仅使代码更加清晰、简洁,还能提升代码的可读性和可维护性。在今后的编程实践中,将这些技巧运用到自己的项目中,定能事半功倍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/859781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虹科新品 | 振动监测:提升风能行业效率与安全!

一、 CTC概览 服务于工业振动分析市场ISO 9001认证设计和测试以满足工业环境的实际需求无条件终身保修兼容所有主要数据采集器、分析仪和在线系统美国制造 二、风能行业&#xff1a;为什么要进行监测&#xff1f; 在风能行业&#xff0c;振动监测是一项至关重要的节约成本和安…

详解低代码和无代码的区别

低代码是近几年被炒的很热的一个概念&#xff0c;与之同样热议的还有无代码。那么针对这两个概念&#xff0c;背后的价值、面向的人群、发展的趋势是什么&#xff1f; 一、低代码 vs 无代码 低代码是什么&#xff1f; 低代码&#xff08;Low-Code&#xff09;这一概念是2014年一…

js 额外知识

加油&#xff0c;嘎嘎嘎 &#x1f923; &#x1f495;&#x1f495;&#x1f495; 文章目录 一、 with二、 eval 函数三、严格模式三、严格模式的限制 一、 with with语句 扩展一个语句的作用域链。 会形成一个自己的作用域不建议使用with语句&#xff0c;因为它可能是混淆错误…

Centos7.9_解决每次重启机器配置的java环境变量都需要重新source /etc/profile才生效的问题---Linux工作笔记060

这种情况需要把环境变量,java的环境变量在/root/.bashrc文件中也放一份,注意这个文件是隐藏的,默认是,需要进行ls -a才能显示. #jdk export JAVA_HOME/lib/jvm export JRE_HOME${JAVA_HOME}/jre export CLASSPATH.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH${JAVA_HOME}/b…

STM32F105RCT6 -- ST-Link ITM Trace printf 打印日志

1. STM32 可以配置UASRT&#xff0c;使用串口来打印日志&#xff0c;还有另外一种方式&#xff0c;使用ITM 调试功能来打印日志&#xff0c; 主要使用到的三个函数 core_cm3.h 1.1 发送函数 static __INLINE uint32_t ITM_SendChar(uint32_t ch)&#xff0c;相当于串口的发送函…

锚框【目标检测】

生成多个锚框 假设输入图像高为h,宽为w,我们以图像每个像素为中心生成不同形状的锚框,缩放比 s∈(0,1],宽高比为r>0。那么锚框的宽度和高度分别为和。当中心位置给定时, 已知宽和高的锚框是确定的。缩放比为锚框高与图像高的比值,然后得到一个正方形锚框面积。 ​​…

pytest接口自动化测试框架搭建的全过程

目录 一. 背景 二. 基础环境 三. 项目结构 四、框架解析 pytest是Python的一种单元测试框架,可用来组织用例执行,用例断言,下面这篇文章主要给大家介绍了关于pytest接口自动化测试框架搭建的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下 一. 背景 Pyte…

sql高频面试题-连续完成两个指定动作的用户统计

用户行为分析 业务背景 某购物APP最近上线了一个新功能&#xff0c;用户签到后可以跳转到大转盘抽奖&#xff0c;抽奖获得的奖金可以抵消购物的费用&#xff0c;以此来培养用户使用app的习惯。 数据表介绍 现有一张用户行为表action_log&#xff0c;主要字段如下&#xff0c…

7天获英国名校邀请函|CSC青骨获批成功案例补记

Q老师要求2周内拿到邀请函且必须是世界排名前200名的高校。我们在第7天就获得了世界百强名校-英国兰卡斯特大学的邀请函&#xff0c;导师的研究方向完全契合&#xff0c;提前实现了Q老师的委托目标&#xff0c;使其顺利获批CSC青骨项目。特别提示&#xff1a;青骨项目国内派出院…

5. 服务发现

当主机较少时&#xff0c;在抓取配置中手动列出它们的IP地址和端口是常见的做法&#xff0c;但不适用于较大规模的集群。尤其不适用使用容器和基于云的实例的动态集群&#xff0c;这些实例经常会变化、创建或销毁的情况。 Prometheus通过使用服务发现解决了这个问题&#xff1…

测试人员该怎样写软件缺陷报告?

软件测试过程中&#xff0c;每个公司都制订了软件的缺陷处理流程&#xff0c;每个公司的软件缺陷处理流程不尽相同&#xff0c;但是它们遵循的最基本流程是一样的&#xff0c;都要经过提交、分配、确认、处理、复测、关闭等环节&#xff0c;如图1所示。 缺陷处理流程 关于图1所…

Linux:shell脚本:基础使用(3)

for循环语句 语句格式 for for变量 in 取值列表&#xff08;可以是变量或者自己定义&#xff09; do 循环内容 done 工作方式就是通过取值列表去判断循环的次数&#xff0c;每次循环的同时把列表一行的值赋予到for变量。取值方式如果是数字&#xff0c;那就通过数字去…

MySQL 索引 详解

一、索引概述 索引是帮助 MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上…

设计师常用的6款UI设计工具

在选择UI设计工具时&#xff0c;设计师需要关注UI设计工具的功能。市场上有很多设计UI的工具。既然UI设计工具这么多&#xff0c;设计师应该如何选择UI设计工具&#xff1f;本文盘点了6种流行的UI设计工具&#xff0c;快来看看。 1.即时设计 即时设计是一款免费的在线 UI 设计…

利用ChatGPT绘制思维导图——以新能源汽车竞品分析报告为例

随着人们对环境保护的日益关注和传统燃油汽车的限制&#xff0c;全球范围内对新能源汽车的需求不断增长。新能源汽车市场的激烈竞争使得了解各个竞品的特点和优劣成为关键。然而&#xff0c;针对这一领域的详尽竞品分析却常常需要大量时间和精力。 在此背景下&#xff0c;人工智…

行业追踪,2023-08-10

自动复盘 2023-08-10 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

maven Jar包反向install到本地仓库

maven Jar包反向install到本地仓库 需求实现 需求 项目打包时报错&#xff0c;缺少一个jar包。 但是在maven仓库都找不到此jar包&#xff0c;其他人提供了这个jar包。 需要把这个jar包install到本地仓库&#xff0c;使项目能正常打包运行。 实现 使用git bash命令执行以下脚…

qt5.15.2 使用mysql8.1

报错&#xff1a; QMYSQL driver not loaded 报错&#xff1a;无 QMYSQL 使用 QStringList drivers QSqlDatabase::drivers(); //获取现在可用的数据库驱动 foreach(QString driver, drivers) qDebug() << driver; “QSQLITE” “QMARIADB” “QMYSQL” “QMYSQL3” “…

UML-状态图

目录 状态图 状态图的图符 状态机 状态 ​转换 电话机状态图 活动图和状态图区别&#xff1a; 状态图 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为&#xff0c;显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态…

基于金融行业的软件测试分析

随着银行业务不断增加&#xff0c;业务模式不断复杂化&#xff0c;对我们的银行软件也要求越来越高&#xff0c;产出高质量的产品也非常重要&#xff0c;下面对银行软件测试进行分析总结。 银行软件集中度高&#xff0c;规模庞大&#xff0c;往往是以系统群的方式存在&#xff…