IO流&lambda总结

发布时间 2023-12-28 20:53:55作者: ZWJAS

总结

  • 读取文件,统计文件中偶数的个数

    public class HomeWorkDemo1 {
        /**
         * 读取文件,统计文件中偶数的个数
         */
        public static int getEvenCount(String file) {
            int evenCount = 0; // 保存偶数个数
            // 参数的合法判断
            if (file == null || file.isEmpty())
                throw new IllegalArgumentException("非法参数");
            File f = new File(file);
            if (f.isDirectory())
                throw new IllegalArgumentException("必须是文件");
            try (
                    FileInputStream fis = new FileInputStream(f); // 使用自动关流
            ) {
                byte[] bytes = new byte[1024];
                int count; // 保存读取的字节个数
                StringBuilder sb = new StringBuilder();
                while ((count = fis.read(bytes)) != -1) {
                    // 创建字符串
                    String s = new String(bytes, 0, count);
                    // 将s追加到sb里面
                    sb.append(s);
                }
                // 将sb转换为String
                String str = sb.toString();
                // 分割字符串
                String[] split = str.split(" ");
                // 遍历数组
                for (String num : split) {
                    // 将num由String转换int
                    int i = Integer.parseInt(num.trim());
                    // 判断i是否为偶数
                    if (i % 2 == 0) evenCount++;
                }
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // 返回结果
            return evenCount;
        }
    
        public static void writeCount(String file, String content, boolean append) {
            // 省略参数的判断
            try (
                    FileOutputStream fos = new FileOutputStream(file, append);
            ) {
                fos.write(content.getBytes()); // 将数据写流
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        public static void main(String[] args) {
            int evenCount = getEvenCount("C:\\Users\\ITsource\\Desktop\\新建文本文档.txt");
            System.out.println(evenCount);
            writeCount("1.txt","偶数:" + evenCount + "个",false);
        }
    
    

字符流

字符流:以字符为单位来操作文件的流
Reader:所有输入字符流的父类,输入字符流

  • FileReader:文件字符输入流,用来按字符为单位读取文件

注意:read():读取一个字符,返回的是字符ASCII码

  • Writer:所有输出字符流的父类,输出字符流

文件字符输入流:FileReader

public class IODemo1 {
    public static void main(String[] args) throws IOException {
        // 创建FileReader对象:文件字符输入流
        FileReader fr = new FileReader("e:/1.txt");
        // 读取文件
//        int data = fr.read();// 一次读取一个字符,返回的是字符ASCII码
//        System.out.println(data);
//        int data2 = fr.read();// 一次读取一个字符,返回的是字符ASCII码
//        System.out.println(data2);
        // 返回-1表示文件读完了
//        int data;
//        while((data = fr.read()) != -1) {
//            System.out.print((char)data);
//        }
        char[] chars = new char[3];
        int count; // 读取字符个数
//        while((count = fr.read(chars)) != -1) {
//            // 创建字符创
//            String s = new String(chars, 0, count);
//            System.out.print(s);
//        }

        while ((count = fr.read(chars,1,2)) != -1) {
            String s = new String(chars, 1, count);
            System.out.println(s);
        }

    }
}
  • 文件字符输入流的案例
/**
 * 文件字符输入流的案例
 */
public class IODemo2 {
    public static void main(String[] args) throws IOException {
        try(
            // 创建文件字符输入流
            FileReader fr = new FileReader("C:\\Users\\ITsource\\Desktop\\新建文本文档.txt");
        ) {
            char[] chars = new char[1024];
            int count;
            while ((count = fr.read(chars)) != -1) {
                String s = new String(chars, 0, count);
                System.out.println(s);
            }
        }
    }
}

文件字符输出流:FileWriter(Writer的子类)

FileWriter:文件字符输出流,不会自动刷新

/**
 * 讲解字符输出流
 *  FileWriter:文件字符输出流,不会自动刷新
 *
 */
public class IODemo3 {
    public static void main(String[] args) throws IOException {
        // 创建文件字符输出流对象
        FileWriter fw = new FileWriter("e:/4.txt");// 覆盖流
//        fw.write(34567); // 向流写入
//        fw.write(23456);
//        fw.write(65222);
//        fw.write(21345);
//        fw.flush(); // 刷新流
//        fw.write("dsgfdsfgd水电费三分大萨达撒325432sds".toCharArray(),2,4);
        fw.write("的双方各得十分43543543",2,5);
        fw.flush();
    }
}
  • 写入对象案例
public class StudentTest {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        ts.add(new Student("s0001", "张三", "男", 23));
        ts.add(new Student("s0001", "张三", "男", 23));
        ts.add(new Student("s0002", "李四", "男", 21));
        ts.add(new Student("s0003", "张小三", "女", 25));
        // 创建一个字符输出流
        try (
                FileWriter fw = new FileWriter("2.txt");
        ) {
            for (Student t : ts) {
                fw.write(t.toString());
                fw.write("\r\n");
                fw.flush();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
public class Student implements Comparable<Student>{
    private String id;
    private String name;
    private String gender;
    private Integer age; // 使用包装类

    public Student() {
    }

    public Student(String id, String name, String gender, Integer age) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id) && Objects.equals(name, student.name) && Objects.equals(gender, student.gender) && Objects.equals(age, student.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, gender, age);
    }

    @Override
    public int compareTo(Student o) {
        if(o.age != this.age) {
            return o.age - this.age;
        }else if(!o.name.equals(this.name)) {
            return o.name.hashCode()-this.name.hashCode();
        }
        return 0;
    }
}
  • 复制文本文件的案例
/**
 * 复制文本文件的案例
 */
public class CopyTxt {
    public static void main(String[] args) {
        File file = new File("C:\\Users\\ITsource\\Desktop\\ReviewDemo.java");
        try (
                FileReader fr = new FileReader(file);
                FileWriter fw = new FileWriter(file.getName());
        ) {
            char[] chars = new char[1024];
            int count;
            while((count = fr.read(chars)) != -1) {
                fw.write(chars,0,count);
                fw.flush();
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

转换流

将字节流转换字符流的一种流

  • InputStreamReader:字节输入转换流,将输入字节流转换为输入字符流

    • InputStreamReader(InputStream in):将传入的字节流转换字符流

    • utStreamReader(InputStream in, String charsetName):设置字符流的编码集

  • OutputStreamWriter:字节输出转换流,将字节输出流转换字符输出流

    • OutputStreamWriter(OutputStream out) -
    • OutputStreamWriter(OutputStream out, String charsetName)

    注意:转换流只能操作字节流,不能直接操作文件

public class IODemo4 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("1.txt");
        // 将字节流转换字符流
//        InputStreamReader isr = new InputStreamReader(fis);
//        int data;
//        while((data = isr.read()) != -1) {
//            System.out.print((char)data);
//        }

        new InputStreamReader(fis,"gbk"); // 将字节流转换字符流,并且设置字符流的编码集是gbk
    }
}
  • 使用缓冲流来复制文件
/**
 * 使用缓冲流来复制文件
 */
public class CopyDataOfBuffer {
    public static void main(String[] args) {
        try (
                FileInputStream fis = new FileInputStream("e:/2.webp");
                FileOutputStream fos = new FileOutputStream("e:/111.webp");
                // 使用缓冲流
                BufferedInputStream bis = new BufferedInputStream(fis);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
        ) {
            byte[] bytes = new byte[1024];
            int count;
            while((count = bis.read(bytes)) != -1) {
                bos.write(bytes,0,count);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

缓冲流

1、字节流和字符流操作的流程
1)、和文件产生连接
2)、开始操作
操作一次就要连接一次(连接的次数多操作性能就比较低)
为提高操作性能,用数组,减少连接次数

2、缓冲流:自带缓冲区的流,默认的缓冲区是8K,操作文件就可以减少连接次数,从而提高的性能
缓冲字节流
缓冲字节输入流:操作的对象是输入字节流
BufferedInputStream
缓冲字节输出流:

​ BufferedWriteStream

缓冲字符流:操作的对象是输入字符流
 		缓冲字符输入流:BufferedReader
		 缓冲字符输出流:BufferedWriter
public class IODemo5 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("e:/1.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("e:/333.txt"));
//        char[] chars = new char[1024];
//        int count;
//        while ((count = br.read(chars)) != -1) {
//            String s = new String(chars, 0,count);
//            System.out.print(s);
//        }
        String s = "";
        while ((s = br.readLine()) != null) { // readLine()返回null说明文件读完了
//            System.out.println(s);
            bw.write(s);
            bw.newLine(); // 换行
            bw.flush(); // 刷新流
        }



    }
}
  • 小结IO

    • 字节流:
      - InputStream
      FileInputStream
      - OutputStream
      FileOutputStream

    • 字符流:
      - Reader
      FileReader
      - Writer
      FileWriter

    • 转换流:
      InputStreamReader
      OutputStreamWriter

    • 缓冲流
      BufferedInputStream
      BufferedOutputStream
      BufferedReader
      BufferedWriter

补讲接口

1、接口中成员
常量
抽象方法:必须重写的方法
默认方法:可以重写也可以不重写的方法
default 返回值类型 方法签名 + 方法体
静态方法:不能重写的方法

public class InterfaceDemo {
}

interface  A {
    int NUM = 1; // 在接口所有的成员变量都常量
    void am(); // 抽象方法
    default  void dm() {

    } // 默认方法,是一个实例方法

    static void sm() {

    } // 静态方法


}

函数式接口

接口有且仅有1个抽象方法,与Object签名一样的抽象方法除外

见过的函数式接口
Runnable等

jdk8以后提供4大核心函数式接口
Consumer:消费型的接口,提供一个数据,把它消费掉(输出),做遍历操作

Supplier<T>:供给型的接口,创建数据,创建对象

Function<T,R>:函数型

Predicate<T>:断言型接口

接口在开发中做标准,需要子类去重写,利用多态,再去调方法
如果不用接口,那么我们写的业务必须是固定

public class InterfaceDemo2 {
    public static void main(String[] args) {

    }
}

@FunctionalInterface // 检查一个接口是否是函数式接口
interface  B {
    void am();
    String toString();
    default  void dm() {

    }
}

回顾匿名内部类

可以用创建接口和抽象类对象,不用自己去创建子类

/**
 * 回顾匿名内部类
 *  可以用创建接口和抽象类对象,不用自己去创建子类
 */
public class InnerDemo {
    public static void main(String[] args) {
        // 创建IDemo接口的对象
        IDemo iDemo = new IDemo() { // 创建接口对象
            @Override
            public int getSum(int n) {
                int sum = 0;
                for (int i = 1; i <= n; i++) {
                    sum += i;
                }
                return sum;
            }
        };
        int sum = iDemo.getSum(10);
        System.out.println(sum);
        // 匿名内部代码很多,需要简化一下,使用lambda表达式
        // 注意:不是所有的代码都能使用lambda,你的匿名内部类中是在创建一个函数式接口的对象,就可以简化
    }
}
public interface IDemo {
    int getSum(int n); // 求和的方法
}

Lambda表达式

简化使用匿名内部类创建函数式接口对象的代码
注意:函数式接口只有一个抽象方法
()-> {}
参数也是固定
从抽象方法的()开始简化,到这个方法的方法体,其他都不要了
()和方法体之间需要->连接

实例:

public interface IDemo3 {
    void sayHi();
}

public interface IDemo2 {
    int getMax(int a,int b);
}

public interface IDemo {
    int getSum(int n); // 求和的方法
}
  • 测试类
public class LambdaDemo {
    public static void main(String[] args) {
        IDemo iDemo = new IDemo() {
            @Override
            public int getSum(int n) {
                return 10 + n;
            }
        };
        System.out.println(iDemo.getSum(10));

        IDemo iDemo2 = (int n) ->{ // (int n):就是重写getSum()方法,方法体就是->后面
            return 10 + n;
        };
        System.out.println(iDemo2.getSum(10));

        // 创建IDemo2函数式接口的对象
        IDemo2 d2 = (int a,int b) -> {return a > b ? a : b;};

        // 创建IDemo3的函数式接口的对象
        IDemo3 d3 = () -> {
            System.out.println("hello");
        };

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        // 遍历集合
        list.forEach((Integer pp)->{
            System.out.println(pp);
        });

        // 简化lambda表达式
        // 方法名已经简化了,可以省略参数的数据类型
        // 如果参数的个数只有一个,可以省略()
        // ->后面的称为lambda体,如果lambda体只有一句语句,{}可以省略,如果{}里面有return,在省略{}时候一起省略
        IDemo id = a -> 10 + a;

        IDemo2 id2 = (a,b) -> a > b ? a : b;

        IDemo3 id3 = () -> System.out.println("hello");

        List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "xixixi");
        list1.forEach(a -> System.out.println(a));


    }
}