(超级详细)JAVA之Stream流分析-------持续更新喔!!!

news2025/1/15 6:43:57

学习目标:

  • 掌握 Java Stream流的相关api
  • 掌握 Java Stream流的基本实现
  • 掌握 java Stream流的使用场景
  • 代码已经整理上传到了gitee中,有需要的小伙伴可以取查看一下源码点个小心心喔

大家也可以帮我提交一点案例喔!!!!!
大家一起交流学习!
https://gitee.com/Aoyuan-210902/JAVAStreamDemo.git


点个赞嘛!!!!!!!!!!!!!!!!!!!!!!!!!
在这里插入图片描述

JAVA Stream流

概述

Java Stream API 是 Java 8 中引入的一个功能强大的新库,它提供了一种高效且声明式的处理数据集合的方法。通过使用 Streams,开发者可以写出简洁且易于理解的代码,用于对数据执行复杂的查询和聚合操作。

什么是Stream流,Stream流的特点是什么?

  • 含义
    在 Java 中,Stream 是对集合(Collection)对象功能的一个补充,它支持顺序和并行的聚集操作。Streams 不存储数据,它们只在需要时从源(如集合或数组)中获取数据。

  • 主要特点
    声明式:相比于传统的迭代方式,stream 提供了一种声明式的方法来表达数据处理任务。
    可组合:stream 操作可以链接起来,形成一个大的流水线,这样可以表达复杂的数据处理策略(比如筛选,排序等)。
    并行能力:Streams 可以透明地并行处理,利用多核架构而无需编写特定的多线程代码。

常见操作

Stream 操作分为中间操作和终端操作两种:

中间操作:如 filter、map、sorted 等,它们返回一个新的 Stream,可以连接多个中间操作。
终端操作:如 forEach、collect、reduce 等,它们输出结果或者产生副作用(例如输出到屏幕),并且关闭 Stream。

一些Stream的特性

  • 函数式编程: 通过Stream流可以代替复繁琐难懂的for循环等代码,对数据进行操作。
  • Stream流不会直接得出结果,而是在调用终端操作的时候,才会运行中间操作。

Optional类

在Java中,Optional是一个容器类,它可以包含也可以不包含非空值。Optional类主要用于防止NullPointerException异常的发生,它提供了一种更优雅的方法来处理可能为null的对象。使用Optional可以显式地要求调用者处理空值情况。

Optional提供了多种方法来检查、获取和转换包含的值:

isPresent():检查Optional是否有值。
get():获取Optional的值,如果Optional为空,则抛出NoSuchElementException。
orElse():如果Optional有值则返回该值,否则返回传递给orElse的参数。
ifPresent():如果值存在,执行给定的操作。 map()和flatMap():对Optional的值应用函数。
Optional常用于新的Java API中,如Stream的终端操作,返回一个Optional类型的结果

Stream流的操作

distinct

package distinctStream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class DistincrtStrream {
    public static void main(String[] args) {
        //distint主要是去除掉集合中重复的代码
        List<Integer> list = Arrays.asList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6);
        List<Integer> collect = list.stream().distinct().collect(Collectors.toList());
        collect.forEach(System.out::println);
    }
}

运行实例

在这里插入图片描述

filter筛选操作

示例1

package filterStream;

import java.util.ArrayList;
import java.util.List;

public class FilterDemo01 {
    //找到集合中元素大于5的数
    public static void main(String[] args) {
        List<Integer> demo01 = new ArrayList<>();
        demo01.add(1);
        demo01.add(5);
        demo01.add(7);
        demo01.add(8);
        demo01.add(9);
        System.out.println("没有进行筛选之前的数据");

        demo01.forEach(System.out::println);
        System.out.println("筛选之后的数据");
        demo01.stream().filter(x -> x > 5).forEach(System.out::println);
    }
}

在这里插入图片描述
示例2

