java8里如何使用流?《Java8 实战》读书笔记 第 5 章 使用流

目录

  • 第 5 章 使用流
    • 5.1 筛选和切片
      • 5.1.1 用谓词筛选(filter)
      • 5.1.2 筛选各异的元素(distinct)
      • 5.1.3 截短流(limit)
      • 5.1.4 跳过元素(skip)
    • 5.2 映射(map,flatMap)
      • 5.2.1 对流中每一个元素应用函数(map)
      • 5.2.2 流的扁平化(flatMap)
    • 5.3 查找和匹配
      • 5.3.1 检查谓词是否至少匹配一个元素(anyMatch)
      • 5.3.2 检查谓词是否匹配所有元素(allMatch、noneMatch)
      • 5.3.3 查找元素(findAny)
      • 5.3.4 查找第一个元素(findFirst)
    • 5.4 归约
      • 5.4.1 元素求和(reduce)
      • 5.4.2 最大值和最小值(reduce)
      • 5.4.3 统计个数(reduce、count)
    • 5.5 付诸实践
      • 代码清单5-1 找出2011年的所有交易并按交易额排序(从低到高)
      • 代码清单5-2 交易员都在哪些不同的城市工作过
      • 代码清单5-3 查找所有来自于剑桥的交易员,并按姓名排序
      • 代码清单5-4 返回所有交易员的姓名字符串,按字母顺序排序
      • 代码清单5-5 有没有交易员是在米兰工作的
      • 代码清单5-6 打印生活在剑桥的交易员的所有交易额
      • 代码清单5-7 所有交易中,最高的交易额是多少
      • 代码清单5-8 找到交易额最小的交易
    • 5.6 数值流
      • 引入背景:
      • 5.6.1 原始类型流特化(mapToInt、mapToDouble、mapToLong)
      • 5.6.2 数值范围(rangeClosed,range)
      • 5.6.3 数值流应用:勾股数
    • 5.7 构建流
      • 5.7.1 由值创建流(Stream.of)
      • 5.7.2 由数组创建流(Arrays.stream)
      • 5.7.3 由文件生成流(Files.lines)
      • 5.7.4 由函数生成流:创建无限流(Stream.iterate、Stream.generate)
      • 5.7.5 由集合创建流(list.stream())

第 5 章 使用流

5.1 筛选和切片

5.1.1 用谓词筛选(filter)

Streams接口支持filter方法。该操作会接受一个谓词作为参数,并返回一个包括所有符合谓词的元素的流。

Stream<T> filter(Predicate<? super T> predicate);
List<Dish> vegetarianMenu = menu.stream().filter(Dish::isVegetarian)    ←─方法引用检查菜肴是否适合素食者.collect(toList());

5.1.2 筛选各异的元素(distinct)

流还支持一个叫作distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流

List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

5.1.3 截短流(limit)

流支持limit(n)方法,该方法会返回一个不超过给定长度的流。

Stream<T> limit(long maxSize);
List<Dish> dishes = menu.stream().filter(d -> d.getCalories() > 300).limit(3).collect(toList());

5.1.4 跳过元素(skip)

流还支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流。

Stream<T> skip(long n);
List<Dish> dishes = menu.stream().filter(d -> d.getCalories() > 300).skip(2).collect(toList());

5.2 映射(map,flatMap)

一个非常常见的数据处理套路就是从某些对象中选择信息。比如在SQL里,你可以从表中选择一列。Stream API也通过map和flatMap方法提供了类似的工具。

5.2.1 对流中每一个元素应用函数(map)

流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。

<R> Stream<R> map(Function<? super T, ? extends R> mapper);
List<Integer> dishNameLengths = menu.stream().map(Dish::getName).map(String::length).collect(toList());

5.2.2 流的扁平化(flatMap)

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
给定单词列表["Hello","World"],你想要返回列表["H","e","l", "o","W","r","d"]List<String> uniqueCharacters =words.stream().map(w -> w.split(""))      ←─将每个单词转换为由其字母构成的数组.flatMap(Arrays::stream)    ←─将各个生成流扁平化为单个流.distinct().collect(Collectors.toList());

