JAVA学习 第四部分

前言

java 语言的 安装、介绍;语法、流程控制、数组、javaBean 等知识,可以查询上上一个内容

Java学习 第一部分

java 语言的 String、StringBuilder、集合、对象和类 进阶、窗体 等知识,可以查阅上一个内容

Java学习 第二部分

java 语言的 api、时间类、递归异常、集合

Java学习 第三部分

Stream 流

Stream 不是数据结构,而是 对数据源(集合、数组、I/O等)进行高效、声明式处理的操作序列,类似流水线

%title插图%num

Stream 操作的三大步骤:数据源 → 中间操作(链式) → 终止操作

常用方法

创建 Stream

方法示例说明
Collection.stream()list.stream()最常用,从集合获取
Arrays.stream()Arrays.stream(array)从数组
Stream.of()Stream.of("a","b","c")直接列举元素
IntStream.range()IntStream.range(1, 100)生成整数范围(无装箱)
Stream.iterate()Stream.iterate(0, n->n+2).limit(10)生成无限流,需要限制
Stream.generate()Stream.generate(Math::random).limit(5)生成无限流

中间操作(惰性,返回新 Stream)

常用组合:filter → map → sorted → limitfilter → flatMap → distinct → collect

方法用途示例
filter过滤元素.filter(x -> x > 10)
map转换元素类型或值.map(String::length)
flatMap将每个元素转为流并扁平化(合并).flatMap(list -> list.stream())
distinct去重(依赖 equals).distinct()
sorted排序.sorted() / .sorted(Comparator)
limit截取前 n 个.limit(5)
skip跳过前 n 个.skip(10)
peek调试查看每个元素(不修改).peek(System.out::println)
takeWhile (Java 9+)取开头满足条件的元素.takeWhile(x -> x < 50)
dropWhile (Java 9+)删除开头满足条件的元素.dropWhile(x -> x < 10)

静态方法

无需主动实例化,直接可以调用的静态工厂方法,它们一般属于构造流的工具方法,用于创建流

方法用途示例
concat合并参数1和参数2两个流为1个流(静态方法)Stream.concat(Stream a, Stream b)

Stream.concat(a,b) 创建的流会“接管”原流的数据源,一旦新流被终端操作触发,streamA 和 streamB 都会被消耗关闭,不能再单独操作

终止操作(触发执行,关闭流)

对于 Stream 实例,只要方法返回的不是某种流类型(例如普通对象、基本类型、void),它就是终端操作

