javaIO-实习期笔记

阶段:第一阶段

计划时间:1.12-1.14
计划内容:

Java IO的相关知识点学习,Java 8流操作、 Lambda表达式、Optional类使用

  • IO
    • File
    • OutputStream
    • InputStream
    • Writer
    • Reader
    • Serializable
  • Lambda表达式
  • Optional类

Java IO

​ 整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable.

流式部分

  1. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
  2. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
  3. Reader(文件格式操作):抽象类,基于字符的输入操作。
  4. Writer(文件格式操作):抽象类,基于字符的输出操作。

非流式部分

  1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
  2. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object。它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

本质:数据传输,将数据传输特性抽象为各种类,方便更直观的进行数据操作

作用:为数据源和目的第建立一个传输通道

InputStream

方法
读方法
// 读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
public abstract int read() throws IOException;
// 将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
public int read(byte b[]) throws IOException {
   return read(b, 0, b.length);
}
// 将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。
public int read(byte b[], int off, int len) throws IOException {
        ...
}
其他方法
  1. long skip(long n):在输入流中跳过n个字节,并返回实际跳过的字节数。
  2. int available() :返回在不发生阻塞的情况下,可读取的字节数。
  3. oid close() :关闭输入流,释放和这个流相关的系统资源。
  4. voidmark(int readlimit) :在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。
  5. void reset() :返回到上一个标记。
  6. booleanmarkSupported() :测试当前流是否支持mark和reset方法。

OuntputStream

写方法
// 将指定的字节写入此输出流。必须实现该方法
public abstract void write(int b) throws IOException;
// 将 b.length字节从指定的字节数组写入此输出流。
public void write(byte b[]) throws IOException
// 从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
public void write(byte b[], int off, int len) throws IOException
其他方式
  1. void flush() :刷新输出流,强制缓冲区中的输出字节被写出。
  2. void close() :关闭输出流,释放和这个流相关的系统资源。

Reader

读方法
// 尝试将字符读入指定的字符缓冲区。
public int read(java.nio.CharBuffer target) throws IOException
// 读一个字符
public int read() throws IOException
// 将字符读入数组。
public int read(char cbuf[]) throws IOException
// 将字符读入数组的一部分。抽象方法由子类实现   
abstract public int read(char cbuf[], int off, int len) throws IOException;

其他方法

  1. ready()
  2. reset()
  3. skip(long n)
  4. mrk()
  5. close()

Writer

写方法
public void write(int c) throws IOException
public void write(char cbuf[]) throws IOException
abstract public void write(char cbuf[], int off, int len) throws IOException;
public void write(String str) throws IOException
public void write(String str, int off, int len) throws IOException

字节流和字符流的区别

  1. 字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。
  2. 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  3. 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

File

public class File implements Serializable, Comparable<File>

File类是Object的直接子类,同时它继承了Comparable接口可以进行数组的排序。File类的操作包括文件的创建、删除、重命名、得到路径、创建时间等,通过对象的思想来操作文件和文件夹。

构造函数

提供了三个构造函数,以便不同的参数形式灵活地接收文件和目录名信息。

// 已经标准化的路径名称来构造
private File(String pathname, int prefixLength) {
    this.path = pathname;
    this.prefixLength = prefixLength;
}

// 从父抽象路径名和子路径名字符串创建新的 File实例。
private File(String child, File parent) {
    assert parent.path != null;
    assert (!parent.path.equals(""));
    this.path = fs.resolve(parent.path, child);
    this.prefixLength = parent.prefixLength;
}

// 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String pathname) {
    if (pathname == null) {
        throw new NullPointerException();
    }
    this.path = fs.normalize(pathname);
    this.prefixLength = fs.prefixLength(this.path);
}
// 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

public File(URI uri) {
		// 整个流程就是,检查合法性,并初始化为标准化的路径
        // Check our many preconditions
        if (!uri.isAbsolute())
            throw new IllegalArgumentException("URI is not absolute");
        if (uri.isOpaque())
            throw new IllegalArgumentException("URI is not hierarchical");
        String scheme = uri.getScheme();
        if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
            throw new IllegalArgumentException("URI scheme is not \"file\"");
        if (uri.getAuthority() != null)
            throw new IllegalArgumentException("URI has an authority component");
        if (uri.getFragment() != null)
            throw new IllegalArgumentException("URI has a fragment component");
        if (uri.getQuery() != null)
            throw new IllegalArgumentException("URI has a query component");
        String p = uri.getPath();
        if (p.equals(""))
            throw new IllegalArgumentException("URI path component is empty");

        // Okay, now initialize
        p = fs.fromURIPath(p);
        if (File.separatorChar != '/')
            p = p.replace('/', File.separatorChar);
        this.path = fs.normalize(p);
        this.prefixLength = fs.prefixLength(this.path);
    }