一言以蔽之,flatmap方法把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。

为巩固对于map和flatMap的理解,如下测试:

给定[1, 2, 3, 4, 5],应该返回[1, 4, 9, 16, 25]List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares =numbers.stream().map(n -> n * n).collect(toList());
例如,给定列表[1, 2, 3]和列表[3, 4],应该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs =numbers1.stream().flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})).collect(toList());
 如何扩展前一个例子,只返回总和能被3整除的数对呢?例如(2, 4)(3, 3)是可以的。List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs =numbers1.stream().flatMap(i ->numbers2.stream().filter(j -> (i + j) % 3 == 0).map(j -> new int[]{i, j})).collect(toList());

5.3 查找和匹配

5.3.1 检查谓词是否至少匹配一个元素(anyMatch)

anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词”。比如,你可以用它来看看菜单里面是否有素食可选择:

boolean anyMatch(Predicate<? super T> predicate);
if(menu.stream().anyMatch(Dish::isVegetarian)){System.out.println("The menu is (somewhat) vegetarian friendly!!");
}

5.3.2 检查谓词是否匹配所有元素(allMatch、noneMatch)

allMatch方法的工作原理和anyMatch类似,但它会看看流中的元素是否都能匹配给定的谓词。

boolean allMatch(Predicate<? super T> predicate);
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000);

和allMatch相对的是noneMatch。它可以确保流中没有任何元素与给定的谓词匹配。

boolean noneMatch(Predicate<? super T> predicate);
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() >= 1000);

anyMatch、allMatch和noneMatch这三个操作都用到了我们所谓的短路,这就是大家熟悉的Java中&&||运算符短路在流中的版本。

短路操作:
allMatch、anyMatch、noneMatch、findFirst、findAny、limit

5.3.3 查找元素(findAny)

findAny方法将返回当前流中的任意元素。

Optional<T> findAny();
Optional<Dish> dish =menu.stream().filter(Dish::isVegetarian).findAny();

5.3.4 查找第一个元素(findFirst)

Optional<T> findFirst();
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree =someNumbers.stream().map(x -> x * x).filter(x -> x % 3 == 0).findFirst(); // 9

为什么会同时有findFirst和findAny呢?
答案是并行。找到第一个元素在并行上限制更多。如果你不关心返回的元素是哪个,请使用findAny,因为它在使用并行流时限制较少。

5.4 归约

“计算菜单中的总卡路里”或“菜单中卡路里最高的菜是哪一个”。此类查询需要将流中所有元素反复结合起来,得到一个值,比如一个Integer。这样的查询可以被归类为归约操作(将流归约成一个值)。用函数式编程语言的术语来说,这称为折叠(fold),因为你可以将这个操作看成把一张长长的纸(你的流)反复折叠成一个小方块,而这就是折叠操作的结果。

5.4.1 元素求和(reduce)

有初始值

T reduce(T identity, BinaryOperator<T> accumulator);
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int sum = numbers.stream().reduce(0, Integer::sum);    ←─可以使用方法引用让这段代码更简洁

reduce操作对这种重复应用的模式做了抽象。
reduce接受两个参数:
一个初始值,这里是0;
一个BinaryOperator来将两个元素结合起来产生一个新值,这里我们用的是lambda (a, b) -> a +b,Lambda反复结合每个元素,直到流被归约成一个值。

无初始值(reduce)

Optional<T> reduce(BinaryOperator<T> accumulator);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

为什么它返回一个Optional呢?
考虑流中没有任何元素的情况。reduce操作无法返回其和,因为它没有初始值。这就是为什么结果被包裹在一个Optional对象里,以表明和可能不存在。

5.4.2 最大值和最小值(reduce)

用归约计算最大值和最小值:

Optional<Integer> max = numbers.stream().reduce(Integer::max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);
Optional<Integer> min = numbers.stream().reduce((x, y) -> x < y ? x : y);

5.4.3 统计个数(reduce、count)

int count = menu.stream().map(d -> 1).reduce(0, (a, b) -> a + b);
long count = menu.stream().count();

