深入解析 Java Stream API:筛选子节点的优雅实现!!!

🚀 深入解析 Java Stream API:筛选子节点的优雅实现 🔧

大家好!👋 今天我们来聊聊 Java 8 中一个非常常见的操作:使用 Stream API 从 Map 中筛选出特定条件的元素。🎉 具体来说,我们将深入分析以下代码片段:

List<InviteCode> children = inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());

这段代码是构建邀请码层级树的一部分,背后涉及了 Stream API、Lambda 表达式以及 Collectors.toList 的强大功能。💡 我们将从代码的背景开始,逐步拆解它的实现原理,探讨使用场景、优势和优化方法,最后通过一个实际案例展示它的应用。为了更直观地理解整个过程,我们还会插入一个 Mermaid 流程图!📊

准备好了吗?让我们开始吧!🚀


📖 背景:为什么需要筛选子节点?

在 Java 开发中,我们经常需要处理层级数据。例如,在一个邀请码系统中,我们有一个 Map<Integer, InviteCode>,其中 InviteCode 是一个实体类,包含以下字段:

public class InviteCode {private Integer id;private String inviteCode;private Integer inviteLevel;private Integer createdBy;// Getters and Setterspublic Integer getId() {return id;}public String getInviteCode() {return inviteCode;}public Integer getInviteLevel() {return inviteLevel;}public Integer getCreatedBy() {return createdBy;}
}

假设我们有一个 Map<Integer, InviteCode>inviteCodeMap),包含 adminId = 7 的所有邀请码记录:

idadmin_idcreated_byinvite_codeinvite_level
207NULL******0
217202631131
227207043581
237209828681
247NULL******0
25724******1
26725******2
277269914763

我们的目标是构建一个以 adminId 为根的邀请码层级树。层级树的构建需要递归地从根节点开始,找到每个节点的子节点。子节点的定义是 createdBy 等于当前节点 idInviteCode 对象。换句话说:

  • createdBy == root.getId():表示这是一个子节点(root 是它的父节点)。
  • createdBy != root.getId():表示这不是 root 的子节点。

因此,我们需要从 inviteCodeMap 中筛选出所有 createdBy == root.getId()InviteCode 对象,这就是以下代码的作用:

List<InviteCode> children = inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());

🌟 代码拆解:一步步理解

让我们逐步拆解这段代码,弄清楚它是如何工作的!

1. inviteCodeMap.values()

  • inviteCodeMap:是一个 Map<Integer, InviteCode>,键是 InviteCodeid,值是 InviteCode 对象本身。
  • values()Map 的方法,返回 Map 中所有值的 Collection(类型为 Collection<InviteCode>)。
    • 在这里,inviteCodeMap.values() 返回一个包含所有 InviteCode 对象的集合(例如 id = 20, 21, ..., 27 的 8 个对象)。

结果inviteCodeMap.values() 是一个 Collection<InviteCode>,包含所有 InviteCode 对象。

2. .stream()

  • stream():将 Collection<InviteCode> 转换为一个 Stream<InviteCode>
    • Stream 是 Java 8 引入的流式 API,允许你以声明式的方式处理集合数据(例如映射、过滤、归约等)。

结果inviteCodeMap.values().stream() 生成了一个 Stream<InviteCode>,包含 inviteCodeMap 中的所有 InviteCode 对象。

3. .filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId()))

  • filter:是 Stream API 的一个中间操作,用于筛选流中的元素。
  • ic -> Objects.equals(ic.getCreatedBy(), root.getId()):这是一个 Lambda 表达式,表示一个谓词(Predicate),用于判断每个 InviteCode 对象是否满足条件。
    • ic:代表流中的每个 InviteCode 对象。
    • ic.getCreatedBy():获取 InviteCode 对象的 createdBy 字段(Integer 类型)。
    • root.getId():获取当前根节点的 idInteger 类型)。
    • Objects.equals(ic.getCreatedBy(), root.getId()):比较 ic.getCreatedBy()root.getId() 是否相等。
      • 使用 Objects.equals 而不是直接 == 是为了安全地处理 null 值(如果 ic.getCreatedBy()null== 可能会导致问题)。
  • 作用filter 会保留所有满足条件的元素(createdBy 等于 root.getId()InviteCode),丢弃不满足条件的元素。