package filterStream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class FilterDemo02 {
    public String username;
    public String password;

    public FilterDemo02() {
    }

    public FilterDemo02(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "FilterDemo02{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public static void main(String[] args) {
        FilterDemo02 user01 = new FilterDemo02("aoyuan","123");
        FilterDemo02 user02 = new FilterDemo02("yuan","234");
        FilterDemo02 user03 = new FilterDemo02("ao","345");

        List<FilterDemo02> list  = new ArrayList<>();
        list.add(user01);
        list.add(user02);
        list.add(user03);
        //查找username = aoyuan的
        List<FilterDemo02> collect = list.stream().filter(n -> n.getUsername().equals("aoyuan")).collect(Collectors.toList());
        collect.forEach(System.out::println);
                System.out.println("------------------------------------------------------------------------------");

         //查找username =ao
         List<FilterDemo02> collect01 = list.stream().filter(n -> n.getUsername().equals("ao")).collect(Collectors.toList());
         collect01.forEach(System.out::println);
        System.out.println("------------------------------------------------------------------------------");
         List<FilterDemo02> collect02 = list.stream().filter(n -> n.getPassword() != "123").collect(Collectors.toList());
         collect02.forEach(System.out::println);
    }
}

运行示例

在这里插入图片描述

limit截取操作

示例1

package limitStream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class LimitDemo01 {
    public static void main(String[] args) {
        //limit是截取第n个元素
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Stream<Integer> limit1 = list.stream().limit(2);
        Stream<Integer> limit2 = list.stream().limit(6);
        System.out.println("----------------截取第2个---------------");
        limit1.forEach(System.out::println);
        System.out.println("-----------------截取6个---------------------");
        limit2.forEach(System.out::println);
    }
}

运行示例

在这里插入图片描述
示例2

package limitStream;

import java.util.stream.Stream;

public class LimitDemo02 {
    public static void main(String[] args) {
        //interage迭代器会一直进行下去,所以由inerate创建的流是无限流,需要limit方法截断
        Stream<Integer> demo03 = Stream.iterate(0, n -> n+2).limit(6);
        demo03.forEach(System.out::println);
        System.out.println("limit起到了什么作用呢?起到了截断的作用");
        Stream<Integer>  demo04 = Stream.iterate(0,n -> n+2).limit(7);
        demo04.forEach(System.out::println);
        System.out.println("generate方法");
        //generate方法
        Stream<Double> generateStream = Stream.generate(Math::random).limit(5);
        generateStream.forEach(System.out::println);
    }
}

运行示例

在这里插入图片描述

map映射操作

User类

package mapStream;

public class User {
    private String username;
    private Integer id;
    private String address;

    public User() {
    }

    public User(String username, Integer id, String address) {
        this.username = username;
        this.id = id;
        this.address = address;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getId() {
        return id;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", id=" + id +
                ", address='" + address + '\'' +
                '}';
    }
}

userdao类

package mapStream;

public class UserDao {
    private String username;
    private String address;

    public UserDao() {
    }

    public UserDao(String username, String address) {
        this.username = username;
        this.address = address;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "UserDao{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

示例1

package mapStream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

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

        List<User>  userList= new ArrayList<>();
        userList.add(new User("aoyuan",1,"baotou"));
        userList.add(new User("aoyuan01",2,"bao"));
        userList.add(new User("aoyuan02",3,"tou"));
        //拿到用户集合中的数据并将用户名转化为大写
        List<String> collect = userList.stream().map(x -> x.getUsername().toUpperCase()).collect(Collectors.toList());
        collect.forEach(System.out::println);
       //拿到user集合选择数据存储在新的userDao集合中
        List<UserDao> collect1 = userList.stream().map(x -> {
            UserDao userDao = new UserDao();
            userDao.setUsername(x.getUsername());
            userDao.setAddress(x.getAddress());
            return userDao;
        }).collect(Collectors.toList());
        collect1.forEach(System.out::println);
    }
}

运行示例

在这里插入图片描述
示例2

package mapStream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

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

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> collect = list.stream().map(x -> x + 3).collect(Collectors.toList());
        collect.forEach(System.out::println);
    }



}

运行示例

在这里插入图片描述

取max和min的相关操作

示例1

package maxStream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Demo {
    public static void main(String[] args) {
        //自定义排序
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        //从大到小排序
        Optional<Integer> max = list.stream().max((o1, o2) -> o1 - o2);
        System.out.println("最大值为+"+ max.get());

    }
}