归约方法的优势与并行化
reduce的好处在于,这里的迭代被内部迭代抽象掉了,这让内部实现得以选择并行执行reduce操作。而外部迭代式求和例子要更新共享变量sum,这不是那么容易并行化的。如果你加入了同步,很可能会发现线程竞争抵消了并行本应带来的性能提升!这种计算的并行化需要另一种办法:将输入分块,分块求和,最后再合并起来

可变的累加器模式对于并行化来说是死路一条 !!!

流操作:无状态和有状态
诸如map或filter等操作会从输入流中获取每一个元素,并在输出流中得到0或1个结果。这些操作一般都是无状态的:它们没有内部状态。

但诸如reduce、sum、max等操作需要内部状态来累积结果。在上面的情况下,内部状态很小。在我们的例子里就是一个int或double。不管流中有多少元素要处理,内部状态都是有界的。相反,诸如sort或distinct等操作一开始都和filter和map差不多——都是接受一个流,再生成一个流(中间操作),但有一个关键的区别。从流中排序和删除重复项时都需要知道先前的历史。例如,排序要求所有元素都放入缓冲区后才能给输出流加入一个项目,这一操作的存储要求是无界的。要是流比较大或是无限的,就可能会有问题(把质数流倒序会做什么呢?它应当返回最大的质数,但数学告诉我们它不存在)。我们把这些操作叫作有状态操作。

5.5 付诸实践

代码清单5-1 找出2011年的所有交易并按交易额排序(从低到高)

代码清单5-1 找出2011年的所有交易并按交易额排序(从低到高)List<Transaction> tr2011 =transactions.stream().filter(transaction -> transaction.getYear() == 2011)    ←─给filter传递一个谓词来选择2011年的交易.sorted(comparing(Transaction::getValue))    ←─按照交易额进行排序.collect(toList());    ←─将生成的Stream中的所有元素收集到一个List

代码清单5-2 交易员都在哪些不同的城市工作过

代码清单5-2 交易员都在哪些不同的城市工作过List<String> cities =transactions.stream().map(transaction -> transaction.getTrader().getCity())    ←─提取与交易相关的每位交易员的所在城市.distinct()    ←─只选择互不相同的城市.collect(toList());Set<String> cities =transactions.stream().map(transaction -> transaction.getTrader().getCity()).collect(toSet());

代码清单5-3 查找所有来自于剑桥的交易员,并按姓名排序

代码清单5-3 查找所有来自于剑桥的交易员,并按姓名排序List<Trader> traders =transactions.stream().map(Transaction::getTrader)    ←─从交易中提取所有交易员.filter(trader -> trader.getCity().equals("Cambridge"))    ←─仅选择位于剑桥的交易员.distinct()    ←─确保没有任何重复.sorted(comparing(Trader::getName))    ←─对生成的交易员流按照姓名进行排序.collect(toList());

代码清单5-4 返回所有交易员的姓名字符串,按字母顺序排序

代码清单5-4 返回所有交易员的姓名字符串,按字母顺序排序
String traderStr =transactions.stream().map(transaction -> transaction.getTrader().getName())    ←─提取所有交易员姓名,生成一个Strings构成的Stream.distinct()    ←─只选择不相同的姓名.sorted()    ←─对姓名按字母顺序排序.reduce("", (n1, n2) -> n1 + n2);    ←─逐个拼接每个名字,得到一个将所有名字连接起来的String以上解决方案效率不高(所有字符串都被反复连接,每次迭代的时候都要建立一个新的String对象)。String traderStr =transactions.stream().map(transaction -> transaction.getTrader().getName()).distinct().sorted().collect(joining()); ←─使用joining(其内部会用到StringBuilder

代码清单5-5 有没有交易员是在米兰工作的

代码清单5-5 有没有交易员是在米兰工作的
boolean milanBased =transactions.stream().anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));    ←─把一个谓词传递给anyMatch,检查是否有交易员在米兰工作

代码清单5-6 打印生活在剑桥的交易员的所有交易额

代码清单5-6 打印生活在剑桥的交易员的所有交易额
transactions.stream().filter(t -> "Cambridge".equals(t.getTrader().getCity()))    ←─选择住在剑桥的交易员所进行的交易.map(Transaction::getValue)     ←─提取这些交易的交易额.forEach(System.out::println);    ←─打印每个值