类型Predicate<InviteCode>,将 InviteCode 映射为一个布尔值(truefalse)。

4. .collect(Collectors.toList())

  • collect:是 Stream API 的终止操作,用于将流中的元素收集到一个结果容器中(例如 ListSetMap)。
  • Collectors.toList():是一个收集器(Collector),专门用于将流中的元素收集到一个 List 中。

结果collect(Collectors.toList()) 将筛选后的 Stream<InviteCode> 收集到一个新的 List<InviteCode> 中。

5. 整体效果

  • inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList())
    • inviteCodeMap 获取所有 InviteCode 对象,转换为 Stream<InviteCode>
    • 筛选出 createdBy 等于 root.getId()InviteCode 对象(即 root 的子节点)。
    • 将筛选结果收集到一个新的 List<InviteCode> 中。
  • 赋值:将结果赋值给 childrenchildren 是一个 List<InviteCode>,包含 root 的所有直接子节点。

📊 Mermaid 流程图:可视化筛选过程

为了更直观地理解从 Map<Integer, InviteCode> 筛选子节点的过程,我们使用 Mermaid 流程图来展示:

True
False
Start: Map<Integer, InviteCode> inviteCodeMap
Collection<InviteCode>
inviteCodeMap.values()
Stream<InviteCode>
.stream()
For each InviteCode in Stream
Check Condition:
Objects.equals(ic.getCreatedBy(), root.getId())
Keep InviteCode
(e.g., id=21, createdBy=20)
Discard InviteCode
(e.g., id=24, createdBy=null)
Collect to List<InviteCode>
Collectors.toList()
End: List<InviteCode> children
  • 流程说明
    1. Map<Integer, InviteCode> 开始,获取所有值(inviteCodeMap.values())。
    2. 转换为 Stream<InviteCode>
    3. 对流中的每个 InviteCode 对象:
      • 检查 createdBy == root.getId()
      • 如果 true,保留该对象;如果 false,丢弃。
    4. 将筛选后的元素收集到 List<InviteCode> 中。

📝 示例:具体数据

假设 inviteCodeMap 包含以下数据(adminId = 7):

idadmin_idcreated_byinvite_codeinvite_level
207NULL******0
217202631131
227207043581
237209828681
247NULL******0
25724******1
26725******2
277269914763

1. inviteCodeMap.values().stream()

  • inviteCodeMap.values() 返回一个 Collection<InviteCode>,包含 8 个 InviteCode 对象(id = 20, 21, ..., 27)。
  • .stream() 将其转换为 Stream<InviteCode>

2. .filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId()))

假设当前 rootid = 20InviteCode

  • root.getId() = 20
  • 对每个 InviteCode 对象检查 createdBy 是否等于 20
    • id = 20createdBy = nullObjects.equals(null, 20) = false,丢弃。
    • id = 21createdBy = 20Objects.equals(20, 20) = true,保留。
    • id = 22createdBy = 20Objects.equals(20, 20) = true,保留。
    • id = 23createdBy = 20Objects.equals(20, 20) = true,保留。
    • id = 24createdBy = nullObjects.equals(null, 20) = false,丢弃。
    • id = 25createdBy = 24Objects.equals(24, 20) = false,丢弃。
    • id = 26createdBy = 25Objects.equals(25, 20) = false,丢弃。
    • id = 27createdBy = 26Objects.equals(26, 20) = false,丢弃。

结果:筛选后的 Stream<InviteCode> 包含 3 个元素:

  • InviteCode(id=21, createdBy=20, ...)
  • InviteCode(id=22, createdBy=20, ...)
  • InviteCode(id=23, createdBy=20, ...)

3. .collect(Collectors.toList())

  • 将筛选后的 Stream<InviteCode> 收集到一个新的 List<InviteCode> 中。

结果children 是一个 List<InviteCode>,包含以下 3 个元素:

  • InviteCode(id=21, createdBy=20, ...)
  • InviteCode(id=22, createdBy=20, ...)
  • InviteCode(id=23, createdBy=20, ...)