运行示例

在这里插入图片描述

示例2

package maxStream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

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

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        Optional<Integer> max = list.stream().max(Integer::compareTo);
        System.out.println("最大值为+:"+ max);



    }
}

运行示例

在这里插入图片描述

示例3

package maxStream;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

public class Demo02 {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("aoyuan", "aoyuanao", "aoyuanaoyuan");
        Optional<String> max = strings.stream().max(Comparator.comparing(String::length));
        System.out.println("最长的字符串为" + max);
    }



}

运行示例

在这里插入图片描述
示例3

package minStream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class StreamMinExample01 {
    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        int getAge() {
            return age;
        }

        @Override
        public String toString() {
            return name + ": " + age;
        }
    }

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Alice", 22),
                new Person("Bob", 20),
                new Person("Charlie", 30),
                new Person("David", 25)
        );


        Optional<Person> youngest = people.stream().min((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));


        youngest.ifPresent(person -> System.out.println("The youngest person is " + person));
    }
}

运行示例

在这里插入图片描述

示例4

package minStream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class StreamMinExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, -1, 6, 7);

        // Using Stream.min() to find the minimum value in the list
        Optional<Integer> minNumber = numbers.stream()
                .min(Integer::compare);

        // Checking and displaying the minimum number
        if (minNumber.isPresent()) {
            System.out.println("The minimum number is " + minNumber.get());
        } else {
            System.out.println("List is empty.");
        }
    }
}

运行示例

在这里插入图片描述

reduce归约

package reduce;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ReduceStreamDemo {

    public static void main(String[] args) {
        List<Integer> demo = new ArrayList<>();
        demo.add(2);
        demo.add(4);
        demo.add(1);
        demo.add(5);
//x+y的和
        Optional<Integer> reduce = demo.stream().reduce((x, y) -> x + y);
        System.out.println(reduce.get());
        //求最大值
        Optional<Integer> reduce1 = demo.stream().reduce((x, y) -> x > y ? x : y);
        System.out.println(reduce1.get());

    }
}

运行示例

在这里插入图片描述

排序

示例1

package sortStream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSortExample {
    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        String getName() {
            return name;
        }

        @Override
        public String toString() {
            return name + ": " + age;
        }
    }

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Alice", 22),
                new Person("Charlie", 30),
                new Person("David", 25),
                new Person("Bob", 20)
        );


        List<Person> sortedPeople = people.stream()
                .sorted((p1, p2) -> p1.getName().compareTo(p2.getName()))
                .collect(Collectors.toList());

                sortedPeople.forEach(System.out::println);



    }
}

运行示例

在这里插入图片描述

示例2

package sortStream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSortExample02 {
    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        int getAge() {
            return age;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return name + ": " + age;
        }
    }

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Alice", 22),
                new Person("Charlie", 30),
                new Person("David", 25),
                new Person("Bob", 20)
        );

        // Sorting people by age using Stream
        List<Person> sortedByAge = people.stream()
                //自然排序
                .sorted((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()))
                .collect(Collectors.toList());

        // Displaying the sorted list
        sortedByAge.forEach(System.out::println);
        System.out.println("------------------自定义排序--------------");
        //先根据年龄再根据姓名排序
        List<Person> collect = people.stream().sorted((p1, p2) -> {
            if (p1.getAge() == p2.getAge()) {
                return p1.getName().compareTo(p2.getName());
            } else {
                return p2.getAge() - p1.getAge();
            }

        }).collect(Collectors.toList());
        collect.forEach(System.out::println);
    }
}

运行示例

在这里插入图片描述

总结

作用场景

Java Stream API 是用于处理集合和数据库的理想选择,它能够执行如排序、过滤或映射数据等聚合操作。Stream 支持并行处理,使得它能够有效地处理大型数据集。此外,Stream 在处理数据序列时能增强代码的可读性和减少样板代码,使编程更加表达和简洁。它在 Java 中的函数式编程模式中尤为有价值,帮助以声明方式操作集合。

优势和不足