代码清单5-7 所有交易中,最高的交易额是多少

代码清单5-7 所有交易中,最高的交易额是多少
Optional<Integer> highestValue =transactions.stream().map(Transaction::getValue)    ←─提取每项交易的交易额.reduce(Integer::max);    ←─计算生成的流中的最大值

代码清单5-8 找到交易额最小的交易

代码清单5-8 找到交易额最小的交易
Optional<Transaction> smallestTransaction =transactions.stream().reduce((t1, t2) -> t1.getValue() < t2.getValue() ? t1 : t2);    ←─通过反复比较每个交易的交易额,找出最小的交易Optional<Transaction> smallestTransaction =transactions.stream().min(comparing(Transaction::getValue));

5.6 数值流

引入背景:

nt calories = menu.stream().map(Dish::getCalories).reduce(0, Integer::sum);

这段代码的问题是,它有一个暗含的装箱成本。每个Integer都必须拆箱成一个原始类型,再进行求和

5.6.1 原始类型流特化(mapToInt、mapToDouble、mapToLong)

Java 8引入了三个原始类型特化流接口来解决这个问题:IntStream、DoubleStream和LongStream,分别将流中的元素特化为int、long和double,从而避免了暗含的装箱成本。这些特化的原因并不在于流的复杂性,而是装箱造成的复杂性——即类似int和Integer之间的效率差异。
1. 映射到数值流
将流转换为特化版本的常用方法是mapToInt、mapToDouble和mapToLong。

int calories = menu.stream()    ←─返回一个Stream<Dish>.mapToInt(Dish::getCalories)    ←─返回一个IntStream.sum();请注意,如果流是空的,sum默认返回0IntStream还支持其他的方便方法,如max、min、average等。

2. 转换回对象流
一旦有了数值流,你可能会想把它转换回非特化流

IntStream intStream = menu.stream().mapToInt(Dish::getCalories);    ←─将Stream 转换为数值流
Stream<Integer> stream = intStream.boxed();    ←─将数值流转换为Stream

3. 默认值OptionalInt
对于三种原始流特化,也分别有一个Optional原始类型特化版本:OptionalInt、OptionalDouble和OptionalLong。

OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();nt max = maxCalories.orElse(1);    ←─如果没有最大值的话,显式提供一个默认最大值

5.6.2 数值范围(rangeClosed,range)

IntStream evenNumbers = IntStream.rangeClosed(1, 100)    ←─表示范围[1, 100].filter(n -> n % 2 == 0);    ←─一个从1100的偶数流System.out.println(evenNumbers.count());    ←─从110050个偶数IntStream evenNumbers = IntStream.range(1, 100)       ←─表示范围[1, 100).filter(n -> n % 2 == 0); System.out.println(evenNumbers.count());    ←─从19949个偶数

5.6.3 数值流应用:勾股数

Stream<int[]> pythagoreanTriples =IntStream.rangeClosed(1, 100).boxed().flatMap(a -> IntStream.rangeClosed(a, 100).filter(b -> Math.sqrt(a*a + b*b) % 1 == 0).mapToObj(b ->new int[]{a, b, (int)Math.sqrt(a * a + b * b)}));Stream<double[]> pythagoreanTriples2 =IntStream.rangeClosed(1, 100).boxed().flatMap(a -> IntStream.rangeClosed(a, 100).mapToObj(b -> new double[]{a, b, Math.sqrt(a*a + b*b)})    ←─产生三元数.filter(t -> t[2] % 1 == 0));    ←─元组中的第三个元素必须是整数pythagoreanTriples.limit(5).forEach(t ->System.out.println(t[0] + ", " + t[1] + ", " + t[2]));

5.7 构建流

5.7.1 由值创建流(Stream.of)

Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);
Stream<String> emptyStream = Stream.empty();  ←─使用empty得到一个空流

5.7.2 由数组创建流(Arrays.stream)

int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();    ←─总和是4

5.7.3 由文件生成流(Files.lines)