4. 另一个例子:root = id = 24

  • root.getId() = 24
  • 筛选 createdBy = 24
    • id = 20createdBy = null,丢弃。
    • id = 21createdBy = 20,丢弃。
    • id = 22createdBy = 20,丢弃。
    • id = 23createdBy = 20,丢弃。
    • id = 24createdBy = null,丢弃。
    • id = 25createdBy = 24,保留。
    • id = 26createdBy = 25,丢弃。
    • id = 27createdBy = 26,丢弃。

结果children 包含 1 个元素:

  • InviteCode(id=25, createdBy=24, ...)

🌟 为什么需要 children

buildTree 方法中,children 的作用是找到当前节点(root)的所有直接子节点,以便递归构建树形结构:

private InviteCodeTreeDTO buildTree(InviteCode root, Map<Integer, InviteCode> inviteCodeMap) {InviteCodeTreeDTO node = new InviteCodeTreeDTO();node.setId(root.getId());node.setInviteCode(root.getInviteCode());node.setInviteLevel(root.getInviteLevel());node.setChildren(new ArrayList<>());// 查找所有子节点(createdBy = root.id)List<InviteCode> children = inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());// 递归构建子树for (InviteCode child : children) {InviteCodeTreeDTO childNode = buildTree(child, inviteCodeMap);node.getChildren().add(childNode);}return node;
}
  • 层级树构建
    • 当前节点 root(例如 id = 20)。
    • 找到所有子节点(createdBy = 20InviteCode,即 id = 21, 22, 23)。
    • 递归调用 buildTree 为每个子节点构建子树。
  • 递归:通过不断查找子节点,构建完整的树形结构。

🚀 优势:为什么使用 Stream API?

1. 代码简洁

  • Stream API 提供了声明式的写法,比传统的 for 循环更简洁。
  • 传统写法可能需要手动遍历和填充 List
    List<InviteCode> children = new ArrayList<>();
    for (InviteCode ic : inviteCodeMap.values()) {if (Objects.equals(ic.getCreatedBy(), root.getId())) {children.add(ic);}
    }
    
  • 使用 Stream API,代码更简洁优雅。

2. 功能强大

  • Stream API 支持链式操作,可以轻松添加其他过滤条件。
  • 例如,如果只想筛选 inviteLevel == 1 的子节点:
    List<InviteCode> children = inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId()) && ic.getInviteLevel() == 1).collect(Collectors.toList());
    

3. 并行处理

  • Stream API 支持并行处理(parallelStream()),在大规模数据下可以提高性能:
    List<InviteCode> children = inviteCodeMap.values().parallelStream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());
    

🛠️ 优化建议

1. 更高效的子节点查找

当前实现中,inviteCodeMap.values().stream() 需要遍历所有 InviteCode 对象,效率不高。可以通过预先构建一个 Map<Integer, List<InviteCode>> 来存储 createdBy 到子节点的映射:

// 在 getAdminInviteCodeTree 中预构建
Map<Integer, List<InviteCode>> childrenMap = inviteCodes.stream().filter(ic -> ic.getCreatedBy() != null).collect(Collectors.groupingBy(InviteCode::getCreatedBy));// 修改 buildTree 方法
private InviteCodeTreeDTO buildTree(InviteCode root, Map<Integer, InviteCode> inviteCodeMap, Map<Integer, List<InviteCode>> childrenMap) {InviteCodeTreeDTO node = new InviteCodeTreeDTO();node.setId(root.getId());node.setInviteCode(root.getInviteCode());node.setInviteLevel(root.getInviteLevel());node.setChildren(new ArrayList<>());// 直接从 childrenMap 获取子节点List<InviteCode> children = childrenMap.getOrDefault(root.getId(), Collections.emptyList());for (InviteCode child : children) {InviteCodeTreeDTO childNode = buildTree(child, inviteCodeMap, childrenMap);node.getChildren().add(childNode);}return node;
}
  • 效果:通过 childrenMap,可以以 O(1) 的时间复杂度找到某个 id 的所有子节点。