优势
  1. 提高代码可读性和简洁性:通过流式表达式,可以用更少的代码完成复杂的集合处理,使代码更易于理解和维护。
  2. 支持并行处理:Stream API 设计支持并行执行,可以很容易地对数据进行并行处理,提高处理效率,尤其适用于处理大数据量。
  3. 函数式编程:支持函数式编程风格,有助于减少副作用,使程序更加稳定。
不足
  1. 性能开销:相对于传统的 for-loop,Stream 操作可能引入更多的性能开销,尤其是在小数据量或高性能场景中。
  2. 学习曲线:对于初学者,Stream API 的一些操作和概念可能比较难以理解,需要一定的学习投入。
  3. 调试困难:由于 Stream 操作的链式结构,调试可能比较复杂,特别是在流水线操作中定位问题可能比较困难。

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

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

相关文章

java:观察者模式

java&#xff1a;观察者模式 1 前言 观察者模式&#xff0c;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;他定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所…

本地部署Docker容器可视化图形管理工具DockerUI并实现无公网IP远程访问——“cpolar内网穿透”

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

从0到1带你玩转pandas

学习 pandas 的过程可以分为几个阶段&#xff0c;每个阶段都围绕着不同的核心技能和概念。下面是一个为初学者设计的学习大纲&#xff1a; 一. 基础介绍 学习如何安装和设置 pandas 以及了解它的基本概念是开始使用 pandas 进行数据分析的第一步。下面我将详细介绍这些步骤&am…

overleaf如何使用中文(超简单)

LaTeX默认都是不支持中文的&#xff0c;有时候我们想输入中文。 1、编译器配置为XeLaTeX 菜单-编译器-XeLaTeX 2、代码开头添加宏包 \usepackage[UTF8]{ctex}

STM32 ADC转换器

一、ADC简介 ADC&#xff08;Analog-Digital Converter&#xff0c;模拟-数字转换器&#xff09;&#xff0c;可以将引脚上连续变化的模拟量转换为内存中存储的数字量&#xff0c;建立模拟电路到数字电路的桥梁 模拟量&#xff1a;时间和幅值均连续的信号&#xff0c;例如&…

YOLOv9训练结果分析->mAP、Precision、Recall、FPS、Confienc、混淆矩阵分析

简介 这篇博客&#xff0c;主要给大家讲解我们在训练yolov9时生成的结果文件中各个图片及其中指标的含义&#xff0c;帮助大家更深入的理解&#xff0c;以及我们在评估模型时和发表论文时主要关注的参数有那些。本文通过举例训练过程中的某一时间的结果来帮助大家理解&#xf…

Sigmoid激活函数

Sigmoid函数是一种常用的激活函数&#xff0c;其数学公式为&#xff1a; σ ( x ) 1 1 e − x \sigma(x) \frac{1}{1 e^{-x}} σ(x)1e−x1​ 其中&#xff0c; x x x 是函数的输入&#xff0c; σ ( x ) \sigma(x) σ(x) 是函数的输出。 sigmoid函数在神经网络中常被用于…

等待队列如何应用

等待队列 上一篇的程序写完出现了一个比较棘手的问题,运行应用程序就会发现,此时的read函数是非阻塞的,而实际使用场景往往需要我们在读取按键状态时阻塞,在用户按下按键之后read函数返回并得到按下按键的键值。阻塞用户空间的read当然可以在驱动层用一个死循环来实现,但…

【前端】vue的基础知识及开发指引

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Vue是什么二、学习 Vue.js 的基础知识三、熟悉 Vue.js 的生态系统四、掌握常用工具和库五、实践和项目开发六、 持续学习和跟进 前言 随着开发语言及人工智…

【office安装错误1402或1406】

office安装错误1402或1406 错误如图 解决方法 打开autoremove&#xff0c;点击扩展&#xff0c;输入1402&#xff0c;点击搜索 等待修复成功&#xff0c;再尝试安装office 软件每周六选择其他登录方式可以免费使用

深入探索GDB:Linux下强大的调试神器

目录 一、GDB简介&#xff1a;源码级调试的基石 二、GDB基础操作&#xff1a;从入门到熟练 启动与基本命令 三、GDB进阶功能&#xff1a;解锁更深层次的调试能力 1. 回溯追踪&#xff1a;洞察调用栈 2. 动态内存检测&#xff1a;揪出内存问题 3. 条件断点与观察点&#…