long uniqueWords = 0;
try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {    ←─流会自动关闭uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))    ←─生成单词流.distinct()    ←─删除重复项.count();      ←─数一数有多少各不相同的单词
} catch (IOException e) {←─如果打开文件时出现异常则加以处理
}

5.7.4 由函数生成流:创建无限流(Stream.iterate、Stream.generate)

1. 迭代

iterate方法生成了一个所有正偶数的流
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(10);
stream.forEach(System.out::println);
斐波纳契元组序列
Stream<int[]> stream = Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}).limit(20);
stream.forEach(t -> System.out.println("(" + t[0] + "," + t[1] + ")"));

2. 生成

生成一个流,其中有五个01之间的随机双精度数
Stream<Double> stream = Stream.generate(Math::random).limit(5);
stream.forEach(System.out::println);
生成一个全是1的无限流
IntStream ones = IntStream.generate(() -> 1);

5.7.5 由集合创建流(list.stream())

list.stream()

-----------------------------------------------------------------------------读书笔记摘自 书名:Java 8实战 作者:[英] Raoul-Gabriel Urma [意] Mario Fusco [英] Alan M

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

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

相关文章

JavaScript常见高级知识点

目录 防抖节流高阶函数函数柯里化数组去重set去重filter去重includes去重 数组扁平化深拷贝getBoundingCilentRectIntersectionObserver自定义事件 防抖 防抖是一种常用的技术手段&#xff0c;在JavaScript中特别常见。它的作用是控制某些高频率触发的事件&#xff0c;在一定时…

RocketMQ消息过滤Tag标签

生产者在封装Message消息时可以传入tag参数&#xff0c;消费者在进行消费时可以进行订阅主题时可以进行tag过滤,代码示例如下. //生产者 public class Producer {public static void main(String[] args) throws Exception{DefaultMQProducer producer new DefaultMQProducer(…

LLM - Chinese-Llama-2-7b 初体验

目录 一.引言 二.模型下载 三.快速测试 四.训练数据 五.总结 一.引言 自打 LLama-2 发布后就一直在等大佬们发布 LLama-2 的适配中文版&#xff0c;也是这几天蹲到了一版由 LinkSoul 发布的 Chinese-Llama-2-7b&#xff0c;其共发布了一个常规版本和一个 4-bit 的量化版本…

Linux命令行宝典:随时查询、轻松应对

&#x1f57a;作者&#xff1a; 迷茫的启明星 学习路线C语言从0到1C初阶数据结构从0到1 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

Ama no Jaku

登录—专业IT笔试面试备考平台_牛客网 题目大意&#xff1a;有一个n*n且仅由0和1构成的矩阵&#xff0c;每次操作可以将一整行或一整列的所有数取反&#xff0c;问能否使所有行中构成的最小数>所有列中构成的最大数 1<n<2000 思路&#xff1a;首先&#xff0c;如果…

H2TEST自动化测试

ref&#xff1a; GitHub - kunyi0605/H2testwpywinauto实战-操作h2testw.exe自动化测试脚本_肤白貌美的博客-CSDN博客 https://www.cnblogs.com/qican/p/15038067.html

Flink CEP (一)原理及概念

目录 1.Flink CEP 原理 2.Flink API开发 2.1 模式 pattern 2.2 模式 pattern属性 2.3 模式间的关系 1.Flink CEP 原理 Flink CEP内部是用NFA&#xff08;非确定有限自动机&#xff09;来实现的&#xff0c;由点和边组成的一个状态图&#xff0c;以一个初始状态作为起点&am…

文件共享服务器(五)sicis

目录 前言 一、概述 1.iscsi概念 2.iscsi介绍 3.相关名词 二、实验 1.构建iscsi服务 2.实现步骤 服务器端 客户端 3.注意事项 总结 前言 iSCSI是由IBM发明的基于以太网的存储协议&#xff0c;该协议与SUN的NFS协议都是为了解决存储资源共享问题的解决方案。两者意图…

git rebase -i

git rebase -i 是一种交互式的 rebase 方式&#xff0c;其中 -i 是 --interactive 的简写。这种方式允许你修改一系列的 commit 信息&#xff0c;在 rebase 过程中有选择地选择、编辑或者合并 commit。 在执行 git rebase -i 命令时&#xff0c;你需要提供一个参数&#xff0c…