方法返回说明
forEachvoid遍历每个元素
collectR(集合/自定义)将结果收集到容器,最常用(搭配 Collectors
reduceOptional / T聚合:求和、乘积、拼接等
countlong元素个数
anyMatchboolean是否存在任一元素匹配
allMatchboolean是否全部匹配
noneMatchboolean是否全不匹配
findFirstOptional找到第一个元素
findAnyOptional找到任意一个(并行流更快)
max / minOptional按比较器求最大值/最小值
toArrayObject[] 或指定类型数组转为数组
操作说明

集合获取 Stream 流 操作

使用 Collection 接口中的默认方法(单列集合内置)

Java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class StreamTest2 {
    static void main() {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        // ArrayList集合 获取 steam 流
        list.stream().forEach(i -> System.out.println(i));

        HashSet<String> list1 = new HashSet<>();
        list1.add("张三");
        list1.add("李四");
        list1.add("王五");
        // HashSet集合 获取 steam 流
        list.stream().forEach(i -> System.out.println(i));

        HashMap<String, Integer> list2 = new HashMap<>();
        list2.put("张三", 100);
        list2.put("李四", 100);
        list2.put("王五", 80);
        // HashMap是双列集合,推荐 entrySet 转为单列后 获取 steam流
        Set<Map.Entry<String, Integer>> ent = list2.entrySet();
        ent.stream().forEach(i -> System.out.println(i.getKey() + ":" + i.getValue()));
    }
}

效果展示

%title插图%num

数组获取 Stream流 操作

通过 Arrays.stream() 静态方法将数组转换成 stream 流

Java
import java.util.*;

public class StreamTest2 {
    static void main() {
        int[] list = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Arrays.stream(list).forEach(i -> System.out.println(i));
    }
}

效果展示

%title插图%num

零散数据获取 Steam流 操作

通过 Stream.of() 传入数据转换成 stream

Java
import java.util.*;
import java.util.stream.Stream;

public class StreamTest2 {
    static void main() {
        Stream<Integer> stream = Stream.of(4, 2, 1, 4, 5, 2);
        stream.forEach(System.out::println);
        
        Stream<String> sreeam2 = Stream.of("张三", "李四", "王五");
        sreeam2.forEach(System.out::println);
    }
}

效果展示

%title插图%num

当触发终止操作后流将关闭,无法再次执行中间方法

另外,一旦 Stream.concat 创建的新流被关闭,底层的 stream1 和 stream2 就会被关闭,进入 “已操作” 状态,不能再被复用。
因此,建议 一旦流被拼接,只使用 Stream.concat 拼接后的新流。

Java
import java.util.*;
import java.util.stream.Stream;

public class StreamTest2 {
    static void main() {
        Stream<Integer> s1 = Stream.of(4, 2, 1, 4, 5, 2);
        Stream<Integer> s2 = Stream.of(3, 1, 3, 14, 5, 3);
        // 合并 s1 和 s2 流
        Stream<Integer> s3 = Stream.concat(s1, s2);
        s3.forEach(System.out::println);
        // 报错:提示流已关闭
        s3.distinct().forEach(System.out::println);
        // 无法再次调用 s1,因为 s1 已经被消费过了
        // s1.forEach(i -> System.out.println(s));
    }
}

效果展示

%title插图%num

错误提示:stream has already been operated upon or closed

Collect 终止收集

通过 collect 方法,传入 Collectors 类,将 stream 流的数据收集并导入到 List 或者 Map 或者 Set 集合中

转 List
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamTest2 {
    static void main() {
        Stream<Integer> s1 = Stream.of(4, 2, 1, 4, 5, 2);
        List<Integer> collect = s1.limit(4).skip(1).collect(Collectors.toList());
        System.out.println(collect);
    }
}

效果展示

%title插图%num

Collectors.toMap(new Function,new Function) 接收键和值,并得到 map 集合数据

Java
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 StreamTest3 {
    static void main() {
        ArrayList<String> list = new ArrayList<String>();
        list.add("张三,22");
        list.add("李四,24");
        list.add("王五,18");
        list.add("老六,24");
        list.add("头七,22");
        list.add("刘八,13");

        Map<String, Integer> collect = list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return Integer.parseInt(s.split(",")[1]) > 18;
            }
        }).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(collect);
    }
}

效果展示

%title插图%num
File 类

Java 中的 File 类是 java.io 包的一部分,用于表示文件和目录路径名的抽象表示形式。

File类 不是用来读写文件内容的(那要使用 InputStream/OutputStream 等流),而是主要用于文件和目录的创建、删除、重命名、获取属性等元操作。

常用方法

文件/目录基本判断

方法说明
boolean exists()文件或目录是否存在
boolean isFile()是否为普通文件
boolean isDirectory()是否为目录
boolean canRead()是否可读
boolean canWrite()是否可写
boolean canExecute()是否可执行
boolean isHidden()是否为隐藏文件(依赖于操作系统)

获取信息

方法说明
String getName()返回文件或目录名,不包含路径
String getPath()返回构造时传入的路径字符串
String getAbsolutePath()返回绝对路径字符串
String getParent()返回父目录路径,可能为 null
long length()文件大小(字节),目录时返回值不确定
long lastModified()最后修改时间的毫秒值

操作文件/目录

方法说明
boolean createNewFile()当且仅当文件不存在时创建一个新的空文件,返回是否成功
boolean mkdir()创建单级目录
boolean mkdirs()创建多级目录(包括所有不存在的父目录)
boolean delete()删除文件或空目录。非空目录需递归删除
void deleteOnExit()在 JVM 退出时删除文件或目录(常用于临时文件)
boolean renameTo(File dest)重命名文件/目录,可能移动文件(取决于操作系统)

目录遍历

方法说明
String[] list()返回目录下所有文件和目录的名称数组,若为文件或无权限返回 null
String[] list(FilenameFilter filter)带文件名过滤器的名称列表
File[] listFiles()返回 File 对象数组
File[] listFiles(FileFilter filter)使用 FileFilter 过滤的 File 数组
File[] listFiles(FilenameFilter filter)使用 FilenameFilter 过滤的 File 数组