2. 并row处理

如果 inviteCodeMap 非常大,可以使用 parallelStream() 提高性能:

List<InviteCode> children = inviteCodeMap.values().parallelStream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());
  • 注意:并行流适合大数据量,但在小数据量下可能有性能开销。

3. 日志记录

添加日志,跟踪子节点的查找:

List<InviteCode> children = inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList());
logger.info("Found {} children for root node {}: {}", children.size(), root.getId(), children);
  • 效果:便于调试和监控。

📝 完整代码:实际应用

以下是完整的 InviteCodeService 实现,展示了如何使用 children 构建层级树:

public class InviteCodeService {private final InviteCodeRepository inviteCodeRepository;private static final Logger logger = LoggerFactory.getLogger(InviteCodeService.class);public InviteCodeService(InviteCodeRepository inviteCodeRepository) {this.inviteCodeRepository = inviteCodeRepository;}public AdminInviteCodeTreeDTO getAdminInviteCodeTree(Integer adminId) {List<InviteCode> inviteCodes = inviteCodeRepository.findByAdminId(adminId);if (inviteCodes.isEmpty()) {AdminInviteCodeTreeDTO result = new AdminInviteCodeTreeDTO();result.setAdminId(adminId);result.setChildren(Collections.emptyList());return result;}// 将 List<InviteCode> 转换为 Map<Integer, InviteCode>Map<Integer, InviteCode> inviteCodeMap = inviteCodes.stream().collect(Collectors.toMap(InviteCode::getId, ic -> ic));// 预构建 createdBy 到子节点的映射Map<Integer, List<InviteCode>> childrenMap = inviteCodes.stream().filter(ic -> ic.getCreatedBy() != null).collect(Collectors.groupingBy(InviteCode::getCreatedBy));// 找到所有根节点(createdBy = NULL)List<InviteCode> roots = inviteCodes.stream().filter(ic -> ic.getCreatedBy() == null).collect(Collectors.toList());logger.info("Found {} root nodes for adminId {}: {}", roots.size(), adminId, roots);// 如果没有根节点,直接返回if (roots.isEmpty()) {AdminInviteCodeTreeDTO result = new AdminInviteCodeTreeDTO();result.setAdminId(adminId);result.setChildren(Collections.emptyList());return result;}// 为每个根节点构建树形结构List<InviteCodeTreeDTO> trees = new ArrayList<>();for (InviteCode root : roots) {InviteCodeTreeDTO tree = buildTree(root, inviteCodeMap, childrenMap);trees.add(tree);}AdminInviteCodeTreeDTO result = new AdminInviteCodeTreeDTO();result.setAdminId(adminId);result.setChildren(trees);return result;}private InviteCodeTreeDTO buildTree(InviteCode root, Map<Integer, InviteCode> inviteCodeMap, Map<Integer, List<InviteCode>> childrenMap) {InviteCodeTreeDTO node = new InviteCodeTreeDTO();node.setId(root.getId());node.setInviteCode(root.getInviteCode());node.setInviteLevel(root.getInviteLevel());node.setChildren(new ArrayList<>());// 直接从 childrenMap 获取子节点List<InviteCode> children = childrenMap.getOrDefault(root.getId(), Collections.emptyList());logger.info("Found {} children for root node {}: {}", children.size(), root.getId(), children);for (InviteCode child : children) {InviteCodeTreeDTO childNode = buildTree(child, inviteCodeMap, childrenMap);node.getChildren().add(childNode);}return node;}
}

🎉 总结

通过 Stream API 和 Collectors.toList,我们可以轻松地从 Map<Integer, InviteCode> 中筛选出子节点,为后续的层级树构建提供了基础。💻