音视频——封装格式原理

视频解码基础 一、封裝格式 ​ 我们播放的视频文件一般都是用一种封装格式封装起来的&#xff0c;封装格式的作用是什么呢&#xff1f;一般视频文件里不光有视频&#xff0c;还有音频&#xff0c;封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式&#xff0…

集成学习Boosting - AdaBoost

目录 1. Boosting方法的基本思想 1.1 Bagging VS Boosting 1.2 Boosting算法的基本元素与基本流程 1.3 sklearn中的Boosting算法 2. AdaBoost 3 AdaBoost的基本参数与损失函数 3.1 参数 base_estimator&#xff0c;属性base_estimator_与estimators_ 3.1. 参数 learnin…

vue之vue-pboc组件

功能描述 PBOC业务页面基类组件,提供多个PBOC操作方法,,它的父级组件为vue-base #方法 查询电子现金余额及电子现金上限 queryElecBalance(); 查询电子现金明细 queryElecDetail(); pboc初始化过程接口 initDeviceInfo: function initDeviceInfo( appid, acctype, tranty…

用QFramework来重构 祖玛游戏

资料 Unity - 祖玛游戏 GitHub 说明 用QF一个场景就够了&#xff0c;在UIRoot下切换预制体达到面板切换。 但测试中当然要有一个直接跳到测试面板的 测试脚本&#xff0c;保留测试Scene&#xff08;不然初学者也不知道怎么恢复测试Scene&#xff09;&#xff0c;所以全文按S…

宋浩线性代数笔记(二)矩阵及其性质

更新线性代数第二章——矩阵&#xff0c;本章为线代学科最核心的一章&#xff0c;知识点多而杂碎&#xff0c;务必仔细学习。 重难点在于&#xff1a; 1.矩阵的乘法运算 2.逆矩阵、伴随矩阵的求解 3.矩阵的初等变换 4.矩阵的秩 &#xff08;去年写的字&#xff0c;属实有点ugl…

多态及其原理

文章目录 构成多态的条件虚函数作用&#xff1a;完成重写 重写重载 重写 隐藏为什么析构函数要搞成符合多态?原理预热对于基类指针或引用指向父类或者子类的成员函数是如何调用不同的函数呢&#xff1f; 一个类如果是基类&#xff0c;它的析构函数最好加上virtual 构成多态的条…

E: 有几个软件包无法下载 有未能满足的依赖关系 解决办法

E: 有几个软件包无法下载 有未能满足的依赖关系 解决办法 今天sudo apt install ros-noetic-desktop-full安装ros突然遇到了一些问题&#xff0c;记录一下 E: 无法下载 http://cn.archive.ubuntu.com/ubuntu/pool/universe/s/simbody/libsimbody-dev_3.6.1dfsg-7build1_amd64…

python 小案例33

下面是一个简单的示例代码&#xff0c;展示了如何使用Django来创建一个股票管理分析系统。 首先&#xff0c;在你的虚拟环境中安装Django&#xff1a; pip install Django 然后&#xff0c;创建一个新的Django项目&#xff1a; django-admin startproject stock_management 进入…

AlSD 系列智能安全配电装置是安科瑞电气有限公司专门为低压配电侧开发的一款智能安全用电产 品-安科瑞黄安南

一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护 不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电系统发生漏…

2022 China Open Source Report

| 翻译&#xff1a;黄绍雅、岳扬、刘文涛、李思颖 | 编辑&#xff1a;胡欣元 | 设计&#xff1a;胡欣元 As 2022 finally came to an end, we also emerged from the challenging years of the three-year-long COVID pandemic. The new edition of the "China Open Sourc…

06.计算机网络——IP协议

文章目录 网络层IP协议基本概念协议头格式如何解包如何交付网段划分子网掩码特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址路由 网络层 IP协议 IP协议提供一种将数据从A主机送达到B主机的能力&#xff0c;进行网络层的通信。 ​ IP协议 基本概念 主机 —— 配有IP地址…