路径比较与转换

方法说明
boolean equals(Object obj)比较是否指向同一抽象路径(系统依赖)
int compareTo(File another)按字典顺序比较路径
URI toURI()将文件路径转换为 file: URI
Path toPath()(JDK 7+)转换为 java.nio.file.Path
基本操作

多种 Flie 类关联路径的操作(不使用 Path 类情况)

Java
import java.io.File;
import java.io.IOException;

public class FileTest {
    static void main() throws IOException {
      // 方式 A:直接给完整路径
      File f1 = new File("E:\\smm\\code\\javaWord\\test\\1.txt");

      // 方式 B:父路径 + 子路径(推荐,自动处理分隔符)
      File parent = new File("E:\\smm\\code\\javaWord");
      File f2 = new File(parent, "test\\1.txt");

      // 方式 C:字符串父路径 + 子路径
      File f3 = new File("E:\\smm\\code\\javaWord", "test\\1.txt");
    }
}

效果展示

%title插图%num

关联路径对应文件

通过 File 类可以创建文件夹、文件,检查文件信息

Java
import java.io.File;
import java.io.IOException;

public class FileTest {
    // 存在异常可能 需要抛出异常
    static void main() throws IOException {
        File dir = new File("E:\\smm\\code\\javaWord\\test");
        File file = new File("E:\\smm\\code\\javaWord\\test\\1.txt");
        // 创建目录,若路径节点均存在则返回 false
        if (dir.mkdirs()) {
            System.out.println("目录不存在,已创建。");
        }
        // 在指定位置创建文件,若原本存在则不处理并返回 false
        if (file.createNewFile()) {
            System.out.println("文件不存在,已创建。");
        }
        // 检查状态
        System.out.println("是否为文件: " + file.isFile());
        System.out.println("大小: " + file.length() + " bytes");
    }
}

效果展示

%title插图%num

通过执行代码后,得到空白文件

%title插图%num

通过 new File("").getAbsolutePath() 获取当前项目的绝对路径,如果不指定路径直接创建文件,默认也是当前项目下创建

绝对路径:从盘符开始往下到具体位置文件或文件夹,相对路径:相对于当前项目

Java
import java.io.File;
import java.io.IOException;

public class FileTest {
    static void main() throws IOException {
        File basedir = new File(new File("").getAbsolutePath());
        System.out.println(basedir);
        File text = new File("1.txt");
        System.out.println(text.getAbsolutePath());
    }
}

效果展示

%title插图%num

获取更多文件数据信息,例如最后更新时间、是否为目录、是否隐藏

Java
package cn.smmcat.test02;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTest {
    static void main() throws IOException {
        File basedir = new File(new File("").getAbsolutePath());
        System.out.println(basedir.getAbsolutePath());
        File text = new File("1.txt");
        System.out.println(text.createNewFile()); // 目录是否存在
        System.out.println(text.getAbsolutePath()); // 获取此文件绝对路径
        System.out.println(text.isFile()); // 判断是否为文件
        System.out.println(text.isDirectory()); // 判断是否为目录
        System.out.println(text.isHidden()); // 文件是否隐藏
        System.out.println(text.length()); // 文件大小(文件夹无法正常显示)
        System.out.println(text.getName()); // 获取文件名
        // 最后修改时间 并搭配 SimpleDateFormat 进行格式化
        String lastUpTime = new SimpleDateFormat("yyyy年M月d日 HH:mm:ss")
        .format(new Date(text.lastModified()));
        System.out.println(lastUpTime);
    }
}

效果展示

%title插图%num

通过 File.delete() 可以删除文件或者文件夹,需要注意是:文件夹必须里面没有文件才可以删除,且不走回收站

Java
import java.io.File;
import java.io.IOException;

public class FileTest3 {
    static void main() throws IOException {
        File file = new File("/temp/2.txt");
        File dir  = new File("/temp");
        // 创建文件夹
        dir.mkdirs();
        // 创建文件
        file.createNewFile();
        // 当文件夹存在文件时,无法删除文件夹,返回 false
        System.out.println(dir.delete());
        // 删除文件,成功返回 true
        System.out.println(file.delete());
        // 当文件夹中不存在任何文件时候,就可以删除文件夹,返回 true
        System.out.println(dir.delete());
    }
}

效果展示

%title插图%num