方法

一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。

  1. public boolean exists( ) 判断文件或目录是否存在
  2. public boolean isFile( ) 判断是文件还是目录
  3. public boolean isDirectory( ) 判断是文件还是目录
  4. public String getName( ) 返回文件名或目录名
  5. public String getPath( ) 返回文件或目录的路径。
  6. public long length( ) 获取文件的长度
  7. public String[ ] list ( ) 将目录中所有文件名保存在字符串数组中返回。

File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:

  1. public boolean renameTo( File newFile ); 重命名文件
  2. public void delete( ); 删除文件
  3. public boolean mkdir( ); 创建目录

RandomAccessFile

public class RandomAccessFile implements DataOutput, DataInput, Closeable

该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。该对象特点:

  1. 该对象只能操作文件,所以构造函数接收两种类型的参数:

    a.字符串文件路径;

    b.File对象。

  2. 该对象既可以对文件读写,在进行对象实例化时可指定操作模式(r,rw)

    public RandomAccessFile(String name, String mode)
        throws FileNotFoundException
    
  3. 该对象在实例化时,如文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。可以用于多线程下载或多个线程同时写数据到文件。

System对IO的支持

针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:

  • System.in(标准输入),通常代表键盘输入。

  • System.out(标准输出):通常写往显示器。

  • System.err(标准错误输出):通常写往显示器。

标准I/O

​ Java程序可通过命令行参数与外界进行简短的信息交换,同时,也规定了与标准输入、输出设备,如键盘、显示器进行信息交换的方式。而通过文件可以与外界进行任意数据形式的信息交换。

在Java语言中使用字节流和字符流的步骤基本相同,以输入流为例,首先创建一个与数据源相关的流对象,然后利用流对象的方法从流输入数据,最后执行close()方法关闭流。

Java 8 Stream

用函数式编程方式在集合类上进行复杂操作的工具。简而言之,是以内部迭代的方式处理集合数据的操作,内部迭代可以将更多的控制权交给集合类。Stream 和 Iterator 的功能类似,只是 Iterator 是以外部迭代的形式处理集合数据的操作。

Java8以前,对集合的操作需要写出处理的过程。如筛选,需要一 一遍历集合中的每个元素,再把每个元素逐一判断是否满足条件,最后将满足条件的元素保存返回。而Stream 对集合筛选的操作提供了一种更为便捷的操作,只需将实现函数接口的筛选条件作为参数传递进来,Stream会自行操作并将合适的元素同样以stream 的方式返回,最后进行接收即可。

  • 中间操作:中间操作的结果是刻画了一个Stream,没有产生一个新集合,这种操作也叫做惰性求值方法。
  • 终止操作:最终会从Stream中得到值

该部分具体在demo代码中查看,大部分是方法的示例

创建

  1. .stream()

    /**
     * 流的特性:支持并行流与顺序流
     * 并行流:多个线程同时运行
     * 顺序流:使用主线程,单线程
    */
    // 自定义一个学生类集合(ArrayList)
    List<Student> students = StudentData.getStudents();
    // 第一种:返回一个顺序流
    Stream<Student> stream = students.stream();
    // 第二种:返回一个并行流
    Stream<Student> stream1 = students.parallelStream();
    
  2. Arrays.stream

    int []arr = {1, 34, 54, 6, 8};
    IntStream intStream = Arrays.stream(arr);
    
  3. stream.of()

    // 基础数据类型
    Stream<String> stringStream = Stream.of("1","3","6","9","3");
    // 自定义类型
    Stream<Student> studentStream = Stream.of(new Student(1,"cherry",23,99.5),new Student(1,"1",1, 1.1);
    

使用

一般和Lambda表达式结合使用,更好的完成常见集合操作

  • filter-过滤

    // 过滤出年纪大于22的学生
    list.stream().filter(item -> item.getAge() > 22)
    
  • limit-截断流

    // 筛选出前三条
    list.stream().limit(3)
    
  • skip-跳过元素

  • distinct-跳过重复元素

  • map-映射

    将一种类型的值映射为另一种类型的值,可以将 Stream 中的每个值都映射为一个新的值,最终转换为一个新的 Stream 流。

    Stream<Student> stream1 = students.stream();
    //把所有的年龄取出来变为一个新的stream
    Stream<Integer> stream2 = stream1.map(Student::getAge);
    //过滤出大于23的名字
    stream2.filter(age -> age > 23).forEach(System.out::println);
    

终止

  • allMatch–检查是否匹配所有元素

  • anyMatch–检查是否至少匹配一个元素

  • noneMatch–检查是否没有匹配所有元素

  • findFirst–返回第一个元素

  • findAny–返回当前流中的任意元素

  • count–返回流中元素的总个数

  • max–返回流中最大值

  • min–返回流中最小值

    //判断所有的学生年龄是否都大于20岁
    boolean allMatch = list.stream().allMatch(student -> student .getAge() > 20);
    //判断是否存在学生的年龄大于20岁
    boolean anyMatch = list.stream().anyMatch(student -> student .getAge() > 20);
    //判断是否不存在学生叫小白
    boolean noneMatch = list.stream().noneMatch(student -> "小白".equals(student .getName()));
    //查找第一个学生
    Optional<Student> first = list.stream().findFirst() ;
    //查找当前流中的元素
    Optional<Student> any = list.stream().findAny() ;
    //查找所有的学生数量
    long count = list.stream().count();
    

Lambda表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

lambda表达式拆分为两部分

左侧:lambda 表达式的参数列表

右侧:lambda 表达式中所需要执行的功能,即lambda体

  1. 不需要参数,返回值为 5

    () -> 5

  2. 接收一个参数(数字类型),返回其2倍的值

    x -> 2 * x

  3. 接受2个参数(数字),并返回他们的差值

    (x, y) -> x – y

  4. 接收2个int型整数,返回他们的和

    (int x, int y) -> x + y

  5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)

    (String s) -> System.out.print(s)

  6. 支持引用写法

    对象::实例方法名 System.out::println 等价于 (x) -> System.out.println(x)

    类::静态方法名 Integer::compare 等价于 (x,y) -> Integer.compare(x,y)

    类::实例方法名 String::equals 等价于 bp = (x,y) -> x.equals(y);

    构造器引用 Supplier sup2 = String::new; 等价于 Supplier sup = () -> new String();