  • 核心代码inviteCodeMap.values().stream().filter(ic -> Objects.equals(ic.getCreatedBy(), root.getId())).collect(Collectors.toList()) 筛选出子节点。
  • 优势:代码简洁、功能强大、支持并行处理。
  • 优化:通过 childrenMap 提高查找效率、添加日志、支持并行流。

希望这篇博客对你理解 Stream API 和 filter 操作有所帮助!💬 如果你有其他问题,欢迎留言讨论!🚀

📚 参考:Java 官方文档、Collectors 源码。点赞和分享哦!😊

在这里插入图片描述

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

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

相关文章

统计学重要概念:自由度

在统计学中&#xff0c;自由度&#xff08;degrees of freedom&#xff0c;简称df&#xff09;是一个重要的概念&#xff0c;它表示在计算某个统计量时可以自由变化的值的数量。对于一个样本量为n的样本&#xff0c;自由度通常为n-1&#xff0c;这是因为我们需要用样本数据来估…

数据结构-排序

文章目录 1. 排序的概念2. 常见排序算法的实现2.1 插入排序1&#xff09;插入排序一&#xff09;基本思想二&#xff09;特性及时间复杂度三&#xff09;代码实现 2&#xff09;希尔排序&#xff08;缩小增量排序&#xff09;一&#xff09;基本思想二&#xff09;特性及时间复…

压缩壳学习

壳是什么 壳就是软件的一个保护套&#xff0c;防止软件被进行反编译或被轻易地修改。 其作用就是为了保护软件。 常见的大类壳有压缩壳、加密壳、VM 壳的分类。 压缩壳顾名思义就是用来减小软件的文件大小的&#xff1b;加密壳&#xff0c;通过加密软件来保护软件&#xff…

《AI大模型趣味实战》第6集:基于大模型和RSS聚合打造个人新闻电台

《AI大模型趣味实战》第6集&#xff1a;基于大模型和RSS聚合打造个人新闻电台 摘要 本文将带您探索如何结合AI大模型和RSS聚合技术&#xff0c;打造一个功能丰富的个人新闻电台系统。我们将使用Python和PyQt5构建一个桌面应用程序&#xff0c;该应用可以从多个RSS源抓取新闻&…

(学习总结29)Linux 进程概念和进程状态

Linux 进程概念 冯诺依曼体系结构软件运行与存储分级数据流动的理论过程 操作系统操作系统(Operator System) 概念操作系统的功能与作用系统调用和库函数概念 进程概念描述进程 - PCBtask_struct查看进程通过系统调用获取进程标示符 PID通过系统调用 fork 函数创建进程简单使用…

LLM - CentOS上离线部署Ollama+Qwen2.5-coder模型完全指南

文章目录 离线安装OllamaOllama下载Ollama硬件需求Ollama 常用命令参考Ollama安装Ollama 服务管理&开机启动开启局域网访问 Ollama 服务 离线安装模型gguf 文件格式下载Qwen2.5-Coder-7B-Instruct-GGUF格式选择 ( gguf 版本 )构建Modelfile文件加载并运行离线模型测试 集成…

Linux——信号

目录 Linux——信号1.信号的基础了解2.技术应用角度的信号3.产生信号3.1按键组合3.2系统调用产生信号3.2.1 kill()3.2.2 raise()3.2.3 abort() 3.3**.** 软件条件产生信号3.4硬件异常产生信号3.4.1 /0异常3.4.2 内存越界异常 4.理解信号的存在5.总结一下6.核心转储7.全部信号都…

向量叉积的应用——正反画画

1 解题思路 解题思路涉及的向量积相关知识 c实现 #include<iostream> #include<vector>using namespace std;struct TrianglePoint {int x;int y; };int momentForce(TrianglePoint A, TrianglePoint B, TrianglePoint C) {//AB向量&#xff1a;(B.x-A.x, B.y-A.…

构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据

构建自定义MCP天气服务器:集成Claude for Desktop与实时天气数据 概述 本文将指导开发者构建一个MCP(Model Control Protocol)天气服务器,通过暴露get-alerts和get-forecast工具,为Claude for Desktop等客户端提供实时天气数据支持。该方案解决了传统LLM无法直接获取天气…

Web安全策略CSP详解与实践

引言 &#xff1a;在黑客攻击频发的今天&#xff0c;你的网站是否像“裸奔”一样毫无防护&#xff1f;跨站脚本&#xff08;XSS&#xff09;、数据注入等攻击随时可能让用户数据泄露。今天我们将揭秘一个网站的隐形保镖——内容安全策略&#xff08;CSP&#xff09;&#xff0c…

HC-05与HC-06蓝牙配对零基础教程 以及openmv识别及远程传输项目的概述

这个是上一年的项目&#xff0c;之前弄得不怎么完整&#xff0c;只有一个openmv的&#xff0c;所以openmv自己去我主页找&#xff0c;这篇主要讲蓝牙 这个是我在使用openmv连接单片机1然后单片机1与单片机2通过蓝牙进行通信 最终实现的效果是&#xff1a;openmv识别到图形和数…

点云分割方法

点云分割 通过判断三维距离&#xff0c;实现对创建3团点云的分割 通过判断三维距离&#xff0c;实现对创建3团点云的分割 * 点云1 gen_object_model_3d_from_points (rand(100), rand(100),rand(100), Points1)* 点云2 gen_object_model_3d_from_points (rand(100), 2rand(100…

SpringBoot3使用CompletableFuture时java.util.ConcurrentModificationException异常解决方案

问题描述 在Spring Boot 3项目中&#xff0c;使用CompletableFuture进行异步编程时&#xff0c;偶发{"code":500,"msg":"java.util.ConcurrentModificationException"}异常&#xff0c;但代码中并未直接操作List或CopyOnWriteArrayList等集合类…

细说卫星导航:测距定位原理

测距定位原理 1. 伪距测量技术 核心原理&#xff1a;卫星发射信号&#xff0c;用户接收并记录传播时间&#xff0c;乘以光速得到距离&#xff08;伪距&#xff09;。 技术细节&#xff1a; 信号传播路径分析 信号结构&#xff1a; 卫星信号包含三部分&#xff1a; 载波&…

Linux系统管理与编程09:任务驱动综合应用

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 [环境] windows11、centos9.9.2207、zabbix6、MobaXterm、Internet环境 [要求] zabbix6.0安装环境&#xff1a;Lamp&#xff08;linux httpd mysql8.0 php&#xff09; [步骤] 5 …

RAG(Retrieval-Augmented Generation)基建之PDF解析的“魔法”与“陷阱”

嘿&#xff0c;亲爱的算法工程师们&#xff01;今天咱们聊一聊PDF解析的那些事儿&#xff0c;简直就像是在玩一场“信息捉迷藏”游戏&#xff01;PDF文档就像是个调皮的小精灵&#xff0c;表面上看起来规规矩矩&#xff0c;但当你想要从它那里提取信息时&#xff0c;它就开始跟…

RK3568 I2C底层驱动详解

前提须知&#xff1a;I2C协议不懂的话就去看之前的内容吧&#xff0c;这个文章需要读者一定的基础。 RK3568 I2C 简介 RK3568 支持 6 个独立 I2C: I2C0、I2C1、I2C2、I2C3、I2C4、I2C5。I2C 控制器支持以下特性: ① 兼容 i2c 总线 ② AMBA APB 从接口 ③ 支持 I2C 总线主模式…

UNIX网络编程笔记:基本TCP套接字编程

一、socket函数 一、socket函数核心参数与协议组合 函数原型与基本功能 #include <sys/socket.h> int socket(int family, int type, int protocol);• 功能&#xff1a;创建通信端点&#xff08;套接字&#xff09;&#xff0c;返回描述符供后续操作。 • 返回值&#…

JSON在AutoCAD二次开发中应用场景及具体案例

配置文件的读取 在AutoCAD插件开发中&#xff0c;可能需要生成、修改、读取配置文件中一些参数或设置。JSON格式的配置文件易于编写和修改&#xff0c;且可以方便地反序列化为对象进行使用。 运行后效果如下 using Autodesk.AutoCAD.ApplicationServices; using Autodesk.Au…

自由学习记录(46)

CG语法的数据类型 // uint : 无符号整数&#xff08;32位&#xff09; // int : 有符号整数&#xff08;32位&#xff09; // float : 单精度浮点数&#xff08;32位&#xff09;&#xff0c;通常带后缀 f&#xff08;如 1.0f&#xff09; // half : 半精度浮…