pyTorch框架部署实践

相关代码链接见文末 1.所需基本环境配置 首先&#xff0c;我们需要一个预先训练好的模型以及相应的配置。接下来&#xff0c;为了实际应用这个模型&#xff0c;我们必须搭建一个功能强大的服务器。这台服务器的核心任务是加载我们的模型&#xff0c;并能够接收用户上传的图片。…

关于Domain的查询命令

dig: 用来执行DNS查询&#xff0c;可以获取指定域名的所有类型的DNS记录。对网络管理员和开发人员尤其有用。 host: 一个简化版的DNS查询工具&#xff0c;适合快速查询域名的IP地址或某种类型的DNS记录。 nslookup: 另一个DNS查询工具&#xff0c;既支持交互模式也支持命令行模…

OFDM-OCDM雷达通信一体化信号模糊函数对比研究【附MATLAB代码】

文章来源&#xff1a;微信公众号&#xff1a;EW Frontier 1.引言 为提高频谱利用率并实现系统小型化、集成化,近年来雷达通信一体化系统成为重要研究方向。正交线性调频波分复用(OCDM)信号是利用菲涅尔变换形成的一组正交线性啁啾(chirp)信号,基于OCDM 的雷达通信一体化信号不…

架构师核心-云计算云上实战(云计算基础、云服务器ECS、云设施实战、云上高并发Web架构)

文章目录 云计算基础1. 概念1. 云平台优势2. 公有云3. 私有云4. IaaS、PaaS、SaaS 2. 云设施1. 概览2. 核心组件 云服务器ECS1. ECS介绍1. 简介2. 组件3. 概念4. 图解5. 规格6. 场景 2. ECS服务器开通1. 开通服务器2. 连接服务器 3. 云部署准备1. 1Panel介绍2. 安装1Panel3.安全…

<开源> 轮廓内缩外扩算法

轮廓内缩外扩算法 项目是论文A new offset algorithm for closed 2D lines with Islands的JAVA实现。 项目的GitHub地址&#xff1a;https://github.com/Lee-0o0/polygon-offset-algorithm。 参考博客 https://blog.csdn.net/qq_41261251/article/details/114462696

多目标应用:基于非支配排序粒子群优化算法NSPSO求解无人机三维路径规划(MATLAB代码)

一、无人机多目标优化模型 无人机三维路径规划是无人机在执行任务过程中的非常关键的环节&#xff0c;无人机三维路径规划的主要目的是在满足任务需求和自主飞行约束的基础上&#xff0c;计算出发点和目标点之间的最佳航路。 1.1路径成本 无人机三维路径规划的首要目标是寻找…

Java 【数据结构】 二叉树(Binary_Tree)【神装】

登神长阶 第五神装 二叉树 Binary-Tree 目录 &#x1f3b7;一.树形结构 &#x1fa97;1.概念 &#x1f3b8;2.具体应用 &#x1f3b9; 二.二叉树&#xff08;Binary Tree&#xff09; &#x1f3ba;1.概念 &#x1f3bb;2.表现形式 &#x1fa95;3.特殊类型 &#x1f941…

Windows下使用SDKMAN对JDK(Java)进行多版本管理

Windows下使用SDKMAN对JDK&#xff08;Java&#xff09;进行多版本管理 1.背景2.基于msys2工具2.1. msys2简介2.2. 安装与配置2.2. Windows环境变量配置参考2.3 结果确认 3. 基于WSL 1.背景 前端有nvm,python有miniconda,miniforge等&#xff0c;java呢&#xff1f;java在Linu…

PCB走线宽度、PCB走线宽度计算、PCB走线宽度和电流

目录 一、什么是PCB走线宽度&#xff1f; 二、什么是走线&#xff1f; 三、哪些因素对走线宽度至关重要&#xff1f; 1、信号走线 2、电源走线 3、直线宽度和信号反射 四、怎么计算PCB走线宽度&#xff1f; 1、使用PCB走线宽度计算器 2、使用方程式 五、怎么计算PCB 走…