注意点

  • lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
  • 在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

Optional

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常

类方法

  • static Optional empty()

    返回空的Optional实例

  • boolean equals(Object obj)

    判断其他对象是否等于 Optional。

  • Optional filter(Predicate<? super predicate)

    如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。

  • Optional flatMap(Function<? super T,Optional> mapper)

    如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional

  • T get()

    ** T get()**如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException

  • int hashCode()

    返回存在值的哈希码,如果值不存在 返回 0。

  • void ifPresent(Consumer<? super T> consumer)

    如果值存在则使用该值调用 consumer , 否则不做任何事情。

  • boolean isPresent()

    如果值存在则方法会返回true,否则返回 false。

  • Optional map(Function<? super T,? extends U> mapper)

    如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。

  • static Optional of(T value)

    返回一个指定非null的Optional

  • static Optional ofNullable(T value)

    如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。

  • T orElse(T other)

    如果存在该值,返回值, 否则返回 other。

  • T orElseGet(Supplier<? extends T> other)

    如果存在该值,返回值, 否则返回 otherr,并返回 other 调用的结果。

  • T orElseThrow(Supplier<? extends X> exceptionSupplier)

    如果存在该值,返回包含的值,否则抛出由Supplier继承的异常

  • String toString()

    返回一个Optional的非空字符串,用来调试

注意点:

1、orElse和orElseGet的区别

// 对比二者源码
public T orElse(T other) {
    return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
  • 无论optional是否有值,orElse都会被执行
  • 只有optional为空时,orElseGet才会被执行

在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响

2、of和ofNullable的使用

从以下源码来分析

// of直接返回一个新的Optional,所以如果为空时抛出异常
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
// ofNullable在传入空值时调用empty()
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
// empty会创建一个空的Option实例
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

使用示例

// Optional.ofNullable - 允许传递为 null 参数,在不确定对象是不是一定非空用ofNullable
Optional<Integer> a = Optional.ofNullable(value1);

// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException,只有在确认对象一定不为空时使用
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));

3、转换值

如使用map()

***map()* 对值应用(调用)作为参数的*函数*,然后将返回的值包装在 *Optional* 中。**这就使对返回值进行链试调用的操作成为可能

User user = new User("anna@gmail.com", "1234");
    String email = Optional.ofNullable(user)
      .map(u -> u.getEmail()).orElse("default@gmail.com");

4、map和faltmap区别

map是把结果自动封装成一个Optional,但是flatmap需要你自己去封装。

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { // 参数中需要Optonal
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        // 不封装Optional,不要自行调用of()/ofNullable去封装Optional后传入
        return Objects.requireNonNull(mapper.apply(value));
    }
}
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        // 封装Optional
        return Optional.ofNullable(mapper.apply(value));
    }
}

5、链式方法

为了更充分的使用 Optional,你可以链接组合其大部分方法,因为它们都返回相同类似的对象。

// 示例
String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值