程序猿DD - Java专区 https://java.didispace.com/ 分享关于Java基础、Java并发、Java新版本特性等关于Java的学习总结和实践经验分享 zh-CN Tue, 01 Jul 2025 02:58:23 GMT Tue, 01 Jul 2025 02:58:23 GMT vuepress-plugin-feed2 https://validator.w3.org/feed/docs/rss2.html Java IntelliJ IDEA 10个Java开发者必须改掉的过时编程习惯 https://java.didispace.com/article/20250701-10-java-features-you-should-stop-using-today.html https://java.didispace.com/article/20250701-10-java-features-you-should-stop-using-today.html 10个Java开发者必须改掉的过时编程习惯 10个Java开发者必须改掉的过时编程习惯 "如果你一直拖着过去不放,就无法向前进步。"这正是我在代码审查时对团队说的话。然而,每次我打开一个拉取请求时,我仍然看到过时的Java特性、坏习惯和应该在几年前就被淘汰的编码习惯。所以,如果你今天在使用Java,无论你是初级、中级还是高级开发者,这篇文章都适合你 🫵 。其中一些观点可能会让你感到不舒服。有些可能与你所学的相违背。但这正是你应该读到最后的原因。 1. 错误使用 Optional.get() Optional是一个很棒的特性,但我看到许多开发者误用了它: Optional<String> value = getValue(); String result = value.get(); // 可能抛出 NoSuchElementException! Java Mon, 30 Jun 2025 01:00:00 GMT 10个Java开发者必须改掉的过时编程习惯

"如果你一直拖着过去不放,就无法向前进步。"这正是我在代码审查时对团队说的话。然而,每次我打开一个拉取请求时,我仍然看到过时的Java特性、坏习惯和应该在几年前就被淘汰的编码习惯。所以,如果你今天在使用Java,无论你是初级、中级还是高级开发者,这篇文章都适合你 🫵 。其中一些观点可能会让你感到不舒服。有些可能与你所学的相违背。但这正是你应该读到最后的原因。

1. 错误使用 Optional.get()

Optional是一个很棒的特性,但我看到许多开发者误用了它:

这是错误的!

如果你在使用**Optional**,就要拥抱它的API:

2. 硬编码值而不是使用常量

这是我在代码中看到的最大罪过之一:

一个新的初级开发者加入团队,他不知道 3 是什么意思。然后他错误地修改了逻辑。砰。生产环境出现了bug。

正确的方式:

为什么? 因为这样你的代码变得自文档化且安全。

3. 有缺陷的单例模式的双重检查锁定

经典错误:

除非使用volatile完美地完成,否则这在Java中是有缺陷的。在并发环境中可能出现微妙的错误。

这里是修复方法:

更好的方式:

这些方式安全、简单,并且避免了并发错误。

4. Vector 和 Hashtable

现在是2025年。然而,有时我仍然看到这样的代码:

VectorHashtable都是Java早期的遗留类。它们是同步的,因此比现代替代方案慢得多

应该使用什么替代:

如果你需要线程安全,使用:

为什么要停止使用VectorHashtable

  • 在现代应用中性能差
  • 存在更好的替代方案,对同步有更精细的控制

5. 原始类型

我仍然审查到这样的PR:

这是危险的💀。

原始类型移除了类型安全性,导致在运行时爆发的微妙错误。

正确的方式:

提示: 总是使用泛型。你的IDE会帮你早期发现错误。

6. StringBuffer(当你不需要同步时)

许多开发者使用这个:

但除非你在做多线程工作,否则StringBuffer是不必要的慢。

应该使用什么替代:

StringBuilder更快,对于单线程操作来说已经足够了,这是你大部分代码的情况。

7. 直接使用 SimpleDateFormat

这是连高级开发者都会犯的经典错误:

问题在哪里?🤔 SimpleDateFormat不线程安全的。如果这段代码在Web应用或多线程环境中运行,它可能抛出奇怪的日期格式化错误

应该使用什么替代:

新的java.time包(从Java 8开始)是线程安全的,并且远远优越。

8. 使用 System.out.println 进行日志记录

我实际上见过企业应用程序中有数百个**System.out.println()**语句。
当你调试生产问题时,你会后悔的。

正确的方式:

使用日志框架,如SLF4J with LogbackLog4j2

  • 你可以获得日志级别(info、debug、error)
  • 你可以将日志重定向到文件
  • 你可以控制日志格式和保留期

🙅‍♂️永远不要在生产代码中部署System.out.println

9. 过度使用同步而不是使用现代并发

许多开发者仍然这样做:

但Java已经发展了🪴。java.util.concurrent提供了强大、更安全、性能更好的工具:

  • 使用ReentrantLock进行显式锁定
  • 使用ConcurrentHashMap而不是同步映射
  • 使用AtomicIntegerAtomicBoolean
  • 使用ExecutorService而不是手动管理线程

**除非绝对必要,否则避免使用synchronized。**并发很难——让现代库来帮助你。

10. 过时的集合API方法

我有时仍然看到这样的代码:

❌ 当你可以使用现代for-each循环时,停止使用EnumerationIterator

这些更清洁、现代、更可读。

]]>
Java 24 五大特性 https://java.didispace.com/article/20250619-java-24-top-5-features.html https://java.didispace.com/article/20250619-java-24-top-5-features.html Java 24 五大特性 Java 24 五大特性 前言 Java 24 是平台演进过程中一个大胆而深思熟虑的重要里程碑。经验丰富的 Java 开发者不仅会欣赏这次发布的变化数量,更会被其深度和发展方向所震撼。本次发布包含 24 个 JEP,显而易见,OpenJDK 社区正在性能、可扩展性和现代开发需求方面全力投入。在这篇文章中,我将为大家详细介绍我认为对资深工程师最具影响力的五个特性:分代 Shenandoah(实验性)、紧凑对象头(实验性)、Stream Gatherers、提前类加载与链接,以及虚拟线程同步无钉扎。这些特性绝不仅仅是渐进式改进——它们体现了真正的架构思维和对 Java 未来发展方向的深远愿景。我们将深入了解它们的工作原理、核心优势,以及在实际应用中的重要意义——并在关键之处提供详细示例。实验性特性的加入也传达了一个更重要的信息:Java 不仅仅是在跟上时代步伐——它正在引领技术潮流,特别是在内存管理和并发处理领域。如果你正在构建现代高性能 Java 应用程序,这些变化绝对值得你深入理解。 Java Thu, 19 Jun 2025 01:00:00 GMT Java 24 五大特性

前言

Java 24 是平台演进过程中一个大胆而深思熟虑的重要里程碑。经验丰富的 Java 开发者不仅会欣赏这次发布的变化数量,更会被其深度和发展方向所震撼。本次发布包含 24 个 JEP,显而易见,OpenJDK 社区正在性能、可扩展性和现代开发需求方面全力投入。在这篇文章中,我将为大家详细介绍我认为对资深工程师最具影响力的五个特性:分代 Shenandoah(实验性)、紧凑对象头(实验性)、Stream Gatherers、提前类加载与链接,以及虚拟线程同步无钉扎。这些特性绝不仅仅是渐进式改进——它们体现了真正的架构思维和对 Java 未来发展方向的深远愿景。我们将深入了解它们的工作原理、核心优势,以及在实际应用中的重要意义——并在关键之处提供详细示例。实验性特性的加入也传达了一个更重要的信息:Java 不仅仅是在跟上时代步伐——它正在引领技术潮流,特别是在内存管理和并发处理领域。如果你正在构建现代高性能 Java 应用程序,这些变化绝对值得你深入理解。

让我们开始探索吧!

1. 分代 Shenandoah(实验性)

这是对 Shenandoah GC 的革命性增强,引入了全新的实验性分代模式(JEP 404)。如果你曾经因为 Shenandoah 在低延迟高响应应用中令人印象深刻的低暂停时间而青睐它,那么你一定会为它的最新进展感到兴奋——它现在将堆内存分为年轻代和老年代,将垃圾收集工作重点聚焦在最关键的地方——那些在应用程序中占主导地位的短生命周期对象。

启用此特性非常简单:

令人振奋的是,这项增强功能在保持我们期望的超低暂停时间的同时,还能显著减少内存占用和 CPU 开销。收集器会根据应用程序的行为模式智能调整分代大小,使其对具有大量短生命周期对象的工作负载特别有效。

这一发展使 Shenandoah 与 G1 和 ZGC 等其他现代收集器保持同步,同时保持其在最小化延迟方面的独特优势。虽然仍处于实验阶段,在生产环境部署前需要进行充分测试,但分代 Shenandoah 代表了 Java 垃圾收集领域的重要演进。它标志着一个更广泛的趋势,即高性能收集器越来越多地利用弱分代假设来优化内存管理效率。

2. 紧凑对象头(实验性)

Java 24 通过 JEP 450 的紧凑对象头为我们带来了令人兴奋的特性,这是 Project Lilliput 的核心组成部分。简单来说,这个实验性特性将 64 位系统上的对象头从 96-128 位大幅缩减到仅 64 位,这意味着堆内存中每个对象的内存开销都会显著减少。

想要体验吗?只需在 JVM 参数中添加以下配置:

该特性与压缩类指针协同工作(在大多数现代系统上默认启用),虽然你不会看到直接的代码变化,但内存分析工具会清晰地显示出差异。带来的好处非常显著——更小的堆内存占用、更高的部署密度(在相同硬件上运行更多实例),以及改进的数据局部性,从而获得更好的 CPU 缓存利用率和整体性能。

这对于内存密集型应用程序和注重内存占用的微服务架构特别有价值。亚马逊的测试甚至显示启用此特性后 CPU 使用率有所降低。在底层实现上,它将 64 位标记字和 32/64 位类字合并为单个 64 位字,并巧妙地为未来的 Project Valhalla 增强预留了一些位空间。需要注意的是,作为实验性特性,它确实存在一些限制——比如 22 位压缩类指针将你限制在大约 400 万个不同的类。对大多数开发者来说,这个限制已经足够,但如果你正在处理大型系统或涉及大量动态代码生成的场景,这个限制值得仔细考虑。这种对内存效率的专注体现了 Java 对云原生环境优化的坚定承诺,在云环境中每个字节都至关重要!

3. Stream Gatherers:增强流处理能力

Java 24 正式确定了 Stream Gatherers API(JEP 485),对于任何热爱使用流式编程的开发者来说,这都是一个颠覆性的改变。可以把它看作是我们一直在等待的缺失拼图——为你的流处理管道提供自定义中间操作的能力!

核心是全新的 Gatherer 接口,它允许你直接在流中定义复杂的转换逻辑。现在你可以调用新的 gather(Gatherer) 方法来整合这些自定义操作。每个 Gatherer 实现包含四个关键方法:初始化器、集成器、组合器和终结器——让你完全掌控元素的处理方式。

更令人惊喜的是什么?Java 在 java.util.stream.Gatherers 类中提供了现成可用的收集器。看看这个简洁的例子:

这个 API 极大地扩展了流式编程的能力边界——支持有状态转换、通过可重用的收集器提升代码可读性,甚至支持并行执行以获得性能提升。它为中间操作填补了 Collectors 长期以来为终端操作填补的相同角色。

经过几个预览版本的迭代,Stream Gatherers 已经成熟为一个稳定的、经过社区充分测试的 API,大大简化了以前需要复杂解决方案的数据处理任务。对于专业的 Java 开发者来说,这个特性意味着更简洁的代码、更少的外部依赖,以及表达数据转换逻辑的强大新方式。

4. AOT 类加载与链接:启动时间大幅提升

Java 24 引入了一个你绝对想要了解的激动人心的特性:提前(AOT)类加载与链接(JEP 483)。作为 Project Leyden 的重要组成部分,这项优化彻底解决了 Java 长期以来的痛点之一——启动性能问题。利用 AOT 类加载和链接无需对应用程序代码进行任何直接修改,性能优势在 JVM 的初始启动阶段就能立即体现出来。

简单来说,这个特性将类加载和链接过程(通常在运行时完成)提前到预执行阶段,将结果存储在缓存中以实现闪电般的启动速度。实现过程很简单,采用三阶段方法:

  1. 使用 -XX:AOTMode=record -XX:AOTConfiguration=<path> 运行训练会话以识别要缓存的类
  2. 使用 -XX:AOTMode=create -XX:AOTConfiguration=<path> -XX:AOTCache=<path> 创建 AOT 缓存
  3. 在后续运行中仅使用 -XX:AOTCache=<path>

性能提升令人震撼——基准测试显示启动时间最多可提升 42%!"HelloStream" 测试从 0.031 秒优化到 0.018 秒,而 Spring 的 PetClinic 从 4.486 秒大幅提升到 2.604 秒。

这个特性建立在 AppCDS(JDK 11)的基础之上,但走得更远,不仅缓存解析后的字节码,还缓存类的完整加载和链接状态。虽然不像 GraalVM Native Image 那样激进,但它提供了实质性的改进,同时避免了相同的约束和构建复杂性。

对于快速启动至关重要的云原生和无服务器环境,这是一个巨大的突破。Spring Boot 和 Quarkus 等主流框架已经在积极进行集成工作。只需记住,你的训练运行应该准确反映应用程序的正常启动行为,以最大化性能收益。这一进步标志着解决 Java 历史性启动延迟问题的重要里程碑,同时为未来启动和预热性能的进一步增强奠定了坚实基础。

5. 虚拟线程同步无需固定

还记得在JDK 21–23中,当你的虚拟线程在同步块内遇到阻塞操作时,它会被固定到其承载平台线程上吗?

这基本上抵消了虚拟线程承诺的许多可扩展性优势。好消息是,在Java 24中,这个限制已经消失!

这就是它的精妙之处:你的代码无需任何修改。你现有的同步块现在可以与虚拟线程完美协作:

性能改进是革命性的。在 10,000 个并发请求的基准测试中,应用程序从 JDK 21 上的每秒 800.9 个请求飙升到 JDK 24 上惊人的每秒 4,264.4 个请求——完成任务的时间从 12.486 秒大幅缩短到 2.345 秒!参考

这项增强使虚拟线程适用于更广泛的应用场景,包括大量使用同步机制的遗留代码。你现在可以放心地采用虚拟线程,而无需大规模重构来用 ReentrantLock 替换 synchronized。

虽然少数边缘情况(本地代码交互、类初始化)仍可能导致钉扎,但对大多数应用程序的影响微乎其微。这项改进代表了 Java 并发演进的重要里程碑,可能会让许多开发者从复杂的响应式编程模型回归到更简单的每请求一线程方法。

]]>
Java开发者玩转机器学习的利器: Tribuo https://java.didispace.com/article/20250604-java-tribuo.html https://java.didispace.com/article/20250604-java-tribuo.html Java开发者玩转机器学习的利器: Tribuo Java开发者玩转机器学习的利器: Tribuo 1. 概述 机器学习(ML)和人工智能(AI)正在推动软件开发的变革,使系统能够通过数据学习并做出智能预测。 作为一名Java开发者,如果要训练自己的预测模型,是不是第一想到的还是把Python拿起来?其实不一定非要拿起Python,在Java领域也有自己的生产级机器学习工具,它支持分类、回归、聚类等常见任务,还能无缝对接 TensorFlow 等框架,用 Java 就能直接训模型、做预测! 它就是:Tribuo,是 Oracle 推出的面向生产环境的开源机器学习库,极大简化了健壮 ML 模型的构建与部署。与 Weka 和 Deeplearning4j 类似,Tribuo 支持多种机器学习任务,并能轻松集成到 Java 应用中。 Java Wed, 04 Jun 2025 01:00:00 GMT Java开发者玩转机器学习的利器: Tribuo

1. 概述

机器学习(ML)和人工智能(AI)正在推动软件开发的变革,使系统能够通过数据学习并做出智能预测。

作为一名Java开发者,如果要训练自己的预测模型,是不是第一想到的还是把Python拿起来?其实不一定非要拿起Python,在Java领域也有自己的生产级机器学习工具,它支持分类、回归、聚类等常见任务,还能无缝对接 TensorFlow 等框架,用 Java 就能直接训模型、做预测!

它就是:Tribuo,是 Oracle 推出的面向生产环境的开源机器学习库,极大简化了健壮 ML 模型的构建与部署。与 Weka 和 Deeplearning4j 类似,Tribuo 支持多种机器学习任务,并能轻松集成到 Java 应用中。

接下来本文我们将了解 Tribuo 支持的多种机器学习算法,并以 UCI 红葡萄酒质量数据集为例,构建一个用于预测葡萄酒质量的回归模型。

2. 什么是 Tribuo?

Tribuo 是一个以 Java 为核心的机器学习库,支持:

  • 监督学习:如回归、分类等
  • 无监督学习:如聚类

此外,Tribuo 拥有强类型特性,能够强制输入输出类型一致,有效防止运行时错误,确保模型开发过程的规范性。

它支持以 ONNX(开放神经网络交换)格式导入和导出模型,便于与 TensorFlow、PyTorch 等主流 ML 框架集成。

另一个亮点是 provenance(溯源)追踪功能,可记录数据集、模型参数和训练配置等元数据,提升透明度和可复现性。

随着 AI 在企业级 Java 应用中的普及,Tribuo 为在 Java 系统中直接嵌入智能行为提供了实用工具包。

3. 支持的机器学习算法

Tribuo 支持多种机器学习任务,包括:

  • 分类:预测离散类别或标签。例如,预测一支足球队是否会获胜,或根据质量阈值将葡萄酒分为好或坏。
  • 回归:预测连续值,如葡萄酒质量分数或患者胆固醇水平。
  • 聚类:在无标签数据中识别分组。例如,可以根据酸度、酒精含量等化学属性对葡萄酒进行分组,而无需知道其质量分数。

4. 搭建 Tribuo 项目

我们将通过构建一个葡萄酒质量回归预测模型,体验 Tribuo 的实际应用。

首先,在 pom.xml 中添加 Tribuo 依赖

tribuo-all 依赖提供了加载和训练数据集所需的相关类。

然后,下载 UCI 红葡萄酒质量数据集,并放置到 src/main/resources/dataset 目录下。该数据集包含 11 个理化特征,如酸度和酒精含量:

quality 列是一个适合回归任务的连续数值。

最后,创建一个名为 WineQualityRegression 的类:

后续章节将在该类中实现训练和保存模型的相关逻辑。

5. 类级变量

接下来,定义如下类级变量:

上述代码中,我们定义了数据集路径和训练模型保存/加载路径。

随后,定义了四个变量,分别代表:

  • Model —— 存储预测模型的类
  • Trainer —— 可训练预测模型的接口
  • Dataset —— 用于训练的数据集类

此外,我们显式指定了模型输出类型为 Regressor

6. 加载与划分数据集

定义一个方法用于加载并划分数据集:

这里,我们用 CSVLoader 解析分号分隔的 CSV 文件并为回归任务做准备。RegressionFactory 用于创建回归输出,指定目标变量 quality 为连续变量。DataSource<Regressor> 保存解析后的数据。

随后,为了评估模型的泛化能力和表现,使用 TrainTestSplitter 将数据集按 7:3 划分为训练集和测试集。

7. 训练回归模型

由于葡萄酒质量分数为数值型,我们采用分类与回归树(CART)作为基学习器进行训练:

上述方法中,CARTRegressionTrainer 配置了无最大深度、每次分裂最少 6 个样本、以均方误差为分裂标准。随后,RandomForestTrainer 结合 10 棵 CART 决策树,并用 AveragingCombiner 平均预测结果。

train() 方法在 trainSet 数据集上训练模型,生成用于预测葡萄酒质量分数的 Model<Regressor>

8. 评估

接下来,使用 RegressionEvaluator 评估模型在数据集上的表现,计算相关指标:

RegressionEvaluator 用于评估模型在数据集上的表现。我们将 MAE(平均绝对误差)、RMSE(均方根误差)和 R^2(决定系数)输出到控制台。

随后,调用 evaluate() 方法评估模型和数据集:

执行程序后,训练集和测试集的评估结果如下:

MAE 表示预测值与实际值的绝对差异,RMSE 表示预测值与实际值的平方差均值的平方根,R^2 表示模型对训练和测试数据方差的解释能力。

更低的 MAERMSE,以及更高的 R^2,意味着模型预测性能更优。

9. 保存模型

最后,将模型保存为文件以便后续复用:

上述代码通过 ObjectOutputStream 类将训练好的模型序列化保存到文件。这样,我们可以在后续预测中直接复用模型,无需重新训练

10. 方法调用

现在,在 main() 方法中调用前面创建的方法:

编译代码后,模型会被保存到指定目录。

11. 使用模型

新建一个 WinePredictor 类,在 main() 方法中加载已保存的模型:

如前所述,Tribuo 对类型敏感,因此我们指定模型类型为 Regressor

通过创建 ObjectInputStream 并传入模型路径来加载模型。

然后,创建一个 ArrayExample 对象,表示单个葡萄酒样本:

最后,使用 Prediction 类进行预测:

预测结果如下:

12. 总结

在本文中,我们学习了 Tribuo 及其特性,了解了其支持的部分机器学习算法,并通过回归算法训练了葡萄酒质量预测模型。

]]>
Java Lambda 表达式的缺点和替代方案 https://java.didispace.com/article/20250603-java-lambdas-are-overrated-heres-what-i-use-instead.html https://java.didispace.com/article/20250603-java-lambdas-are-overrated-heres-what-i-use-instead.html Java Lambda 表达式的缺点和替代方案 Java Lambda 表达式的缺点和替代方案 Java 8 引入的 Lambda 表达式曾被誉为编写简洁、函数式代码的革命性工具。但说实话,它们并不是万能钥匙。它有不少问题,比如它没有宣传的那么易读,在某些场景下还带来性能开销。 作为一名多年与 Java 冗长语法搏斗的开发者,我找到了更注重清晰、可维护性和性能的替代方案。本文将剖析 Lambda 的不足,分享真实的基准测试,并展示我实际采用的方案:包括代码、图示和一些经验之谈。 Lambda 的热潮 当 Lambda 在 Java 8 中出现时,社区一片沸腾。可以编写内联函数、用流式操作链式处理、拥抱函数式编程令人兴奋。我们可以这样写代码: Java Tue, 03 Jun 2025 01:00:00 GMT Java Lambda 表达式的缺点和替代方案

Java 8 引入的 Lambda 表达式曾被誉为编写简洁、函数式代码的革命性工具。但说实话,它们并不是万能钥匙。它有不少问题,比如它没有宣传的那么易读,在某些场景下还带来性能开销。

作为一名多年与 Java 冗长语法搏斗的开发者,我找到了更注重清晰、可维护性和性能的替代方案。本文将剖析 Lambda 的不足,分享真实的基准测试,并展示我实际采用的方案:包括代码、图示和一些经验之谈。

Lambda 的热潮

当 Lambda 在 Java 8 中出现时,社区一片沸腾。可以编写内联函数、用流式操作链式处理、拥抱函数式编程令人兴奋。我们可以这样写代码:

看起来优雅、简洁、现代。但在生产中用多了,问题逐渐显现。它们并不总比传统循环更易读,调试流很痛苦,某些情况下性能损耗也不能忽视。让我们深入看看这些问题。

Lambda 的不足

1. 可读性受损

Lambda 主张让代码更简洁,但简洁不等于清晰。嵌套的 Lambda 或复杂的流操作很容易变成谜题。

比如下面这个例子:

乍一看,对比传统循环很难理解:

传统循环虽然啰嗦,但一目了然。每一步都很明确,新手或未来的你都能轻松理解和维护。

2. 调试噩梦

你试过调试流操作吗?

Lambda 的堆栈跟踪一团糟,经常指向 Java 内部类而不是你的代码。复杂链路中异常冒泡时,定位问题尤其困难。

3. 性能开销

Lambda 和流在某些场景下会因对象创建、装箱/拆箱带来额外开销。

我用 JMH(Java 微基准测试工具)做了对比,测试了用流和传统循环对一百万整数进行过滤和求和。

基准测试设置

测试代码如下:

结果

在 Intel i7–12700H + JDK 17 下,循环始终更快:

  • Stream :12.5 毫秒/次(±0.3 毫秒)
  • Loop :8.2 毫秒/次(±0.2 毫秒)

流式写法因 Lambda 实例化和流管道搭建带来额外开销,尤其在大数据集下更明显。虽然流在并行处理时有优势,但大多数实际场景并不需要,顺序处理时性能损失很明显。

性能对比结论:在顺序任务中,流落后于循环。

我的替代方案

经历了 Lambda 的种种问题后,我更倾向于混合方案: 简单操作用显式循环 , 需要函数式时用方法引用 , 复杂逻辑用自定义工具类 。以下是我的实践经验。

1. 简单任务用显式循环

对于简单任务,没有什么比循环更好。它们可读、易调试、性能好。比如最近一个项目中处理用户数据:

这种写法自解释,调试也方便。

2. 可复用性用方法引用

需要函数式风格时,我更喜欢方法引用而不是 Lambda。它更明确、可复用。

例如,与其写:

不如这样写:

这样简洁又清晰,还能复用已有方法,减少样板代码。

3. 复杂逻辑用自定义工具类

复杂操作时,我会写工具类和静态方法,逻辑封装好,测试也方便。比如过滤和转换订单:

用法:

这种方式模块化、易测试,避免了流操作的混乱。

架构图

为了直观展示无 Lambda 的代码结构,这里有一张手绘风格的架构图:

这种结构让业务逻辑清晰可维护,工具类作为应用层和数据层的桥梁。

何时用 Lambda

我不是说 Lambda 毫无用处。在下面这些场景,它们还是非常好用的:

  • 并行流 ,用于大数据集的 CPU 密集型任务;
  • 简单、一次性的转换 ,且不会影响可读性时;
  • 函数式接口 ,如 Comparator 或 Runnable。

但日常开发中,显式循环和工具类通常更具可读性、易调试、性能更好。毕竟开发者写代码不仅是给机器看,更是给人看。下一个读你代码的人(也可能是半年后的你)会感谢你选择了清晰而不是跟风。我见过团队为解读 Lambda 密集代码浪费数小时,也体会过调试流异常的痛苦。选择显式、模块化代码,让维护更轻松,团队士气更高。

总结

Java Lambda 曾被吹捧为革命,但其实利弊参半。它们简洁,却可能牺牲可读性、可调试性和性能。我更倾向于用显式循环、方法引用和自定义工具类,让代码更清晰、可维护、性能更优。基准测试不会说谎,易读的代码带来的轻松感也不会骗人。你觉得呢?欢迎评论区一起聊聊。

]]>
什么是 SootUp ? https://java.didispace.com/article/20250522-sootup.html https://java.didispace.com/article/20250522-sootup.html 什么是 SootUp ? 什么是 SootUp ? 1. 简介 在本文中,我们将介绍 SootUp 库。SootUp 是一个用于对 JVM 代码进行静态分析的库,可以分析原始源代码或已编译的 JVM 字节码。它是对 Soot 库的彻底重构,目标是更加模块化、可测试、可维护和易用。 2. 依赖 在使用 SootUp 之前,我们需要在构建中引入最新版本(截至撰写时为 1.3.0)。 &lt;dependency&gt; &lt;groupId&gt;org.soot-oss&lt;/groupId&gt; &lt;artifactId&gt;sootup.core&lt;/artifactId&gt; &lt;version&gt;1.3.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.soot-oss&lt;/groupId&gt; &lt;artifactId&gt;sootup.java.core&lt;/artifactId&gt; &lt;version&gt;1.3.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.soot-oss&lt;/groupId&gt; &lt;artifactId&gt;sootup.java.sourcecode&lt;/artifactId&gt; &lt;version&gt;1.3.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.soot-oss&lt;/groupId&gt; &lt;artifactId&gt;sootup.java.bytecode&lt;/artifactId&gt; &lt;version&gt;1.3.0&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.soot-oss&lt;/groupId&gt; &lt;artifactId&gt;sootup.jimple.parser&lt;/artifactId&gt; &lt;version&gt;1.3.0&lt;/version&gt; &lt;/dependency&gt; Java Thu, 22 May 2025 12:00:00 GMT 什么是 SootUp ?

1. 简介

在本文中,我们将介绍 SootUp 库。SootUp 是一个用于对 JVM 代码进行静态分析的库,可以分析原始源代码或已编译的 JVM 字节码。它是对 Soot 库的彻底重构,目标是更加模块化、可测试、可维护和易用。

2. 依赖

在使用 SootUp 之前,我们需要在构建中引入最新版本(截至撰写时为 1.3.0)。

我们这里有几个不同的依赖,它们的作用如下:

  • org.soot-uss:sootup.core 是核心库。
  • org.soot-uss:sootup.java.core 是用于 Java 的核心模块。
  • org.soot-uss:sootup.java.sourcecode 是用于分析 Java 源代码的模块。
  • org.soot-uss:sootup.java.bytecode 是用于分析已编译 Java 字节码的模块。
  • org.soot-uss:sootup.jimple.parser 是用于解析 Jimple(SootUp 用于表示 Java 的中间表示)的模块。

很遗憾,目前没有 BOM 依赖可用,因此我们需要单独管理这些依赖的版本。

3. 什么是 Jimple

SootUp 能够分析多种格式的代码,包括 Java 源代码、已编译的字节码,甚至 JVM 内部的类。

为此,它会将各种输入转换为一种名为 Jimple 的中间表示。

Jimple 的存在是为了以更易分析的方式,表达 Java 源代码或字节码能实现的所有功能。这意味着它在某些方面有意与原始输入不同。

JVM 字节码在访问某些值时采用基于栈的方式,这种方式对运行时非常高效,但对分析来说却很困难。Jimple 则将其转换为完全基于变量的方式,这样既能实现相同的功能,又更易于理解。

相反,Java 源代码虽然也是基于变量的,但其嵌套结构也让分析变得复杂。Jimple 会将其转换为扁平结构,便于工具分析。

Jimple 也可以作为一种我们可以直接读写的语言。例如,下面的 Java 源代码:

可以被写成如下 Jimple 代码:

虽然更为冗长,但功能完全一致。SootUp 提供了解析和生成 Jimple 代码的能力,便于我们在需要时以这种格式存储和转换代码。

无论原始代码来源如何,分析时都会被转换为这种结构。此时我们将操作如 SootClassSootFieldSootMethod 等类型,它们都直接对应这种中间表示。

4. 代码分析

在使用 SootUp 做任何事情之前,首先需要分析一些代码。这需要创建合适的 AnalysisInputLocation 实例,并基于它构建一个 JavaView

具体创建哪种 AnalysisInputLocation,取决于我们要分析的代码来源。

最简单但实际用处较少的方式,是分析 JVM 自身的类。可以通过 JrtFileSystemAnalysisInputLocation 类实现:

更常用的是分析源码文件,可以用 OTFCompileAnalysisInputLocation

它还支持一次分析多个源码文件:

也可以分析内存中的源码字符串:

最后,还可以分析已编译的字节码。通过 JavaClassPathAnalysisInputLocation,可指向任何 classpath(包括 JAR 包或 class 文件目录):

此外还有其他标准方式,如直接解析 Jimple 表示、读取 Android APK 文件等。

拿到 AnalysisInputLocation 实例后,可以基于它创建 JavaView

这样就能访问输入中的所有类型信息。

5. 访问类

在我们分析完代码并基于它构建了一个 JavaView 实例后,就可以开始访问代码的详细信息了,这首先从访问类开始。

如果我们已经知道要查找的具体类,可以直接通过全限定类名访问。SootUp 使用多种 Signature 类来描述我们想要访问的元素。在这里,我们需要一个 ClassType 实例。幸运的是,可以通过 SootUp 提供的 IdentifierFactory,利用全限定类名轻松生成:

构建好 ClassType 实例后,就可以用它来访问该类的详细信息:

也可以直接获取类,不存在时抛出异常:

拿到 SootClass 实例后,可以用它来检查类的各种属性,例如可见性、是否为具体类或抽象类等:

还可以遍历已解析的代码,比如访问父类或接口:

注意,这些方法返回的是 ClassType 而不是 SootClass 实例,因为无法保证这些类的定义一定在当前视图中,仅能获取它们的名称。

6. 访问字段和方法

除了类本身,还可以访问类的内容,比如字段和方法。

如果已经有了 SootClass 实例,可以直接查询其字段和方法:

与类之间的导航不同,这里可以安全地返回字段或方法的完整表示,因为它们一定在当前视图中。

如果已知具体字段名,可以直接访问字段:

访问方法稍微复杂一些,需要方法名和参数类型:

如果方法有参数,需要通过 IdentifierFactory 提供参数类型的 Type 实例:

这样可以在有重载方法时获取正确的实例。还可以列出所有同名重载方法:

同样,拿到 SootMethodSootField 实例后,可以进一步检查其属性:

7. 分析方法体

拿到 SootMethod 实例后,可以分析方法体本身,包括方法签名、局部变量和调用图。

首先需要获取方法体:

有了方法体后,就可以访问方法体的所有细节。

7.1 访问局部变量

首先可以访问方法内所有可用的局部变量:

这会返回方法内所有可访问的变量。需要注意,这实际上是 Jimple 表示中的变量列表,因此会包含一些解析过程中生成的额外变量,且变量名可能与原始代码不同。

例如,下面的方法有 5 个局部变量:

这些变量包括:

  • this
  • I1 —— 方法参数
  • I2 —— 变量“capitals”
  • $stack3 —— 指向 System.out 的局部变量
  • $stack4 —— 表示“Hello, ” + capitals 的局部变量

其中 $stack3$stack4 是 Jimple 生成的,并不直接出现在原始代码中。

7.2 访问方法语句图

除了局部变量,还可以分析整个方法的语句图,即方法将执行的每条语句的详细信息:

这样可以获得方法将要执行的所有语句,顺序与实际执行一致。每个语句都实现了 Stmt 接口,代表方法可以执行的操作。

例如,前面的方法会生成如下结构:

sootup callgraph

看起来比我们实际写的代码多很多——实际上只有两行。这是因为这里展示的是 Jimple 的表示。我们可以逐步拆解其含义:

首先有两个 JIdentityStmt,分别代表传入方法的 thisI1(即第一个参数)。

接下来有三个 JAssignStmt,分别表示对变量的赋值:将 I1.toUpperCase() 的结果赋给 I2,将 System.out 赋给 $stack3,将“Hello, ” + I2 的结果赋给 $stack4

之后是一个 JInvokeStmt,表示在 $stack3 上调用 println() 方法,并传入 $stack4

最后是一个 JReturnVoidStmt,代表方法末尾的隐式返回。

这是一个没有分支和控制语句的简单方法,但可以清楚看到方法执行的每一步。对于 Java 应用中的任何操作,Jimple 都能完整表示。

8. 总结

本文简要介绍了 SootUp。这个库还有很多强大的功能等待探索。下次需要分析 Java 代码时,不妨试试 SootUp 吧!

感谢阅读!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!

]]>
什么是 ActiveJ ? https://java.didispace.com/article/20250521-activej.html https://java.didispace.com/article/20250521-activej.html 什么是 ActiveJ ? 什么是 ActiveJ ? 1. 简介 ActiveJ 是一个轻量级的 Java 框架,适用于高性能应用。我们可以用它来创建启动速度快、内存占用小的极简和模块化应用。它提供了异步 I/O、依赖注入、高效序列化和响应式编程支持等特性。 在本教程中,我们将讨论 ActiveJ 的主要特性,包括其 Inspect 模块、强大的事件循环和高级网络功能。 2. 注入 Java Thu, 22 May 2025 01:00:00 GMT 什么是 ActiveJ ?

1. 简介

ActiveJ 是一个轻量级的 Java 框架,适用于高性能应用。我们可以用它来创建启动速度快、内存占用小的极简和模块化应用。它提供了异步 I/O、依赖注入、高效序列化和响应式编程支持等特性。

在本教程中,我们将讨论 ActiveJ 的主要特性,包括其 Inspect 模块、强大的事件循环和高级网络功能。

2. 注入

我们从 ActiveJ Inject 开始。它是一个轻量且性能优化的依赖注入库,可用于设置 bean 之间的依赖关系。让我们看看如何使用它。

2.1. 依赖

让我们将 Active Inject 依赖 添加到项目中:

2.2. 使用模块进行依赖注入

让我们创建一个仓库 bean:

在我们的 PersonRepository 中,只指定了对 DataSource 实例的依赖。现在让我们创建一个服务类:

PersonService 类中,我们指定了对 PersonRepository 的依赖。

接下来,让我们创建一个 PersonModule 类,在其中配置所有 bean 之间的关系:

我们继承了 AbstractModule 类。此外,我们提供了 PersonServicePersonRepositoryDataSource 的 bean,并配置了它们之间的关系。

让我们测试依赖注入行为:

我们创建了PersonModule类的实例。然后,使用Injector获取了PersonService实例。可以看到,所有依赖都已被注入。

3. 异步 I/O

**ActiveJ Async I/O 提供了高效编写异步流程的组件。**我们将通过 PromisesEvent Loop 等关键元素来理解这一特性。

3.1. 依赖

让我们添加activej-promise依赖:

3.2. Promise

让我们创建要用到的模型:

现在,给PersonRepository类添加一些逻辑:

我们添加了findPerson()方法,用于模拟按名称查找的过程。我们使用Promises.delay()延迟生成Person实例,结果被包装为Promise实例。

接下来,创建服务层要生成的另一个模型:

VerifiedPerson包含了人员信息和验证结果。

PersonService类中添加业务逻辑:

findPersonNotes()方法中,我们模拟获取人员备注的过程。结果同样用Promise.of()包装。

接下来,添加验证方法:

这里我们模拟了验证流程,根据人员描述添加验证结果。

最后,整合所有操作,完成流程:

在最终方法中,我们通过Promise类的combine()方法,将仓库的findPerson()和服务的findPersonNotes()两个 promise 合并。然后对模型进行验证,返回最终结果的`Promise_。

3.3. 事件循环

**ActiveJ 的 Eventloop 在事件循环和线程中异步执行代码。**让我们看看如何用它来运行基于Promise的流程:

我们从PersonModule获取了PersonService_。然后用Eventloop.create()创建事件循环实例,并用run()方法启动。接着调用findAndVerifyPerson()方法。如果漏掉run()_,此时会遇到如下异常:

4. HTTP 服务器

ActiveJ 的另一个强大特性是高性能异步 HTTP 服务器

4.1. 依赖

首先添加 ActiveJ HTTP 依赖:

再添加 Jackson Databind 依赖:

4.2. REST 接口示例

现在,让我们通过 HTTP 接口暴露VerifiedPerson流程。首先是PersonController类:

这里我们实现了AsyncServlet接口并重写了serve()方法。在方法内部,获取PersonServicefindAndVerifyPerson()结果。然后将其转为 JSON 并作为 HTTP 响应体返回,状态码为 200。异常情况单独映射,默认返回 500 状态码。

将该控制器加入依赖注入上下文:

我们将PersonController加入PersonModule并配置了其依赖。

最后,引入 HTTP 服务器代码:

我们完成了HttpServer实例的搭建。然后用 RoutingServlet 添加了 HTTP 路由映射。最后用listen()方法启动服务器,并准备了异步 HTTP 客户端。

现在调用接口并检查结果:

我们调用了接口并异步获取了预期结果。为了在测试后停止服务器,调用了EventloopbreakEventloop()方法终止执行。

5. 总结

本文介绍了 ActiveJ 框架的关键特性。借助这些特性,我们已经可以构建高效轻量的 Web 应用。当然,该框架还远不止于此。

我们还可以用它进行数据处理、分布式系统等多种场景。其模块化特性帮助我们避免项目臃肿,只引入必要组件。

感谢阅读!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!

]]>
扔了Lombok吧!MapStruct + Records才是正解! https://java.didispace.com/article/20250516-lombok-mapstruts-records.html https://java.didispace.com/article/20250516-lombok-mapstruts-records.html 扔了Lombok吧!MapStruct + Records才是正解! 扔了Lombok吧!MapStruct + Records才是正解! Lombok作为一个广受欢迎的Java开发工具,通过注解的方式帮助我们消除样板代码,提升开发效率。但随着项目的发展,它也带来了一些令人困扰的问题: 🧙‍♂️ Lombok的问题 代码可读性差 - 大量使用@Data、@Builder等注解后,实际生成的代码变得不可见,增加了代码审查和维护的难度 IDE支持不稳定 - 与IDE的集成经常出现问题,导致代码提示失效、编辑器卡顿等问题 运行时行为不可控 - 注解自动生成的方法(如equals、hashCode)可能产生意外的运行时行为 调试困难 - 由于代码是在编译时生成的,调试过程中难以追踪具体实现 Java Fri, 16 May 2025 15:00:00 GMT 扔了Lombok吧!MapStruct + Records才是正解!

Lombok作为一个广受欢迎的Java开发工具,通过注解的方式帮助我们消除样板代码,提升开发效率。但随着项目的发展,它也带来了一些令人困扰的问题:

🧙‍♂️ Lombok的问题

  • 代码可读性差 - 大量使用@Data@Builder等注解后,实际生成的代码变得不可见,增加了代码审查和维护的难度
  • IDE支持不稳定 - 与IDE的集成经常出现问题,导致代码提示失效、编辑器卡顿等问题
  • 运行时行为不可控 - 注解自动生成的方法(如equals、hashCode)可能产生意外的运行时行为
  • 调试困难 - 由于代码是在编译时生成的,调试过程中难以追踪具体实现

这些问题导致团队在开发过程中经常遇到困惑:"这个getter是从哪里来的?"、"为什么equals方法会这样实现?"。虽然表面上代码看起来简洁,但实际上增加了项目的维护成本。

🚪 是时候和 Lombok 分手了

有一天,我们决定移除Lombok! 然后,我们做了一个实验:

  1. 用Java Records替换 @Data
  2. 用真正的构造函数替换 @Builder
  3. MapStruct 替换那些笨重的 ModelMapper/Lombok DTO 组合。

结果怎样?一切都变好了!

🧾 为什么 Java Records > Lombok @Data

Lombok:

对比

Java Records:

哪一个更具可读性?更类型安全?更适合不变性?

Records:

  • 默认是 final 且不可变的。
  • 生成构造函数、equalshashCodetoString——所有这些都是可见的。
  • 与 IDE 和序列化工具配合良好。

额外好处:你不需要仅仅为了写一个有两个字段的类就引入一个外部依赖。

🎯 MapStruct:真正的映射,而非猜测

现在介绍另一位英雄:MapStruct

我们曾经有这样的类:

然后是:

优雅,对吧?直到它不再优雅。

  • 字段无声无息地停止了映射。
  • 调试变成了一场猜谜游戏。
  • 嵌套映射变成了噩梦。

使用 MapStruct,我们这样做:

编译时检查。清晰。明确。快速。

没有反射,没有运行时意外。只有可预测、可读、真正的映射。

🎁 我们获得了什么?

  • 减少了 80% 的样板代码。 真的。
  • 零 IDE 问题。 再也没有奇怪的自动补全 bug。
  • 更好的入职体验。 新来的开发者不需要 Lombok 解码器。
  • 编译时安全。 在映射错误在生产环境中造成麻烦之前就捕捉到它们。

🧠 最后的思考

Lombok 在它那个时代是很出色的,但是 Java 在不断进化了,是时候抛弃它了!

  • 用 Records 替换 @Data
  • 放弃 @Builder 并使用构造函数(如果需要,可以使用 MapStruct 的构建器)。
  • 用 MapStruct 替换 ModelMapper

你将会编写更少的注解,调试更少的 Bug,并最终真正地 掌控你自己的代码,然后睡个好觉,获得更多的头发!

]]>
Java并发编程:ThreadGroup的activeCount()方法 https://java.didispace.com/java-multithreading/4-1-threadgroup-activecount.html https://java.didispace.com/java-multithreading/4-1-threadgroup-activecount.html Java并发编程:ThreadGroup的activeCount()方法 Java并发编程:ThreadGroup的activeCount()方法 在Java中,ThreadGroup.activeCount()方法用于返回线程组及其子组中活动线程的估计数量。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 activeCount()方法语法 理解activeCount() 示例 基本用法 结合子组使用activeCount() 实际应用案例 结论 Java Thu, 20 Mar 2025 10:00:00 GMT Java并发编程:ThreadGroup的activeCount()方法

在Java中,ThreadGroup.activeCount()方法用于返回线程组及其子组中活动线程的估计数量。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  • 引言
  • activeCount()方法语法
  • 理解activeCount()
  • 示例
    • 基本用法
    • 结合子组使用activeCount()
    • 实际应用案例
  • 结论

引言

ThreadGroup.activeCount()方法可提供线程组及其任何子组中活动线程数量的估计值。这对于监控和管理应用程序中的线程活动很有用。

activeCount()方法语法

activeCount()方法的语法如下:

  • 参数:此方法不接受任何参数。
  • 返回值:线程组及其子组中活动线程的估计数量。

理解activeCount()

activeCount()方法返回的是估计值而非确切数量,因为线程数量会随着线程的启动和结束动态变化。该方法统计的线程包括当前线程组中的活动线程以及其任何子组中的线程。

示例

基本用法

为展示activeCount()的基本用法,我们创建一个简单示例,在一个线程组中添加多个线程,并获取活动线程的数量。

输出

结合子组使用activeCount()

你也可以使用activeCount()方法统计包括子组中的线程。

输出

实际应用案例:监控线程活动

在一个包含多个线程组的大型应用程序中,你可以使用ThreadGroup.activeCount()方法来监控和管理线程活动,确保资源得到有效利用,并识别线程使用中可能存在的问题。

输出

结论

Java中的ThreadGroup.activeCount()方法提供了线程组及其子组中活动线程数量的估计值。通过使用此方法,你可以监控线程活动、有效管理资源,并识别线程使用中可能存在的问题。无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.activeCount()方法都为管理和监控线程特定数据提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的activeGroupCount()方法 https://java.didispace.com/java-multithreading/4-2-threadgroup-activegroupcount.html https://java.didispace.com/java-multithreading/4-2-threadgroup-activegroupcount.html Java并发编程:ThreadGroup的activeGroupCount()方法 Java并发编程:ThreadGroup的activeGroupCount()方法 在Java中,ThreadGroup.activeGroupCount()方法用于返回线程组中活动子组的估计数量。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 activeGroupCount()方法语法 理解activeGroupCount() 示例 基本用法 结合嵌套组使用activeGroupCount() 实际应用案例 结论 Java Thu, 20 Mar 2025 13:00:00 GMT Java并发编程:ThreadGroup的activeGroupCount()方法

在Java中,ThreadGroup.activeGroupCount()方法用于返回线程组中活动子组的估计数量。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  • 引言
  • activeGroupCount()方法语法
  • 理解activeGroupCount()
  • 示例
    • 基本用法
    • 结合嵌套组使用activeGroupCount()
    • 实际应用案例
  • 结论

引言

ThreadGroup.activeGroupCount()方法可提供线程组内活动子组数量的估计值。这对于监控和管理应用程序中的线程组层次结构很有用。

activeGroupCount()方法语法

activeGroupCount()方法的语法如下:

  • 参数:此方法不接受任何参数。
  • 返回值:线程组中活动子组的估计数量。

理解activeGroupCount()

activeGroupCount()方法返回的是估计值而非确切数量,因为线程组的数量会随着线程组的创建和销毁动态变化。该方法统计的子组包括当前线程组中的活动子组以及这些子组内的任何子组。

示例

基本用法

为展示activeGroupCount()的基本用法,我们创建一个简单示例,在一个线程组中添加多个子组,并获取活动子组的数量。

输出

结合嵌套组使用activeGroupCount()

你也可以使用activeGroupCount()方法统计包括嵌套组在内的子组数量。

输出

实际应用案例:监控线程组层次结构

在一个包含多个线程组层次结构的大型应用程序中,你可以使用ThreadGroup.activeGroupCount()方法来监控和管理活动子组的数量,确保资源得到有效利用,并识别线程组管理中可能存在的问题。

输出

结论

Java中的ThreadGroup.activeGroupCount()方法提供了线程组中活动子组数量的估计值。通过使用此方法,你可以监控线程组层次结构、有效管理资源,并识别线程组管理中可能存在的问题。

无论你处理的是简单的线程组还是复杂的嵌套线程组结构,ThreadGroup.activeGroupCount()方法都为管理和监控线程组数据提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的enumerate() 方法 https://java.didispace.com/java-multithreading/4-3-threadgroup-enumerate.html https://java.didispace.com/java-multithreading/4-3-threadgroup-enumerate.html Java并发编程:ThreadGroup的enumerate() 方法 Java并发编程:ThreadGroup的enumerate() 方法 在Java中,ThreadGroup.enumerate()方法用于将线程组及其子组中的每个活动线程复制到指定的数组中。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 enumerate(Thread[] list)方法语法 理解enumerate(Thread[] list) 示例 基本用法 结合子组使用enumerate(Thread[] list) 实际应用案例 结论 Java Fri, 21 Mar 2025 11:00:00 GMT Java并发编程:ThreadGroup的enumerate() 方法

在Java中,ThreadGroup.enumerate()方法用于将线程组及其子组中的每个活动线程复制到指定的数组中。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  • 引言
  • enumerate(Thread[] list)方法语法
  • 理解enumerate(Thread[] list)
  • 示例
    • 基本用法
    • 结合子组使用enumerate(Thread[] list)
    • 实际应用案例
  • 结论

引言

ThreadGroup.enumerate(Thread[] list)方法将线程组及其子组中每个活动线程的引用复制到指定的数组中。该方法对于监控和管理应用程序中的线程很有用。

enumerate(Thread[] list)方法语法

enumerate(Thread[] list)方法的语法如下:

  • 参数list:要将活动线程复制到的数组。
  • 返回值: 放入数组中的线程数量。

理解enumerate(Thread[] list)

enumerate(Thread[] list)方法将线程组及其子组中每个活动线程的引用复制到指定的数组中。如果数组太小,无法容纳所有线程,多余的线程将被默默忽略。该方法提供了线程组在特定时间点的快照。

示例

基本用法

为展示enumerate(Thread[] list)的基本用法,我们创建一个简单示例,在一个线程组中添加多个线程,并将活动线程枚举到一个数组中。

输出

结合子组使用enumerate(Thread[] list)

你也可以使用enumerate(Thread[] list)方法包含子组中的线程。

输出

实际应用案例:监控和管理线程

在一个包含多个线程组的大型应用程序中,你可以使用ThreadGroup.enumerate(Thread[] list)方法来监控和管理活动线程,确保资源得到有效利用,并识别线程使用中可能存在的问题。

输出

结论

Java中的ThreadGroup.enumerate(Thread[] list)方法提供了一种将线程组及其子组中每个活动线程的引用复制到指定数组的方式。通过使用此方法,你可以监控线程活动、有效管理资源,并识别线程使用中可能存在的问题。无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.enumerate(Thread[] list)方法都为管理和监控线程特定数据提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的getMaxPriority() 方法 https://java.didispace.com/java-multithreading/4-4-threadgroup-getmaxpriority.html https://java.didispace.com/java-multithreading/4-4-threadgroup-getmaxpriority.html Java并发编程:ThreadGroup的getMaxPriority() 方法 Java并发编程:ThreadGroup的getMaxPriority() 方法 在Java中,ThreadGroup.getMaxPriority()方法用于返回线程组的最大优先级。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 getMaxPriority()方法语法 理解getMaxPriority() 示例 基本用法 结合子组使用getMaxPriority() 实际应用案例 结论 Java Fri, 21 Mar 2025 15:00:00 GMT Java并发编程:ThreadGroup的getMaxPriority() 方法

在Java中,ThreadGroup.getMaxPriority()方法用于返回线程组的最大优先级。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  • 引言
  • getMaxPriority()方法语法
  • 理解getMaxPriority()
  • 示例
    • 基本用法
    • 结合子组使用getMaxPriority()
    • 实际应用案例
  • 结论

引言

ThreadGroup.getMaxPriority()方法用于获取线程组中线程能够拥有的最大优先级。该方法在管理和控制应用程序内的线程优先级方面非常有用。

getMaxPriority()方法语法

getMaxPriority()方法的语法如下:

  • 参数:此方法不接受任何参数。
  • 返回值:线程组的最大优先级。

理解getMaxPriority()

getMaxPriority()方法返回线程组中线程可以拥有的最大优先级。这个值在创建线程组时被设定,并且可以使用setMaxPriority()方法进行更改。线程组的最大优先级限制了该组内线程可以被分配的优先级。

示例

基本用法

为展示getMaxPriority()的基本用法,我们创建一个简单示例,获取线程组的最大优先级。

输出

结合子组使用getMaxPriority()

你也可以使用getMaxPriority()方法来获取子组的最大优先级。

输出

更改并获取最大优先级

你可以更改线程组的最大优先级,然后使用getMaxPriority()方法获取它。

输出

实际应用案例:在多线程应用程序中控制线程优先级

在一个包含多个线程的大型应用程序中,你可以使用ThreadGroup.getMaxPriority()来控制和管理不同线程组内线程的优先级,确保关键线程获得更高优先级,不太重要的线程获得较低优先级。

输出

结论

Java中的ThreadGroup.getMaxPriority()方法提供了一种获取线程组中线程最大优先级的方式。通过使用此方法,你可以在应用程序中管理和控制线程优先级,确保根据线程的重要性为其分配适当的优先级。

无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.getMaxPriority()方法都为管理和监控线程优先级提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的getName()方法 https://java.didispace.com/java-multithreading/4-5-threadgroup-getname.html https://java.didispace.com/java-multithreading/4-5-threadgroup-getname.html Java并发编程:ThreadGroup的getName()方法 Java并发编程:ThreadGroup的getName()方法 在Java中,ThreadGroup.getName()方法用于返回线程组的名称。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 getName()方法语法 理解getName() 示例 基本用法 结合子组使用getName() 实际应用案例 结论 Java Sat, 22 Mar 2025 13:00:00 GMT Java并发编程:ThreadGroup的getName()方法

在Java中,ThreadGroup.getName()方法用于返回线程组的名称。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. getName()方法语法
  3. 理解getName()
  4. 示例
    • 基本用法
    • 结合子组使用getName()
    • 实际应用案例
  5. 结论

引言

ThreadGroup.getName()方法会返回线程组的名称。这在识别和管理应用程序中的线程组时非常有用。

getName()方法语法

getName()方法的语法如下:

  • 参数:该方法不接受任何参数。
  • 返回值:线程组的名称。

理解getName()

getName()方法返回创建线程组时赋予它的名称。这个名称可用于识别线程组,尤其是在调试或监控线程活动时。

示例

基本用法

为展示getName()的基本用法,我们创建一个简单示例,获取线程组的名称。

输出

结合子组使用getName()

你也可以使用getName()方法来获取子组的名称。

输出

实际应用案例:在多线程应用程序中识别线程组

在一个包含多个线程和线程组的大型应用程序中,你可以使用ThreadGroup.getName()来识别和管理线程组,这会让监控和控制线程活动变得更加容易。

输出

结论

Java中的ThreadGroup.getName()方法提供了一种获取线程组名称的方式。通过使用该方法,你可以在应用程序中识别和管理线程组,从而更轻松地监控和控制线程活动。

无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.getName()方法都为管理和识别线程组提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的getParent() 方法 https://java.didispace.com/java-multithreading/4-6-threadgroup-getparent.html https://java.didispace.com/java-multithreading/4-6-threadgroup-getparent.html Java并发编程:ThreadGroup的getParent() 方法 Java并发编程:ThreadGroup的getParent() 方法 在Java中,ThreadGroup.getParent()方法用于返回当前线程组的父线程组。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 getParent()方法语法 理解getParent() 示例 基本用法 结合嵌套组使用getParent() 实际应用案例 结论 Java Sat, 22 Mar 2025 14:00:00 GMT Java并发编程:ThreadGroup的getParent() 方法

在Java中,ThreadGroup.getParent()方法用于返回当前线程组的父线程组。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  • 引言
  • getParent()方法语法
  • 理解getParent()
  • 示例
    • 基本用法
    • 结合嵌套组使用getParent()
    • 实际应用案例
  • 结论

引言

ThreadGroup.getParent()方法返回当前线程组的父线程组。这有助于理解应用程序中线程组的层次结构和组织方式。

getParent()方法语法

getParent()方法的语法如下:

  • 参数:此方法不接受任何参数。
  • 返回值:该线程组的父线程组;如果该线程组没有父线程组,则返回null

理解getParent()

getParent()方法返回当前线程组的父线程组。线程组可以组织成一个层次结构,除了根线程组外,每个线程组都有一个父线程组。这种层次结构有助于高效地管理和组织线程。

示例

基本用法

为展示getParent()的基本用法,我们创建一个简单示例,获取线程组的父线程组。

输出

结合嵌套组使用getParent()

你也可以使用getParent()方法来获取嵌套线程组的父线程组。

输出

实际应用案例:在多线程应用程序中管理线程组层次结构

在一个包含多个线程和线程组的大型应用程序中,你可以使用ThreadGroup.getParent()方法来理解和管理线程组的层次结构。这在调试和监控复杂线程组结构中的线程活动时特别有用。

输出

结论

Java中的ThreadGroup.getParent()方法提供了一种获取线程组父线程组的方式。通过使用此方法,你可以理解和管理应用程序中线程组的层次结构,从而更轻松地监控和控制线程活动。

无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.getParent()方法都为管理和理解线程组结构提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的interrupt()方法 https://java.didispace.com/java-multithreading/4-7-threadgroup-interrupt.html https://java.didispace.com/java-multithreading/4-7-threadgroup-interrupt.html Java并发编程:ThreadGroup的interrupt()方法 Java并发编程:ThreadGroup的interrupt()方法 在Java中,ThreadGroup.interrupt()方法用于中断线程组中的所有线程。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 interrupt()方法语法 理解interrupt() 示例 基本用法 结合子组使用interrupt() 实际应用案例 结论 Java Sat, 22 Mar 2025 15:00:00 GMT Java并发编程:ThreadGroup的interrupt()方法

在Java中,ThreadGroup.interrupt()方法用于中断线程组中的所有线程。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. interrupt()方法语法
  3. 理解interrupt()
  4. 示例
    • 基本用法
    • 结合子组使用interrupt()
    • 实际应用案例
  5. 结论

引言

ThreadGroup.interrupt()方法用于中断线程组及其子组中的所有线程。这在需要同时停止一组线程时非常有用。

interrupt()方法语法

interrupt()方法的语法如下:

  • 参数:该方法不接受任何参数。
  • 返回值:该方法不返回任何值。

理解interrupt()

interrupt()方法会遍历线程组及其子组中的所有活动线程,并对每个线程调用interrupt()。该方法不会中断非活动状态的线程。

示例

基本用法

为展示interrupt()的基本用法,我们创建一个简单示例,在一个线程组中添加多个线程,然后中断该线程组。

输出

结合子组使用interrupt()

你也可以使用interrupt()方法来中断嵌套组中的线程。

输出

实际应用案例:优雅停止一组工作线程

在多线程应用程序中,可能会有一组工作线程执行任务。使用ThreadGroup.interrupt(),当满足特定条件或应用程序关闭时,你可以优雅地停止所有工作线程。

输出

结论

Java中的ThreadGroup.interrupt()方法提供了一种中断线程组及其子组中所有线程的方式。通过使用该方法,你可以高效地管理和控制线程的执行,确保在需要时可以优雅地停止线程组。无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.interrupt()方法都为管理线程执行提供了可靠的工具。

]]>
Java并发编程:ThreadGroup的list()方法 https://java.didispace.com/java-multithreading/4-8-threadgroup-list.html https://java.didispace.com/java-multithreading/4-8-threadgroup-list.html Java并发编程:ThreadGroup的list()方法 Java并发编程:ThreadGroup的list()方法 在Java中,ThreadGroup.list()方法用于将线程组的相关信息打印到标准输出。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。 目录 引言 list()方法语法 理解list() 示例 基本用法 结合子组使用list() 实际应用案例 结论 Java Sat, 22 Mar 2025 16:00:00 GMT Java并发编程:ThreadGroup的list()方法

在Java中,ThreadGroup.list()方法用于将线程组的相关信息打印到标准输出。本指南将介绍该方法的用法,解释其工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. list()方法语法
  3. 理解list()
  4. 示例
    • 基本用法
    • 结合子组使用list()
    • 实际应用案例
  5. 结论

引言

ThreadGroup.list()方法将线程组的相关信息打印到标准输出。这些信息包括线程组及其子组中所有活动线程的详细信息,主要用于调试目的。

list()方法语法

list()方法的语法如下:

  • 参数:该方法不接受任何参数。
  • 返回值:该方法不返回任何值。

理解list()

list()方法会打印当前线程组及其子组的相关信息,包括:

  • 线程组的名称
  • 线程组的最大优先级
  • 线程组是否为守护线程组
  • 线程组中的活动线程列表
  • 活动子组列表

示例

基本用法

为展示list()的基本用法,我们创建一个简单示例,在一个线程组中添加多个线程,然后打印该线程组的信息。

输出

结合子组使用list()

你也可以使用list()方法来打印嵌套线程组的信息。

输出

实际应用案例:调试线程组活动

在多线程应用程序中,你可能需要调试和监控线程及线程组的活动。使用ThreadGroup.list(),你可以打印线程组及其线程的状态,这有助于识别问题并理解线程的组织方式。

输出

结论

Java中的ThreadGroup.list()方法提供了一种将线程组及其子组的信息打印到标准输出的方式。通过使用该方法,你可以调试和监控线程活动,从而更轻松地理解应用程序中线程的组织和状态。

无论你处理的是简单的线程组还是复杂的线程层次结构,ThreadGroup.list()方法都为管理和识别线程组提供了可靠的工具。

]]>
Java并发编程:ThreadLocal的get方法详解 https://java.didispace.com/java-multithreading/3-1-threadlocal-get.html https://java.didispace.com/java-multithreading/3-1-threadlocal-get.html Java并发编程:ThreadLocal的get方法详解 Java并发编程:ThreadLocal的get方法详解 在 Java 里,ThreadLocal.get() 方法主要用于提供线程局部变量。每个访问该变量的线程都有其独立初始化的变量副本。本指南会详细介绍该方法的使用方式、工作原理,并且通过示例来展示它的功能。 目录 引言 get() 方法语法 理解 get() 方法 示例演示 基础使用 多线程环境下的 get() 实际应用场景 总结 Java Wed, 19 Mar 2025 11:00:00 GMT Java并发编程:ThreadLocal的get方法详解

在 Java 里,ThreadLocal.get() 方法主要用于提供线程局部变量。每个访问该变量的线程都有其独立初始化的变量副本。本指南会详细介绍该方法的使用方式、工作原理,并且通过示例来展示它的功能。

目录

  1. 引言
  2. get() 方法语法
  3. 理解 get() 方法
  4. 示例演示
    • 基础使用
    • 多线程环境下的 get()
    • 实际应用场景
  5. 总结

1. 引言

ThreadLocal.get() 方法能够返回当前线程在这个线程局部变量中的值。它主要用于为每个线程维护一个独立的值,这样可以避免同步问题,确保线程安全。

2. get() 方法语法

get() 方法的语法如下:

返回值:当前线程在该线程局部变量中的值。

3. 理解 get() 方法

ThreadLocal.get() 方法会获取当前线程与特定 ThreadLocal 实例相关联的值。每个线程都有自己的线程局部变量副本,而 get() 方法就是返回当前线程的这个变量值。

4. 示例演示

基础使用

下面通过一个简单的例子来展示 get() 方法的基础用法,在这个例子中,每个线程都有自己唯一的值。

输出结果

多线程环境下的 get()

可以在多线程中使用 get() 方法,为每个线程维护不同的值。

输出结果(示例):

实际应用场景:在 Web 应用中存储用户信息

在 Web 应用里,可以利用 ThreadLocal 为不同线程处理的每个请求存储用户特定信息。

输出结果

5. 总结

Java 中的 ThreadLocal.get() 方法可以创建和获取线程局部变量。使用这个方法,能够确保每个线程维护自己的变量副本,从而提升线程安全性,避免同步问题。不管是处理简单的线程局部变量,还是处理 Web 应用中复杂的用户特定信息,ThreadLocal.get() 方法都为管理线程特定数据提供了一种可靠的方式。

]]>
Java并发编程:ThreadLocal的initialValue方法详解 https://java.didispace.com/java-multithreading/3-2-threadlocal-initialvalue.html https://java.didispace.com/java-multithreading/3-2-threadlocal-initialvalue.html Java并发编程:ThreadLocal的initialValue方法详解 Java并发编程:ThreadLocal的initialValue方法详解 在 Java 中,ThreadLocal.initialValue() 方法用于设置线程局部变量的初始值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。 目录 引言 initialValue() 方法语法 理解 initialValue() 示例演示 基础使用 不同初始值的 initialValue() 实际应用场景 总结 Java Wed, 19 Mar 2025 13:00:00 GMT Java并发编程:ThreadLocal的initialValue方法详解

在 Java 中,ThreadLocal.initialValue() 方法用于设置线程局部变量的初始值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. initialValue() 方法语法
  3. 理解 initialValue()
  4. 示例演示
    • 基础使用
    • 不同初始值的 initialValue()
    • 实际应用场景
  5. 总结

1. 引言

ThreadLocal.initialValue() 方法用于返回当前线程在该线程局部变量中的初始值。该方法可被重写,从而为每个线程提供自定义的初始值。

2. initialValue() 方法语法

initialValue() 方法的语法如下:

返回值:当前线程在该线程局部变量中的初始值。

3. 理解 initialValue()

initialValue() 方法设计为供子类重写。默认情况下,它返回 null。当线程首次访问线程局部变量时,会调用 initialValue() 方法为该线程设置初始值。

4. 示例演示

基础使用

通过以下示例展示 initialValue() 的基础用法,每个线程将获得相同的初始值。

输出结果

不同初始值的 initialValue()

可以通过 initialValue() 方法为每个线程提供不同的初始值。

输出结果(示例):

实际应用场景:存储用户会话信息

在 Web 应用中,可以利用 ThreadLocal 为不同线程处理的每个请求存储用户会话信息。

输出结果

5. 总结

Java 中的 ThreadLocal.initialValue() 方法允许为线程局部变量初始化自定义值。通过重写该方法,可以确保每个线程拥有唯一的初始值,从而提升线程安全性,避免同步问题。无论是处理简单的线程局部变量,还是 Web 应用中复杂的用户特定信息,ThreadLocal.initialValue() 方法都为管理线程特定数据提供了可靠的解决方案。

]]>
Java并发编程:ThreadLocal的remove方法详解 https://java.didispace.com/java-multithreading/3-3-threadlocal-remove.html https://java.didispace.com/java-multithreading/3-3-threadlocal-remove.html Java并发编程:ThreadLocal的remove方法详解 Java并发编程:ThreadLocal的remove方法详解 在 Java 中,ThreadLocal.remove() 方法用于移除当前线程在线程局部变量中的值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。 目录 引言 remove() 方法语法 理解 remove() 示例演示 基础使用 多线程环境下的 remove() 实际应用场景 总结 Java Wed, 19 Mar 2025 15:00:00 GMT Java并发编程:ThreadLocal的remove方法详解

在 Java 中,ThreadLocal.remove() 方法用于移除当前线程在线程局部变量中的值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. remove() 方法语法
  3. 理解 remove()
  4. 示例演示
    • 基础使用
    • 多线程环境下的 remove()
    • 实际应用场景
  5. 总结

1. 引言

ThreadLocal.remove() 方法用于移除当前线程在线程局部变量中的值,确保该线程的线程局部变量被重置。这有助于防止内存泄漏并保证资源的正确管理。

2. remove() 方法语法

remove() 方法的语法如下:

参数:该方法不接受任何参数。
返回值:该方法不返回任何值。

3. 理解 remove()

ThreadLocal.remove() 方法用于移除当前线程与特定 ThreadLocal 实例相关联的值。调用 remove() 后,线程下次访问该线程局部变量时,它将被重新初始化为初始值;如果未设置初始值,则为 null

4. 示例演示

基础使用

以下示例展示 remove() 方法的基础用法,每个线程设置并移除其线程局部变量的值。

输出结果

多线程环境下的 remove()

可以在多线程中使用 remove() 方法,确保每个线程的值被独立移除。

输出结果(示例):

实际应用场景:清理 Web 应用中的资源

在 Web 应用中,可以使用 ThreadLocal.remove() 在请求处理完成后清理与用户会话相关的资源,防止内存泄漏。

输出结果

5. 总结

Java 中的 ThreadLocal.remove() 方法允许移除当前线程在线程局部变量中的值。通过使用该方法,可以防止内存泄漏并确保应用程序中的资源正确管理。无论是处理简单的线程局部变量,还是 Web 应用中复杂的用户特定信息,ThreadLocal.remove() 方法都为管理和清理线程特定数据提供了可靠的方式。

]]>
Java并发编程:ThreadLocal的set方法详解 https://java.didispace.com/java-multithreading/3-4-threadlocal-set.html https://java.didispace.com/java-multithreading/3-4-threadlocal-set.html Java并发编程:ThreadLocal的set方法详解 Java并发编程:ThreadLocal的set方法详解 在 Java 中,ThreadLocal.set() 方法用于设置当前线程在线程局部变量中的值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。 目录 引言 set() 方法语法 理解 set() 示例演示 基础使用 多线程环境下的 set() 实际应用场景 总结 Java Wed, 19 Mar 2025 17:00:00 GMT Java并发编程:ThreadLocal的set方法详解

在 Java 中,ThreadLocal.set() 方法用于设置当前线程在线程局部变量中的值。本指南将详细介绍该方法的使用方式、工作原理,并通过示例展示其功能。

目录

  1. 引言
  2. set() 方法语法
  3. 理解 set()
  4. 示例演示
    • 基础使用
    • 多线程环境下的 set()
    • 实际应用场景
  5. 总结

1. 引言

ThreadLocal.set() 方法用于为当前线程设置线程局部变量的值。该方法可确保不同线程维护独立的值,从而在无需同步的情况下保证线程安全。

2. set() 方法语法

set() 方法的语法如下:

参数
value - 要设置给当前线程的线程局部变量的值。
返回值:该方法不返回任何值。

3. 理解 set()

ThreadLocal.set() 方法用于为当前线程的线程局部变量副本分配新值。每个线程拥有独立的变量副本,set() 方法允许更新当前线程的该值。

4. 示例演示

基础使用

以下示例展示 set() 方法的基础用法,每个线程设置并获取其线程局部变量的值。

输出结果

多线程环境下的 set()

可以在多线程中使用 set() 方法,确保每个线程拥有唯一的值。

输出结果(示例):

实际应用场景:管理 Web 应用中的用户会话

在 Web 应用中,可以利用 ThreadLocal 为不同线程处理的每个请求存储用户会话信息。

输出结果

5. 总结

Java 中的 ThreadLocal.set() 方法允许为当前线程设置线程局部变量的值。通过使用该方法,可以确保每个线程拥有唯一的值,从而提升线程安全性,避免同步问题。无论是处理简单的线程局部变量,还是 Web 应用中复杂的用户特定信息,ThreadLocal.set() 方法都为管理和更新线程特定数据提供了可靠的解决方案。

]]>
Java并发编程:概述 https://java.didispace.com/java-multithreading/2-1-java-concurrency-tutorial.html https://java.didispace.com/java-multithreading/2-1-java-concurrency-tutorial.html Java并发编程:概述 Java并发编程:概述 在本教程中,我们将学习Java平台5.0版本引入的高级并发特性。 这些特性大多通过java.util.concurrent包实现。 一、Executor框架核心优势 Executor框架通过以下特性提升并发编程体验: 任务与执行解耦:只需实现Runnable任务,无需关心线程创建/销毁 线程池管理:// 传统线程创建方式 new Thread(new RunnableTask()).start(); // 使用Executor框架 Executor executor = Executors.newFixedThreadPool(10); executor.execute(new RunnableTask()); Callable接口增强: 支持返回值(替代无返回的Runnable) 通过Future对象管理任务状态 Java Wed, 12 Mar 2025 11:00:00 GMT Java并发编程:概述

在本教程中,我们将学习Java平台5.0版本引入的高级并发特性。

这些特性大多通过java.util.concurrent包实现。

一、Executor框架核心优势

Executor框架通过以下特性提升并发编程体验:

  1. 任务与执行解耦:只需实现Runnable任务,无需关心线程创建/销毁
  2. 线程池管理
  3. Callable接口增强
    • 支持返回值(替代无返回的Runnable)
    • 通过Future对象管理任务状态

二、Executor接口体系

java.util.concurrent包定义了三级接口:

1. Executor 基础接口

  • 核心方法:提交Runnable任务
  • 实现类:ThreadPoolExecutor

2. ExecutorService 扩展接口

  • 支持提交Callable任务
  • 提供任务生命周期管理(关闭、等待终止等)

3. ScheduledExecutorService 定时任务接口

  • 支持延迟执行和周期性任务
  • 返回ScheduledFuture对象

三、Future与Callable接口

1. Callable接口

  • 替代Runnable的有返回值任务
  • 允许抛出受检异常

2. Future接口

  • 管理异步任务结果
  • 支持取消任务和超时控制

四、Executors工厂类

提供便捷的线程池创建方法:

方法名称 描述
newSingleThreadExecutor() 创建单线程线程池,确保任务按顺序执行
newFixedThreadPool(int n) 创建固定大小的线程池,重用线程处理新任务
newCachedThreadPool() 缓存型线程池,根据负载动态调整线程数量
newScheduledThreadPool(int n) 创建支持定时任务的线程池,适用于周期性执行场景

五、核心实现示例

1. 基础任务提交

2. Callable任务与Future

3. 定时任务示例

六、最佳实践建议

  1. 优先使用工厂方法:通过Executors创建线程池,避免直接使用ThreadPoolExecutor构造函数
  2. 合理配置线程池参数
    • CPU密集型任务:线程数≈CPU核心数
    • I/O密集型任务:线程数可适当增加
  3. 正确关闭ExecutorService
  4. 监控线程池状态:通过ThreadPoolExecutorgetActiveCount()等方法监控运行状态

通过本教程,您将掌握Java并发编程的核心工具,在保证线程安全的同时提升应用性能。

]]>
Java并发编程:ExecutorService 接口 https://java.didispace.com/java-multithreading/2-2-executor-service.html https://java.didispace.com/java-multithreading/2-2-executor-service.html Java并发编程:ExecutorService 接口 Java并发编程:ExecutorService 接口 ExecutorService 是Java并发编程中管理线程池和异步任务执行的核心接口,属于java.util.concurrent包。它将任务提交与具体执行机制解耦,简化了多线程编程的复杂度。 目录 ExecutorService概述 创建ExecutorService 提交任务 关闭ExecutorService 完整示例 处理Callable和Future 定时任务示例 总结 Java Wed, 12 Mar 2025 12:00:00 GMT Java并发编程:ExecutorService 接口

ExecutorService 是Java并发编程中管理线程池和异步任务执行的核心接口,属于java.util.concurrent包。它将任务提交与具体执行机制解耦,简化了多线程编程的复杂度。

目录

  1. ExecutorService概述
  2. 创建ExecutorService
  3. 提交任务
  4. 关闭ExecutorService
  5. 完整示例
  6. 处理Callable和Future
  7. 定时任务示例
  8. 总结

1. 概述

ExecutorServiceExecutor 的子接口,提供以下核心功能:

  • 任务管理:提交Runnable/Callable任务并获取结果
  • 生命周期控制:优雅关闭线程池
  • 批量任务处理invokeAll()invokeAny()等方法

关键方法:

方法名 描述
submit() 提交任务并返回Future对象
shutdown() 优雅关闭,不再接受新任务
shutdownNow() 立即关闭,尝试中断执行中的任务
awaitTermination() 阻塞等待线程池终止

2. 创建

通过Executors工厂类创建不同类型的线程池:

3. 提交任务

提交Runnable任务

提交Callable任务

4. 关闭服务

优雅关闭流程

5. 完整示例

输出示例

6. 处理Callable和Future

7. 定时任务

8. 总结

  • 优势:线程复用、任务解耦、生命周期管理
  • 最佳实践
    1. 优先使用工厂方法创建线程池
    2. 始终调用shutdown()关闭线程池
    3. 对耗时操作使用Future处理异步结果
    4. 监控线程池状态(getActiveCount()等方法)

通过合理使用ExecutorService,可以显著提升Java应用的并发性能和可维护性。

]]>
Java并发编程:ScheduledExecutorService 接口 https://java.didispace.com/java-multithreading/2-3-scheduled-executor-service.html https://java.didispace.com/java-multithreading/2-3-scheduled-executor-service.html Java并发编程:ScheduledExecutorService 接口 Java并发编程:ScheduledExecutorService 接口 ScheduledExecutorService 是Java并发编程中用于定时任务调度的核心接口,属于java.util.concurrent包。它扩展了ExecutorService,提供延迟执行和周期性任务的支持。 目录 ScheduledExecutorService概述 创建定时任务执行器 延迟执行任务(schedule) 固定速率周期性任务(scheduleAtFixedRate) 固定延迟周期性任务(scheduleWithFixedDelay) 完整示例 关闭执行器 总结 Java Thu, 13 Mar 2025 11:00:00 GMT Java并发编程:ScheduledExecutorService 接口

ScheduledExecutorService 是Java并发编程中用于定时任务调度的核心接口,属于java.util.concurrent包。它扩展了ExecutorService,提供延迟执行和周期性任务的支持。

目录

  1. ScheduledExecutorService概述
  2. 创建定时任务执行器
  3. 延迟执行任务(schedule)
  4. 固定速率周期性任务(scheduleAtFixedRate)
  5. 固定延迟周期性任务(scheduleWithFixedDelay)
  6. 完整示例
  7. 关闭执行器
  8. 总结

1. 概述

ScheduledExecutorService 提供以下核心方法:

  • 延迟执行:任务在指定时间后执行一次
  • 周期性执行:任务按固定频率或固定延迟重复执行

关键方法对比:

方法名 描述
schedule(Runnable, delay, unit) 单次延迟执行任务
scheduleAtFixedRate(Runnable, initialDelay, period, unit) 固定速率周期性执行(基于开始时间)
scheduleWithFixedDelay(Runnable, initialDelay, delay, unit) 固定延迟周期性执行(基于结束时间)

2. 创建

通过Executors工厂类创建:

3. 延迟执行任务

输出

4. 固定速率周期性任务

输出示例

5. 固定延迟周期性任务

输出示例

6. 完整示例

7. 关闭执行器

8. 总结

  • 适用场景:定时任务、心跳检测、周期性数据同步等
  • 注意事项
    • 固定速率任务可能因执行时间过长而并发执行
    • 固定延迟任务的间隔基于任务结束时间计算
    • 始终调用shutdown()释放资源

通过合理使用ScheduledExecutorService,可以轻松实现复杂的定时任务调度需求。

]]>
Java并发编程:Future接口 https://java.didispace.com/java-multithreading/2-4-future.html https://java.didispace.com/java-multithreading/2-4-future.html Java并发编程:Future接口 Java并发编程:Future接口 Future 是Java并发编程中用于管理异步任务的核心接口,属于java.util.concurrent包。它代表异步计算的结果,提供检查任务状态、等待结果和取消任务等功能。 目录 Future接口概述 核心方法详解 与ExecutorService结合使用示例 取消任务示例 异常处理 总结 Java Thu, 13 Mar 2025 12:00:00 GMT Java并发编程:Future接口

Future 是Java并发编程中用于管理异步任务的核心接口,属于java.util.concurrent包。它代表异步计算的结果,提供检查任务状态、等待结果和取消任务等功能。

目录

  1. Future接口概述
  2. 核心方法详解
  3. 与ExecutorService结合使用示例
  4. 取消任务示例
  5. 异常处理
  6. 总结

1. 概述

Future 接口的核心功能:

  • 异步结果管理:通过get()方法获取任务结果
  • 任务状态查询isDone()检查任务是否完成
  • 任务控制cancel()取消任务执行

典型使用场景:

2. 核心方法

方法名 描述
V get() 阻塞直到任务完成,返回结果或抛出异常
V get(long timeout, TimeUnit unit) 带超时的阻塞获取结果
boolean cancel(boolean mayInterrupt) 尝试取消任务(mayInterrupt为true时中断执行中的线程)
boolean isCancelled() 检查任务是否在完成前被取消
boolean isDone() 检查任务是否完成(正常结束、异常或取消)

3. 使用示例

输出示例

4. 取消任务

输出示例

5. 异常处理

输出示例

6. 总结

  • 适用场景:异步计算、非阻塞IO操作
  • 最佳实践
    1. 始终设置get()方法的超时时间
    2. 对可取消任务调用cancel(true)
    3. 使用isDone()避免不必要的阻塞
    4. 优先使用CompletableFuture替代原始Future

通过合理使用Future接口,可以显著提升Java应用的异步编程能力。

]]>
Java并发编程:Callable与Future https://java.didispace.com/java-multithreading/2-5-callable-future.html https://java.didispace.com/java-multithreading/2-5-callable-future.html Java并发编程:Callable与Future Java并发编程:Callable与Future Callable 和 Future 是Java并发编程中处理异步任务的核心接口,属于java.util.concurrent包。Callable类似于Runnable,但支持返回结果和抛出受检异常;Future则代表异步计算的结果,提供任务状态管理和结果获取功能。 目录 Callable接口详解 Future接口详解 与ExecutorService协同使用 基础使用示例 异常处理示例 任务取消示例 总结 Java Thu, 13 Mar 2025 13:00:00 GMT Java并发编程:Callable与Future

CallableFuture 是Java并发编程中处理异步任务的核心接口,属于java.util.concurrent包。Callable类似于Runnable,但支持返回结果和抛出受检异常;Future则代表异步计算的结果,提供任务状态管理和结果获取功能。

目录

  1. Callable接口详解
  2. Future接口详解
  3. 与ExecutorService协同使用
  4. 基础使用示例
  5. 异常处理示例
  6. 任务取消示例
  7. 总结

1. Callable接口

Callable是一个函数式接口,定义如下:

  • 特性
    • 支持返回泛型结果V
    • 允许抛出受检异常
    • 替代无返回值的Runnable

2. Future接口

Future代表异步任务的结果,核心方法:

方法名 描述
V get() 阻塞直到任务完成,返回结果或抛出异常
boolean cancel(boolean mayInterrupt) 尝试取消任务(mayInterrupt为true时中断执行线程)
boolean isDone() 检查任务是否完成(正常结束、异常或取消)
boolean isCancelled() 检查任务是否在完成前被取消

3. 与ExecutorService协同使用

通过ExecutorService提交Callable任务:

4. 基础使用示例

输出

5. 异常处理示例

输出

6. 任务取消示例

输出

7. 总结

  • Callable优势:支持返回值和异常处理
  • Future功能
    • 异步结果获取
    • 任务状态监控
    • 超时控制与取消
  • 最佳实践
    1. 始终设置get()方法的超时时间
    2. 使用CompletableFuture实现更复杂的异步编排
    3. 对可取消任务调用cancel(true)

通过CallableFuture的组合,开发者可以高效地管理异步任务,提升Java应用的并发性能。

]]>
Java并发编程:Executors.newSingleThreadExecutor https://java.didispace.com/java-multithreading/2-6-executors-newSingleThreadExecutor.html https://java.didispace.com/java-multithreading/2-6-executors-newSingleThreadExecutor.html Java并发编程:Executors.newSingleThreadExecutor Java并发编程:Executors.newSingleThreadExecutor Executors.newSingleThreadExecutor 方法用于创建一个使用单个工作线程的ExecutorService,任务将按提交顺序串行执行。 目录 newSingleThreadExecutor概述 创建单线程执行器 提交任务 完整示例 关闭执行器 总结 Java Thu, 13 Mar 2025 14:00:00 GMT Java并发编程:Executors.newSingleThreadExecutor

Executors.newSingleThreadExecutor 方法用于创建一个使用单个工作线程的ExecutorService,任务将按提交顺序串行执行。

目录

  1. newSingleThreadExecutor概述
  2. 创建单线程执行器
  3. 提交任务
  4. 完整示例
  5. 关闭执行器
  6. 总结

1. 概述

newSingleThreadExecutor 创建的执行器特点:

  • 单线程执行:确保任务按顺序执行
  • 无界队列:未执行的任务在队列中等待
  • 线程复用:唯一线程自动回收利用

语法

2. 创建单线程执行器

3. 提交任务

输出示例

4. 完整示例

输出

5. 关闭执行器

优雅关闭流程

6. 总结

  • 适用场景
    • 需要保证任务顺序执行
    • 资源敏感型应用(限制线程数量)
  • 优势
    • 自动管理线程生命周期
    • 避免线程频繁创建/销毁开销
  • 注意事项
    • 无界队列可能导致OOM(内存溢出)
    • 单线程可能成为性能瓶颈

通过合理使用newSingleThreadExecutor,可以在需要顺序执行任务的场景中实现高效并发控制。

]]>
Java并发编程:Executors.newFixedThreadPool https://java.didispace.com/java-multithreading/2-7-executors-newFixedThreadPool.html https://java.didispace.com/java-multithreading/2-7-executors-newFixedThreadPool.html Java并发编程:Executors.newFixedThreadPool Java并发编程:Executors.newFixedThreadPool Executors.newFixedThreadPool 方法用于创建一个固定大小的线程池,适用于需要控制并发线程数量的场景。 目录 newFixedThreadPool概述 创建固定线程池 提交任务 完整示例 关闭线程池 总结 Java Thu, 13 Mar 2025 15:00:00 GMT Java并发编程:Executors.newFixedThreadPool

Executors.newFixedThreadPool 方法用于创建一个固定大小的线程池,适用于需要控制并发线程数量的场景。

目录

  1. newFixedThreadPool概述
  2. 创建固定线程池
  3. 提交任务
  4. 完整示例
  5. 关闭线程池
  6. 总结

1. 概述

newFixedThreadPool 创建的线程池特点:

  • 固定线程数:通过参数指定线程数量
  • 无界队列:未执行的任务在队列中等待
  • 线程复用:线程执行完任务后返回池中

语法

参数说明:

  • nThreads:线程池中线程的数量

2. 创建固定线程池

3. 提交任务

输出示例

4. 完整示例

输出

5. 关闭线程池

优雅关闭流程

6. 总结

  • 适用场景
    • 需要控制并发线程数的计算密集型任务
    • 防止资源耗尽的场景
  • 优势
    • 线程数量固定,避免上下文切换开销
    • 无界队列自动缓冲任务
  • 注意事项
    • 无界队列可能导致内存溢出
    • 线程数应根据硬件资源合理配置

通过newFixedThreadPool可以有效管理并发线程,提升Java应用的性能和稳定性。

]]>
Java并发编程:Executors.newCachedThreadPool https://java.didispace.com/java-multithreading/2-8-executors-newCachedThreadPool.html https://java.didispace.com/java-multithreading/2-8-executors-newCachedThreadPool.html Java并发编程:Executors.newCachedThreadPool Java并发编程:Executors.newCachedThreadPool Executors.newCachedThreadPool 方法用于创建一个缓存型线程池,该线程池会根据任务负载动态调整线程数量,适用于提交大量短期异步任务的场景。 目录 newCachedThreadPool概述 创建缓存型线程池 提交任务 完整示例 关闭线程池 总结 Java Thu, 13 Mar 2025 16:00:00 GMT Java并发编程:Executors.newCachedThreadPool

Executors.newCachedThreadPool 方法用于创建一个缓存型线程池,该线程池会根据任务负载动态调整线程数量,适用于提交大量短期异步任务的场景。

目录

  1. newCachedThreadPool概述
  2. 创建缓存型线程池
  3. 提交任务
  4. 完整示例
  5. 关闭线程池
  6. 总结

1. 概述

newCachedThreadPool 创建的线程池特点:

  • 动态扩展:无任务时线程自动回收(60秒空闲后终止)
  • 无界队列:提交的任务直接分配给可用线程
  • 线程复用:优先使用已存在的线程

语法

2. 创建缓存型线程池

3. 提交任务

输出示例

4. 完整示例

输出

5. 关闭线程池

优雅关闭流程

6. 总结

  • 适用场景
    • 短期异步任务(如HTTP请求处理)
    • 任务数量波动较大的场景
  • 优势
    • 自动适应负载变化
    • 减少线程创建/销毁开销
  • 注意事项
    • 可能因任务激增导致OOM(内存溢出)
    • 长期运行的任务不适合此线程池

通过合理使用newCachedThreadPool,可以在任务数量波动的场景中实现高效并发处理。

]]>
Java并发编程:Executors.newScheduledThreadPool https://java.didispace.com/java-multithreading/2-9-executors-newScheduledThreadPool.html https://java.didispace.com/java-multithreading/2-9-executors-newScheduledThreadPool.html Java并发编程:Executors.newScheduledThreadPool Java并发编程:Executors.newScheduledThreadPool Executors.newScheduledThreadPool 方法用于创建一个固定线程数的定时任务执行器,支持延迟执行和周期性任务调度。 目录 newScheduledThreadPool概述 创建定时任务执行器 延迟执行任务 固定速率周期性任务 固定延迟周期性任务 完整示例 关闭执行器 总结 Java Thu, 13 Mar 2025 17:00:00 GMT Java并发编程:Executors.newScheduledThreadPool

Executors.newScheduledThreadPool 方法用于创建一个固定线程数的定时任务执行器,支持延迟执行和周期性任务调度。

目录

  1. newScheduledThreadPool概述
  2. 创建定时任务执行器
  3. 延迟执行任务
  4. 固定速率周期性任务
  5. 固定延迟周期性任务
  6. 完整示例
  7. 关闭执行器
  8. 总结

1. 概述

newScheduledThreadPool 创建的执行器特点:

  • 固定线程数:核心线程数通过参数指定
  • 支持定时任务
    • schedule():延迟执行
    • scheduleAtFixedRate():固定速率周期性执行
    • scheduleWithFixedDelay():固定延迟周期性执行

语法

参数说明:

  • corePoolSize:线程池核心线程数

2. 创建定时任务执行器

3. 延迟执行任务

输出

4. 固定速率周期性任务

输出示例

5. 固定延迟周期性任务

输出示例

6. 完整示例

7. 关闭执行器

8. 总结

  • 适用场景:定时任务、心跳检测、周期性数据同步等
  • 注意事项
    • 固定速率任务可能因执行时间过长而并发执行
    • 固定延迟任务的间隔基于任务结束时间计算
    • 始终调用shutdown()释放资源

通过合理使用newScheduledThreadPool,可以轻松实现复杂的定时任务调度需求。

]]>
Java多线程教程:Thread Group线程组 https://java.didispace.com/java-multithreading/1-10-threadgroup.html https://java.didispace.com/java-multithreading/1-10-threadgroup.html Java多线程教程:Thread Group线程组 Java多线程教程:Thread Group线程组 Java中的ThreadGroup类提供了一种将线程分组管理的机制。一个ThreadGroup可以包含多个线程甚至其他线程组,形成树状结构。这使得可以对一组线程进行统一管理和控制。 目录 ThreadGroup类概述 创建线程组 向线程组添加线程 管理线程组 ThreadGroup方法 示例:创建和管理线程组 线程组层次结构 ThreadGroup的优缺点 结论 Java Tue, 11 Mar 2025 20:00:00 GMT Java多线程教程:Thread Group线程组

Java中的ThreadGroup类提供了一种将线程分组管理的机制。一个ThreadGroup可以包含多个线程甚至其他线程组,形成树状结构。这使得可以对一组线程进行统一管理和控制。

目录

  1. ThreadGroup类概述
  2. 创建线程组
  3. 向线程组添加线程
  4. 管理线程组
  5. ThreadGroup方法
  6. 示例:创建和管理线程组
  7. 线程组层次结构
  8. ThreadGroup的优缺点
  9. 结论

1. ThreadGroup类概述

ThreadGroup类属于java.lang包,提供以下功能:

  • 创建线程组
  • 设置组内所有线程的最大优先级
  • 处理组内所有线程的未捕获异常
  • 中断、挂起或恢复组内所有线程

核心方法:

  • activeCount():返回组内活动线程的估计数量。
  • activeGroupCount():返回组内活动子组的估计数量。
  • enumerate(Thread[] list):将组内所有活动线程复制到指定数组。
  • getMaxPriority():返回组的最大优先级。
  • interrupt():中断组内所有线程。
  • setMaxPriority(int pri):设置组的最大优先级。
  • uncaughtException(Thread t, Throwable e):处理线程未捕获异常。

2. 创建线程组

通过指定名称或父组+名称创建线程组:

3. 向线程组添加线程

创建线程时指定所属线程组:

4. 管理线程组

对组内所有线程进行统一操作:

5. ThreadGroup方法详解

activeCount()

activeGroupCount()

enumerate(Thread[] list)

getMaxPriority()

interrupt()

setMaxPriority(int pri)

uncaughtException(Thread t, Throwable e)

6. 示例:创建和管理线程组

输出:

7. 线程组层次结构

线程组可以嵌套形成层级结构,根节点是系统线程组:

8. 优缺点

优点:

  • 集中管理:统一操作组内所有线程
  • 组织性强:按功能分组管理线程
  • 异常处理:统一处理组内未捕获异常

缺点:

  • 部分方法已过时(如suspend()resume()
  • 功能有限:不如java.util.concurrent包强大

9. 结论

ThreadGroup提供了一种将线程分组管理的机制,适合需要统一控制一组线程的场景。但需注意其局限性,建议优先使用ExecutorService等现代并发工具进行复杂线程管理。

]]>
Java多线程教程:多线程同步机制 https://java.didispace.com/java-multithreading/1-11-synchronization-in-multithreading.html https://java.didispace.com/java-multithreading/1-11-synchronization-in-multithreading.html Java多线程教程:多线程同步机制 Java多线程教程:多线程同步机制 Java中的同步机制是一种强大的工具,用于控制多个线程对共享资源的访问。它确保同一时间只有一个线程可以访问资源,防止数据不一致和竞态条件。这在多线程环境中尤为重要,因为线程经常共享变量、数组或对象等资源。 目录 同步概述 同步方法 同步块 静态同步 示例:同步方法 示例:同步块 可重入同步 同步与性能 结论 1. 同步概述 Java Tue, 11 Mar 2025 21:00:00 GMT Java多线程教程:多线程同步机制

Java中的同步机制是一种强大的工具,用于控制多个线程对共享资源的访问。它确保同一时间只有一个线程可以访问资源,防止数据不一致和竞态条件。这在多线程环境中尤为重要,因为线程经常共享变量、数组或对象等资源。

目录

  1. 同步概述
  2. 同步方法
  3. 同步块
  4. 静态同步
  5. 示例:同步方法
  6. 示例:同步块
  7. 可重入同步
  8. 同步与性能
  9. 结论

1. 同步概述

在Java中,synchronized关键字用于同步对代码临界区的访问。主要有两种同步方式:

  • 同步方法:整个方法标记为synchronized,确保同一时间只有一个线程执行该方法。
  • 同步块:方法内的特定代码块标记为synchronized,提供更细粒度的同步控制。

2. 同步方法

同步方法确保同一对象实例上的该方法同一时间只能被一个线程执行。锁由调用该方法的对象实例持有。

语法:

3. 同步块

同步块是方法内针对特定对象的同步代码块。它允许只锁定代码的关键部分而非整个方法。

语法:

4. 静态同步

静态同步确保获取的是类级锁,所有类实例共享同一把锁。

语法:

或使用同步块:

5. 示例:同步方法

代码示例:

输出结果:

代码解释:

  • Counter类的increment方法被声明为synchronized
  • 两个线程各执行1000次increment操作。
  • 最终计数为2000,说明同步机制避免了竞态条件。

6. 示例:同步块

代码示例:

输出结果:

代码解释:

  • increment方法使用synchronized (this)同步块。
  • 与同步方法示例效果相同,确保线程安全。

7. 可重入同步

Java的同步锁是可重入的。如果线程已持有某个对象的锁,它可以再次进入该对象的任何同步方法或块。

示例代码:

输出结果:

代码解释:

  • method1调用synchronizedmethod2
  • 线程可重入已持有的锁,体现可重入性。

8. 同步与性能

同步虽然是线程安全的关键,但获取和释放锁的开销可能影响性能。为减少竞争,应尽可能缩小同步代码的范围。

9. 结论

Java同步机制用于确保多线程环境下的线程安全,防止竞态条件。通过同步方法、同步块和静态同步,可以控制多线程对共享资源的访问。但需谨慎使用同步,平衡线程安全与性能。

]]>
Java多线程教程:ThreadLocal类 https://java.didispace.com/java-multithreading/1-12-threadlocal.html https://java.didispace.com/java-multithreading/1-12-threadlocal.html Java多线程教程:ThreadLocal类 Java多线程教程:ThreadLocal类 Java中的ThreadLocal类提供了线程本地变量。每个访问该变量的线程(通过get或set方法)都有自己独立初始化的变量副本。ThreadLocal是实现线程封闭的有效机制,确保每个线程拥有独立的变量实例,从而避免同步问题。 目录 ThreadLocal类概述 创建ThreadLocal变量 使用ThreadLocal变量 示例:ThreadLocal的使用 设置初始值 可继承的ThreadLocal 移除ThreadLocal变量 使用场景 结论 Java Tue, 11 Mar 2025 22:00:00 GMT Java多线程教程:ThreadLocal类

Java中的ThreadLocal类提供了线程本地变量。每个访问该变量的线程(通过getset方法)都有自己独立初始化的变量副本。ThreadLocal是实现线程封闭的有效机制,确保每个线程拥有独立的变量实例,从而避免同步问题。

目录

  1. ThreadLocal类概述
  2. 创建ThreadLocal变量
  3. 使用ThreadLocal变量
  4. 示例:ThreadLocal的使用
  5. 设置初始值
  6. 可继承的ThreadLocal
  7. 移除ThreadLocal变量
  8. 使用场景
  9. 结论

1. ThreadLocal类概述

ThreadLocal类为每个线程提供独立的变量副本。通常作为类的私有静态字段,用于将状态与线程关联。

核心方法:

  • get():获取当前线程的变量副本。
  • set(T value):设置当前线程的变量值。
  • remove():移除当前线程的变量副本。
  • initialValue():返回变量的初始值。

2. 创建ThreadLocal变量

通过实例化ThreadLocal类创建线程本地变量:

3. 使用ThreadLocal变量

各线程的变量副本相互独立,互不影响:

输出:

4. 完整示例

输出:

5. 设置初始值

通过withInitial或重写initialValue方法设置初始值:

6. 可继承的ThreadLocal

InheritableThreadLocal允许子线程继承父线程的变量值:

输出:

7. 移除变量

使用remove()方法释放资源,避免内存泄漏:

8. 使用场景

  • 用户会话:存储线程特定的用户会话信息。
  • 数据库连接:管理线程级别的数据库连接。
  • 事务管理:处理线程独立的事务上下文。
  • 日志上下文:存储日志相关的线程上下文。

9. 结论

ThreadLocal为Java提供了高效的线程本地变量管理方式,确保线程封闭性。通过合理使用ThreadLocal,可以有效避免同步问题,提升多线程程序的可维护性。但需注意及时清理不再使用的线程本地变量。

]]>
Java多线程教程:Thread设置线程名 https://java.didispace.com/java-multithreading/1-6-thread-set-name.html https://java.didispace.com/java-multithreading/1-6-thread-set-name.html Java多线程教程:Thread设置线程名 Java多线程教程:Thread设置线程名 在Java中,每个线程都有一个用于标识的名称。默认情况下,Java虚拟机(JVM)会为线程分配默认名称(如&quot;Thread-0&quot;、&quot;Thread-1&quot;),但开发者也可以自定义线程名称。设置线程名称对调试和监控非常有用,能帮助快速识别多线程应用中的不同线程。 目录 设置线程名称 获取线程名称 设置与获取线程名称示例 使用Lambda表达式设置线程名称 结论 1. 设置线程名称 Java Tue, 11 Mar 2025 16:00:00 GMT Java多线程教程:Thread设置线程名

在Java中,每个线程都有一个用于标识的名称。默认情况下,Java虚拟机(JVM)会为线程分配默认名称(如"Thread-0"、"Thread-1"),但开发者也可以自定义线程名称。设置线程名称对调试和监控非常有用,能帮助快速识别多线程应用中的不同线程。

目录

  1. 设置线程名称
  2. 获取线程名称
  3. 设置与获取线程名称示例
  4. 使用Lambda表达式设置线程名称
  5. 结论

1. 设置线程名称

通过Thread类的setName(String name)方法设置线程名称:

2. 获取线程名称

通过Thread类的getName()方法获取线程名称:

3. 设置与获取线程名称示例

输出:

4. 使用Lambda表达式设置线程名称

输出:

5. 结论

设置和获取线程名称是Java中简单但强大的功能,对调试和监控多线程应用非常有帮助。通过setNamegetName方法,可以轻松识别和管理程序中的线程。本文通过Thread类和Lambda表达式两种方式展示了如何有效设置和获取线程名称。

]]>
Java多线程教程:Thread 中断(interrupt) https://java.didispace.com/java-multithreading/1-7-thread-interrupt.html https://java.didispace.com/java-multithreading/1-7-thread-interrupt.html Java多线程教程:Thread 中断(interrupt) Java多线程教程:Thread 中断(interrupt) Java中的interrupt方法用于中断当前运行的线程。该方法将线程的中断状态设置为true。如果线程处于阻塞状态(如等待、睡眠或I/O阻塞),则会抛出InterruptedException。被中断的线程可以捕获该异常并采取相应措施。 目录 如何中断线程 检查中断状态 处理InterruptedException 中断线程示例 处理睡眠线程中断示例 结论 Java Tue, 11 Mar 2025 17:00:00 GMT Java多线程教程:Thread 中断(interrupt)

Java中的interrupt方法用于中断当前运行的线程。该方法将线程的中断状态设置为true。如果线程处于阻塞状态(如等待、睡眠或I/O阻塞),则会抛出InterruptedException。被中断的线程可以捕获该异常并采取相应措施。

目录

  1. 如何中断线程
  2. 检查中断状态
  3. 处理InterruptedException
  4. 中断线程示例
  5. 处理睡眠线程中断示例
  6. 结论

1. 如何中断线程

通过调用线程实例的interrupt方法中断线程:

2. 检查中断状态

使用isInterrupted方法或静态的Thread.interrupted方法检查中断状态:

3. 处理InterruptedException

当线程在阻塞状态下被中断时(如睡眠或等待),会抛出InterruptedException,需使用try-catch块处理。

4. 中断线程示例

输出:

5. 处理睡眠线程中断示例

输出:

6. 结论

Java的interrupt方法用于控制线程执行流程。通过interruptisInterruptedinterrupted方法,可以优雅地处理线程中断。正确处理InterruptedException能确保线程在各种条件下可控地响应中断,使应用程序行为符合预期。

]]>
Java多线程教程:Thread线程优先级 https://java.didispace.com/java-multithreading/1-8-thread-priority.html https://java.didispace.com/java-multithreading/1-8-thread-priority.html Java多线程教程:Thread线程优先级 Java多线程教程:Thread线程优先级 在Java中,每个线程都被赋予一个优先级,帮助线程调度器决定线程的执行顺序。线程优先级是一个整数,范围从Thread.MIN_PRIORITY(1)到Thread.MAX_PRIORITY(10)。默认优先级是Thread.NORM_PRIORITY(5)。线程调度器根据这些优先级决定各线程何时运行。但需注意,线程优先级不保证执行顺序,它仅仅是对线程调度器的一个建议。 目录 设置线程优先级 获取线程优先级 示例:设置和获取线程优先级 结论 Java Tue, 11 Mar 2025 18:00:00 GMT Java多线程教程:Thread线程优先级

在Java中,每个线程都被赋予一个优先级,帮助线程调度器决定线程的执行顺序。线程优先级是一个整数,范围从Thread.MIN_PRIORITY(1)到Thread.MAX_PRIORITY(10)。默认优先级是Thread.NORM_PRIORITY(5)。线程调度器根据这些优先级决定各线程何时运行。但需注意,线程优先级不保证执行顺序,它仅仅是对线程调度器的一个建议。

目录

  1. 设置线程优先级
  2. 获取线程优先级
  3. 示例:设置和获取线程优先级
  4. 结论

1. 设置线程优先级

可以通过Thread类的setPriority(int newPriority)方法设置线程优先级。新优先级必须在Thread.MIN_PRIORITYThread.MAX_PRIORITY范围内。

语法:

2. 获取线程优先级

可以通过Thread类的getPriority()方法获取线程优先级。该方法返回线程优先级的整数值。

语法:

3. 示例:设置和获取线程优先级

通过以下示例演示如何设置和获取线程优先级:

示例代码:

输出结果:

代码解释:

  • MyThread类继承自Thread类,并调用父类构造函数设置线程名。
  • run方法打印当前线程的名称和优先级。
  • main方法中:
    1. 创建三个自定义名称的MyThread对象。
    2. 使用setPriority方法设置线程优先级。
    3. 使用start方法启动线程。
    4. 使用getPriority方法打印线程优先级。

4. 结论

Java线程优先级是一个实用功能,可帮助线程调度器决定线程执行顺序。通过设置和获取线程优先级,您可以影响程序中线程的执行行为。但请记住:线程优先级仅仅是对调度器的建议,并不保证执行顺序。本指南通过示例演示了Java中设置和获取线程优先级的方法。

]]>
Java多线程教程:Thread线程优先级 https://java.didispace.com/java-multithreading/1-9-thread-isalive.html https://java.didispace.com/java-multithreading/1-9-thread-isalive.html Java多线程教程:Thread线程优先级 Java多线程教程:Thread线程优先级 Java中的isAlive方法用于检查线程是否正在运行。如果线程已启动但尚未终止,返回true;否则返回false。该方法在需要等待线程执行完成后再继续其他任务时非常有用。 目录 使用isAlive方法 示例:检查线程是否存活 示例:使用isAlive等待线程结束 结论 1. 使用isAlive方法 Java Tue, 11 Mar 2025 19:00:00 GMT Java多线程教程:Thread线程优先级

Java中的isAlive方法用于检查线程是否正在运行。如果线程已启动但尚未终止,返回true;否则返回false。该方法在需要等待线程执行完成后再继续其他任务时非常有用。

目录

  1. 使用isAlive方法
  2. 示例:检查线程是否存活
  3. 示例:使用isAlive等待线程结束
  4. 结论

1. 使用isAlive方法

isAlive方法属于Thread类,可在任意线程实例上调用以检查其存活状态。

语法:

2. 示例:检查线程是否存活

以下示例演示如何使用isAlive方法判断线程是否处于运行状态:

示例代码:

输出结果:

代码解释:

  • MyThread类继承自Thread类并设置线程名称。
  • run方法打印线程名称和迭代次数,每次迭代后休眠500毫秒。
  • main方法中:
    1. 创建线程实例并检查启动前状态。
    2. 启动线程后再次检查状态。
    3. 使用join方法等待线程执行完毕。
    4. 最终检查线程状态。

3. 示例:使用isAlive等待线程结束

此示例演示如何通过循环调用isAlive方法等待线程执行完成:

示例代码:

输出结果:

代码解释:

  • main方法中启动线程后,通过while循环持续检查线程状态。
  • 主线程每次循环休眠200毫秒,避免过度占用CPU资源。
  • 当线程执行完毕(isAlive返回false)时,循环终止并输出完成信息。

4. 结论

Java的isAlive方法用于检查线程状态。通过该方法,您可以判断线程是否处于运行状态,并在其执行完毕后再继续后续任务。这在多线程应用中协调多个线程时尤为有用。

]]>
Java多线程教程:Thread中的sleep方法 https://java.didispace.com/java-multithreading/1-4-thread-sleep.html https://java.didispace.com/java-multithreading/1-4-thread-sleep.html Java多线程教程:Thread中的sleep方法 Java多线程教程:Thread中的sleep方法 Java中的sleep方法用于暂停当前线程的执行指定时间。该方法属于Thread类,允许临时挂起线程而不终止它。sleep方法可能抛出InterruptedException,因此必须使用try-catch块处理。 目录 sleep方法变体 使用sleep(long millis)方法示例 使用sleep(long millis, int nanos)方法示例 处理InterruptedException 结论 Java Tue, 11 Mar 2025 14:00:00 GMT Java多线程教程:Thread中的sleep方法

Java中的sleep方法用于暂停当前线程的执行指定时间。该方法属于Thread类,允许临时挂起线程而不终止它。sleep方法可能抛出InterruptedException,因此必须使用try-catch块处理。

目录

  1. sleep方法变体
  2. 使用sleep(long millis)方法示例
  3. 使用sleep(long millis, int nanos)方法示例
  4. 处理InterruptedException
  5. 结论

1. sleep方法变体

sleep(long millis)

暂停当前线程执行指定毫秒数。

sleep(long millis, int nanos)

暂停当前线程执行指定毫秒数+纳秒数。

2. 使用sleep(long millis)方法示例

输出:

3. 使用sleep(long millis, int nanos)方法示例

输出:

4. 处理InterruptedException

输出:

5. 结论

Java的sleep方法用于控制线程执行流程。通过sleep(long millis)sleep(long millis, int nanos)方法,可精确控制线程暂停时间。处理InterruptedException至关重要,确保程序能优雅处理中断。

]]>
Java多线程教程:Thread中的join方法 https://java.didispace.com/java-multithreading/1-5-thread-join.html https://java.didispace.com/java-multithreading/1-5-thread-join.html Java多线程教程:Thread中的join方法 Java多线程教程:Thread中的join方法 Java中的join方法用于暂停当前线程的执行,直到指定线程完成执行。当需要确保某个线程完成任务后再继续程序时,这个方法特别有用。join方法可以在线程实例上调用,有三种重载形式:join()、join(long millis)和join(long millis, int nanos)。 目录 join方法变体 使用join()方法示例 使用join(long millis)方法示例 使用join(long millis, int nanos)方法示例 结论 Java Tue, 11 Mar 2025 15:00:00 GMT Java多线程教程:Thread中的join方法

Java中的join方法用于暂停当前线程的执行,直到指定线程完成执行。当需要确保某个线程完成任务后再继续程序时,这个方法特别有用。join方法可以在线程实例上调用,有三种重载形式:join()join(long millis)join(long millis, int nanos)

目录

  1. join方法变体
  2. 使用join()方法示例
  3. 使用join(long millis)方法示例
  4. 使用join(long millis, int nanos)方法示例
  5. 结论

1. join方法变体

join()

暂停当前线程,直到指定线程执行完毕。

join(long millis)

暂停当前线程,等待指定毫秒数或线程完成(以先发生者为准)。

join(long millis, int nanos)

暂停当前线程,等待指定毫秒数+纳秒数或线程完成(以先发生者为准)。

2. 使用join()方法示例

输出:

3. 使用join(long millis)方法示例

输出:

4. 使用join(long millis, int nanos)方法示例

输出:

5. 结论

Java的join方法用于控制线程执行流程。通过join()join(long millis)join(long millis, int nanos)方法,可以确保某个线程完成后再继续其他线程的执行。这有助于协调任务,确保程序在必要条件满足后再继续运行。

]]>
Java多线程教程:Thread类 https://java.didispace.com/java-multithreading/1-3-thread-class.html https://java.didispace.com/java-multithreading/1-3-thread-class.html Java多线程教程:Thread类 Java多线程教程:Thread类 Java中的Thread类是创建和管理线程的主要机制。每个线程代表程序中的一个独立执行路径,允许并发操作并提高应用程序的性能和响应能力。 目录 Thread类概述 创建线程 继承Thread类 实现Runnable接口 线程生命周期 线程方法 示例:继承Thread类 示例:实现Runnable接口 线程优先级 线程同步 线程间通信 线程状态 守护线程 结论 Java Tue, 11 Mar 2025 13:00:00 GMT Java多线程教程:Thread类

Java中的Thread类是创建和管理线程的主要机制。每个线程代表程序中的一个独立执行路径,允许并发操作并提高应用程序的性能和响应能力。

目录

  1. Thread类概述
  2. 创建线程
    • 继承Thread
    • 实现Runnable接口
  3. 线程生命周期
  4. 线程方法
  5. 示例:继承Thread类
  6. 示例:实现Runnable接口
  7. 线程优先级
  8. 线程同步
  9. 线程间通信
  10. 线程状态
  11. 守护线程
  12. 结论

1. Thread类概述

Java中的Thread类属于java.lang包,提供构造方法和管理线程的方法。线程通过同时执行多个任务,使程序运行更高效。

Thread类的关键方法:

  • start():启动线程执行
  • run():包含线程执行的代码
  • sleep(long millis):使线程休眠指定时间
  • join():等待线程结束
  • interrupt():中断线程
  • isAlive():检查线程是否存活
  • getName():获取线程名称
  • setName(String name):设置线程名称
  • getPriority():获取线程优先级
  • setPriority(int priority):设置线程优先级

2. 创建线程

继承Thread

通过继承Thread类并重写run()方法创建线程:

实现Runnable接口

通过实现Runnable接口创建线程(推荐用于已继承其他类的情况):

3. 线程生命周期

线程在生命周期中会经历以下状态:

  • 新建(New):线程已创建但未启动
  • 可运行(Runnable):线程准备运行,等待CPU调度
  • 运行(Running):线程正在执行
  • 阻塞(Blocked):线程等待监视器锁
  • 等待(Waiting):线程无限期等待其他线程操作
  • 限时等待(Timed Waiting):线程在指定时间内等待其他线程操作
  • 终止(Terminated):线程执行完毕

4. 线程方法

  • start():启动线程,JVM调用run()方法
  • run():线程执行体(用户自定义逻辑)
  • sleep():暂停当前线程指定时间
  • join():等待线程结束
  • interrupt():中断线程
  • isAlive():检查线程是否存活
  • getName()/setName():获取/设置线程名称
  • getPriority()/setPriority():获取/设置线程优先级(1-10,默认5)

5. 示例:继承Thread类

输出:

6. 示例:实现Runnable接口

7. 线程优先级

线程优先级决定执行顺序(1-10,默认5):

输出:

8. 线程同步

通过synchronized关键字控制共享资源访问:

9. 线程间通信

使用wait()notify()notifyAll()实现协作:

输出:

10. 守护线程

守护线程是后台运行的低优先级线程(如垃圾回收):

输出:

12. 结论

Java的Thread类提供了强大的多线程管理机制。通过继承Thread类或实现Runnable接口,开发者可以创建并发任务。理解线程生命周期、同步机制、线程间通信和守护线程等概念,是编写高效健壮多线程应用的关键。

]]>
Java多线程教程:如何创建和启动线程 https://java.didispace.com/java-multithreading/1-1-how-to-create-and-start-a-thread.html https://java.didispace.com/java-multithreading/1-1-how-to-create-and-start-a-thread.html Java多线程教程:如何创建和启动线程 Java多线程教程:如何创建和启动线程 Java中的多线程允许多个线程并发运行,从而能够同时执行多个任务。线程是程序中的轻量级进程,它们共享相同的内存空间。本指南将介绍在Java中使用两种主要方法创建和启动线程的基础知识:扩展Thread类和实现Runnable接口。 目录 线程简介 通过扩展Thread类创建线程 通过实现Runnable接口创建线程 使用Lambda表达式创建线程 常用线程方法 示例程序 结论 Java Tue, 11 Mar 2025 11:00:00 GMT Java多线程教程:如何创建和启动线程

Java中的多线程允许多个线程并发运行,从而能够同时执行多个任务。线程是程序中的轻量级进程,它们共享相同的内存空间。本指南将介绍在Java中使用两种主要方法创建和启动线程的基础知识:扩展Thread类和实现Runnable接口。

目录

  1. 线程简介
  2. 通过扩展Thread类创建线程
  3. 通过实现Runnable接口创建线程
  4. 使用Lambda表达式创建线程
  5. 常用线程方法
  6. 示例程序
  7. 结论

1. 线程简介

线程是可以与其他线程并发运行的轻量级进程。Java通过java.lang.Thread类和java.lang.Runnable接口提供了对多线程的内置支持。多线程可以通过更好地利用系统资源来提高应用程序的性能。

2. 通过扩展Thread类创建线程

在Java中创建线程的一种方法是扩展Thread类并覆盖其run方法。

示例:

解释:

  • MyThread类扩展了Thread类。
  • run方法包含将由线程执行的代码。
  • main方法中,创建了一个MyThread对象,并调用start方法来启动线程。

3. 通过实现Runnable接口创建线程

在Java中创建线程的另一种方法是实现Runnable接口,并将实现类的实例传递给Thread对象。

示例:

解释:

  • MyRunnable类实现了Runnable接口。
  • run方法包含将由线程执行的代码。
  • main方法中,创建了一个MyRunnable对象,将其传递给Thread对象,并调用start方法来启动线程。

4. 使用Lambda表达式创建线程

从Java 8开始,您可以使用Lambda表达式以更简洁的方式创建线程。

示例:

解释:

  • Lambda表达式用于定义Runnable接口的run方法。
  • Lambda表达式被传递给Thread对象,并调用start方法来启动线程。

5. 常用线程方法

  • start():启动线程的执行。run方法由Java虚拟机(JVM)调用。
  • run():包含将由线程执行的代码。此方法由线程的start方法调用。
  • sleep(long millis):暂停当前线程的执行指定的毫秒数。
  • join():等待线程终止。此方法用于确保一个线程在另一个线程开始之前完成其执行。
  • isAlive():如果线程仍在运行或未终止,则返回true

6. 示例程序

示例1:扩展Thread

示例2:实现Runnable接口

示例3:使用Lambda表达式

7. 结论

在Java中创建和启动线程可以通过多种方法完成,包括扩展Thread类、实现Runnable接口以及使用Lambda表达式。每种方法都有其特定的用例和优势。了解这些方法和常见的线程操作可以帮助您在Java应用程序中有效地利用多线程。

]]>
Java多线程教程:Runnable接口 https://java.didispace.com/java-multithreading/1-2-runnable-interface.html https://java.didispace.com/java-multithreading/1-2-runnable-interface.html Java多线程教程:Runnable接口 Java多线程教程:Runnable接口 Java中的Runnable接口是一个函数式接口,用于定义可被线程执行的任务。它提供了一种定义并发执行任务的方式,常与Thread类或java.util.concurrent包中的执行器结合使用。 目录 Runnable接口概述 实现Runnable 运行Runnable 示例:实现并运行Runnable 结合Executor使用Runnable 使用Lambda表达式简化Runnable 使用Runnable的优势 结论 Java Tue, 11 Mar 2025 12:00:00 GMT Java多线程教程:Runnable接口

Java中的Runnable接口是一个函数式接口,用于定义可被线程执行的任务。它提供了一种定义并发执行任务的方式,常与Thread类或java.util.concurrent包中的执行器结合使用。

目录

  1. Runnable接口概述
  2. 实现Runnable
  3. 运行Runnable
  4. 示例:实现并运行Runnable
  5. 结合Executor使用Runnable
  6. 使用Lambda表达式简化Runnable
  7. 使用Runnable的优势
  8. 结论

1. Runnable接口概述

Runnable接口是一个单方法接口,仅定义了run()方法,该方法包含线程要执行的任务代码。

2. 实现Runnable

要创建Runnable任务,需定义一个类实现Runnable接口并实现run()方法。

示例:

3. 运行Runnable

运行Runnable任务有两种常见方式:

  • 通过Thread
  • 通过java.util.concurrent包中的执行器

通过Thread类运行:

4. 示例:实现并运行Runnable

完整示例:

输出:

说明:

  • MyRunnable类实现Runnable接口并覆盖run()方法。
  • 创建两个Thread对象,共享同一个MyRunnable实例。
  • 两个线程并发执行run()方法。

5. 结合Executor使用Runnable

java.util.concurrent包提供ExecutorService接口和线程池实现,能更灵活高效地管理线程。

示例:

输出:

说明:

  • 创建一个包含2个线程的固定线程池。
  • 提交两个MyRunnable任务到执行器。
  • 线程池中的线程并发执行run()方法。

6. 使用Lambda表达式简化Runnable

Java 8引入Lambda表达式后,可更简洁地创建Runnable实例。

示例:

输出:

说明:

  • 使用Lambda表达式直接定义Runnable的run()方法。
  • 创建两个Thread对象执行同一任务。

7. 使用Runnable的优势

  • 任务与执行解耦:任务逻辑与执行线程分离。
  • 设计灵活性:类可在实现Runnable的同时继承其他类。
  • 支持线程池:可与Executor框架结合,优化线程管理。
  • 代码简洁性:结合Lambda表达式减少冗余代码。

8. 结论

Runnable接口是Java多线程编程的核心工具,通过实现该接口,可定义能被线程或线程池执行的任务。结合Java 8的Lambda表达式,代码更简洁高效。掌握Runnable接口的使用对编写并发应用至关重要。

]]>
IDEA碰到:VM warning: Sharing is only supported for boot loader... https://java.didispace.com/article/20231014-VM_warning_Sharing.html https://java.didispace.com/article/20231014-VM_warning_Sharing.html IDEA碰到:VM warning: Sharing is only supported for boot loader... IDEA碰到:VM warning: Sharing is only supported for boot loader... 做个日常记录,今天调试一个使用Flux和R2DBC的应用,发现使用IDEA启动的时候报了下面的红色警告: OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended Java Sat, 14 Oct 2023 16:10:00 GMT IDEA碰到:VM warning: Sharing is only supported for boot loader...

做个日常记录,今天调试一个使用Flux和R2DBC的应用,发现使用IDEA启动的时候报了下面的红色警告:

处理这个警告的方法有两个:

第一个方法:添加VM参数-Xshare:off

如何配置vm参数,之前在Java新特性中的Preview功能如何运行和调试一文中提过,具体参考下面的图,记得修改参数:

第二个方法:在IDEA的Setting中做如下配置

参考资料

  • https://stackoverflow.com/questions/54205486/how-to-avoid-sharing-is-only-supported-for-boot-loader-classes-because-bootstra
]]>
IntelliJ IDEA 2024.1:增强对Spring和Quarkus框架的支持、GitHub Action的支持、更新HTTP Client等 https://java.didispace.com/article/idea-2024-1-eap5.html https://java.didispace.com/article/idea-2024-1-eap5.html IntelliJ IDEA 2024.1:增强对Spring和Quarkus框架的支持、GitHub Action的支持、更新HTTP Client等 IntelliJ IDEA 2024.1:增强对Spring和Quarkus框架的支持、GitHub Action的支持、更新HTTP Client等 有段时间没有更新IDEA了,早上看到 IntelliJ IDEA 2024.1 EAP 5发布的邮件提示,瞄了一眼,发现真的是越来越强了,其中不少功能对我来说还是非常有用的。也许这些能力对关注DD的小伙伴也有帮助,所以搞篇博客介绍和推荐一下。 Spring、Quarkus等主流框架的支持增强 Search Everywhere功能中增加Endpoints选项卡 IntelliJ IDEA Sat, 17 Feb 2024 13:00:00 GMT IntelliJ IDEA 2024.1:增强对Spring和Quarkus框架的支持、GitHub Action的支持、更新HTTP Client等

有段时间没有更新IDEA了,早上看到 IntelliJ IDEA 2024.1 EAP 5发布的邮件提示,瞄了一眼,发现真的是越来越强了,其中不少功能对我来说还是非常有用的。也许这些能力对关注DD的小伙伴也有帮助,所以搞篇博客介绍和推荐一下。

Spring、Quarkus等主流框架的支持增强

  1. Search Everywhere功能中增加Endpoints选项卡

具体如下图所示:

开发者可以在这里直接搜索通过Spring、Quarkus、Micronaut、Ktor实现的接口来找到具体的代码实现位置。这个功能非常实用,尤其是对于接手老项目的开发者来说,可以快速的定位接口实现来完成开发任务或问题排查。

  1. 增强Spring Bean的自动补全和自动装配

IntelliJ IDEA 现在为应用程序上下文中的所有 Bean 提供自动补全功能,并自动连接它们。

如果 bean 通过构造函数具有自动装配依赖项,则相关字段也会通过构造函数自动装配。

同样,如果通过字段或 Lombok 的 @RequiredArgsConstructor 注释注入依赖项,则新 bean 会自动通过字段连接。

  1. 增强 Spring 模型图

在该版本中用户访问Spring模型图变得更加容易,可以如下图这样点击Spring标识的行标记直接跳转:

也可以使用快捷键 ⌥⏎ (MacOS) 或 Alt+Enter(Windows)来生成和跳转。

同时,该版本还引入了新的图标,增强了 Spring 模型图的可视化内容,如:ComponentsControllersRepositories。此外,您现在可以方便地切换库中 Bean 的可见性(默认情况下是隐藏的)。

HTTP Client的改进

HTTP Client现在提供更多身份验证选项,包括 PKCE 授权代码和设备授予流程。它还支持令牌和身份验证请求的额外参数。

现在它可以自动处理 code_challengepasses code_verifier 的生成,以便在 PKCE 请求中检索令牌。

这个版本的HTTP Client 可以使用 Netty 作为其低级网络库。通过支持 SSL、代理和 HTTP/2,使我们能够在 HTTP 客户端中实现 HTTP/2 的支持。

此外,HTTP Client的工具栏外观,也与新的 UI 风格保持一致,提供更加美观的用户体验。

GitHub Action的支持增强

  1. Workflow 上下文的支持

现在可以为各种 GitHub Action上下文引入了广泛的自动完成支持,包括github.*env.*steps.*inputs.*

这个优化非常有用,可以有效的降低编写复杂工作流脚本的过程,开发人员不用再去频繁的搜索上下文中涉及的参数了。

该优化在YAML文件配置中也同样有效:

YAML文件中,开发者还可以使用 branding 功能使用特定图标和颜色指示器自定义 GitHub 上操作的外观。

此功能使操作创建者能够在 GitHub Marketplace 和工作流程中直观地区分他们的操作,使它们更易于识别和用户友好。通过在 action.yml 文件中指定图标和颜色,开发人员可以一目了然地传达其操作的目的,从而增强整体用户体验。这种可视化定制有助于对操作进行分类,并帮助用户快速识别 CI/CD 管道所需的工具。

  1. Docker 镜像自动补全

此增强功能在 GitHub 工作流程文件中提供image和tag建议,从而更轻松地将 Docker 容器集成到您的操作中。

  1. JavaScript 文件路径补全

文件路径完成功能会自动建议文件路径,从而简化 JavaScript 操作的配置并简化工作流程执行。

其他更新

  • 优化JSON schema的处理: 优化了 JSON 模式验证和完成背后的代码。因此,IDE 现在可以更快地处理此任务并减少内存消耗。在使用 Azure Pipelines 的现实文件中,架构检查现在速度提高了 10 倍。

  • 现在可以在所有常见场景中轻松完成 HTTP Header,例如使用 Spring WebClient 和 RestAssured 测试。当遇到预期值时,会自动出现完成弹出窗口。

另外,DD最近把博客重新增加了板块,正在维护几个有意思的长期连载专栏,其中一个就是《玩转IDEA》,这次换了工具,直接采用电子文档的形式,阅读体验更好,​对这些内容感兴趣的,可以关注起来!

]]>
IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式 https://java.didispace.com/article/idea-2024-2-release.html https://java.didispace.com/article/idea-2024-2-release.html IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式 IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式 今早看到,IntelliJ IDEA 2024.2 发布的邮件提示,看了一眼这个版本更新的新特性真的太适合我了!也许这些能力对关注DD的小伙伴也有帮助,所以搞篇博客介绍和推荐一下。下面就来一起看看这个版本中推出的几个强大新特性。 Spring Data JPA 的即时查询 IntelliJ IDEA Fri, 09 Aug 2024 11:00:00 GMT IntelliJ IDEA 2024.2 发布:Spring Data JPA即时查询、自动补全cron表达式

今早看到,IntelliJ IDEA 2024.2 发布的邮件提示,看了一眼这个版本更新的新特性真的太适合我了!也许这些能力对关注DD的小伙伴也有帮助,所以搞篇博客介绍和推荐一下。下面就来一起看看这个版本中推出的几个强大新特性。

Spring Data JPA 的即时查询

在2024.2 Ultimate版本中,对 Spring Data JPA 的支持做了增强。新功能允许您在不运行应用程序和分析日志文件的情况下查看方法将生成的查询。现在,开发者可以直接在 JPA 控制台中执行任何仓库的方法来快速验证数据库操作是否正确。

cron表达式的自动补全

相信每个Spring开发者都用过@Schedule来定义一些简单的定时任务,对于执行规则的定义使用CRON表达式是非常常用的,但是很多人对于编写CRON表达式并不那么熟悉。现在,2024.2 Ultimate版本可以解决这个问题了,当开发者在写好cron属性的时候,会弹出自动补全来给出提示,你可以看到各种基础模版,太方便了!

GraalJS 作为 HTTP 客户端的执行引擎

现在 HTTP 客户端中使用的 JavaScript 执行引擎升级为 GraalJS。 这将使得开发者可以在使用 IntelliJ IDEA 的 HTTP 客户端测试端点以及在 .http 文件中使用 JavaScript 处理结果时使用所有 GraalJS 功能,包括对 ECMAScript 2023 规范的完全支持。

日志管理增强

IntelliJ IDEA 2024.2 为 Java 和 Kotlin 引入了增强的日志管理。

新功能包括字符串文字和实参解析的高亮显示,让您可以从占位符无缝导航到对应实参,同时IDEA还可以检查出不匹配的log占位符和参数量:

对于 System.out.println 语句,现在支持一键转换成log形式:

运行时的性能图表

在 Run 工具窗口中实现了新的 Performance 标签页。 新的标签页提供实时 CPU 和内存图表,并允许您捕获代码的执行时间并直接在编辑器中查看来查明性能瓶颈。 此外,您还可以捕获内存快照来检查对象并找出内存泄漏的根本原因。

JSON、XML 和其他格式的字符串变量可视化工具

现在,调试和浏览复杂数据格式变得容易多了。更新后的调试器可以可视化 JSON、XML、HTML、JWT 和 URL 编码的字符串变量只需点击变量旁边的 View 链接,相关的可视化器便会根据变量的内容自动选择。

其他更新

  • 更快开始编码:优化了IDEA的启动体验。开发者可以在IDEA没有完全启动完成的情况下,也能进行关键功能的访问和编码操作。

  • Markdown支持数学语法,现在可以使用$插入内联数学表达式,使用$$插入包含数学内容的代码块。

  • K2模式稳定性改进和性能提升:这种新的 Kotlin 支持机制为未来的 Kotlin 语言功能奠定了基础,也增强了 IDE 的稳定性和性能。 在 2024.2 版本中,K2 模式现在支持 gradle.kts 脚本、Kotlin Multiplatform (KMP) 项目、所有主要重构、代码高亮显示、调试等。 基准测试表明,K2 模式使 IntelliJ IDEA Ultimate 源库上的代码高亮显示性能几乎翻了一番。

更多关于本版本的更新内容,还可以查阅官方信息:https://www.jetbrains.com/idea/whatsnew/

如果您关注IDEA的内容,还可以查看近期整理的《玩转IDEA》专栏,这次换了工具,直接采用电子文档的形式,阅读体验更好,​对这些内容感兴趣的,可以关注起来!

]]>
30秒免申请直接用上IDEA新UI https://java.didispace.com/article/idea-new-ui-jihuo.html https://java.didispace.com/article/idea-new-ui-jihuo.html 30秒免申请直接用上IDEA新UI 30秒免申请直接用上IDEA新UI 早上给大家介绍了IDEA官方宣布正在开发一套全新的UI,但目前是预览版需要申请才能体验。 随后马上就有网友分享了,不需要申请直接就能激活体验的方法。 本期视频:https://www.bilibili.com/video/BV165411X7u7 只需要下面几步: 下载最新的IDEA版本(DD尝试了2022.1版本,后面的版本应该都会包含,之前的版本不确定) IntelliJ IDEA Thu, 26 May 2022 14:00:00 GMT 30秒免申请直接用上IDEA新UI

早上给大家介绍了IDEA官方宣布正在开发一套全新的UI,但目前是预览版需要申请才能体验。

随后马上就有网友分享了,不需要申请直接就能激活体验的方法。

本期视频:https://www.bilibili.com/video/BV165411X7u7

只需要下面几步:

  1. 下载最新的IDEA版本(DD尝试了2022.1版本,后面的版本应该都会包含,之前的版本不确定)

下载地址:https://www.jetbrains.com/zh-cn/idea/nextversion/

  1. shift键连续按两次,搜索registry:

图 1

  1. 找到ide.experimental.ui选项,勾选上

图 2

  1. 重启IDE,成功切换!

图 3

  1. 最后DD又折腾了一下主题,这下舒坦了!欢迎关注我的公众号:程序猿DD,后面继续分享下配置!

图 4

另外,给大家提一下,我最近把博客重新增加了板块,正在维护几个有意思的长期连载专栏,其中一个就是《玩转IDEA》,这次换了工具,直接采用电子文档的形式,阅读体验更好,​对这些内容感兴趣的,可以关注起来!点击直达:《玩转IDEA》

]]>
JetBrains IDE全新UI预览版来了,目标:简洁与强大兼顾! https://java.didispace.com/article/idea-new-ui.html https://java.didispace.com/article/idea-new-ui.html JetBrains IDE全新UI预览版来了,目标:简洁与强大兼顾! JetBrains IDE全新UI预览版来了,目标:简洁与强大兼顾! 5月23日,JetBrains发布了一篇博文,透露他们正在实现一套全新的界面界面。 他们认为目前行业中的用户界面趋势已经发生了演变,很多新用户认为JetBrains IDE的界面过于笨重,而且过时。所以,团队做出了大胆的决定,将以全新的眼光来重新设计IntelliJ IDEA和相关IDE的外观和感觉。 IntelliJ IDEA Thu, 26 May 2022 03:00:00 GMT JetBrains IDE全新UI预览版来了,目标:简洁与强大兼顾!

5月23日,JetBrains发布了一篇博文,透露他们正在实现一套全新的界面界面。

JetBrains IDE全新UI预览

他们认为目前行业中的用户界面趋势已经发生了演变,很多新用户认为JetBrains IDE的界面过于笨重,而且过时。所以,团队做出了大胆的决定,将以全新的眼光来重新设计IntelliJ IDEA和相关IDE的外观和感觉。

而这次重新设计的核心目标就是降低视觉复杂性,提供对基本功能的轻松访问,并根据需要逐步展开复杂的功能,这就是目前JetBrains团队认为的干净、现代和强大的外观和感觉。

根据官博中的描述,新UI中的主要变更包括以下四个方面:

  • 简化主工具栏:使用新VCS、Project以及Run小部件
  • 新的工具窗口布局
  • 新的浅色和深色主题
  • 全新的图标

文章开头给出的预览对于这一核心设计理念的初步体现还是很明显,整体界面相比目前的IDEA是要简洁、干净很多的,那么根据需要逐步展开的强大功能会怎么样实现呢?可能还得真正用上了才有所体会吧。

目前因为还只是预览版本,如果要使用的话,可以通过官方给出了这个申请链接提交申请后试用,DD已经提交申请了,不知道什么时候可以通过,期待一下!

申请链接https://www.jetbrains.com/lp/intellij-new-ui-preview/

当然了,如果你懒的申请也不要紧,关注我等我后续体验后给大家分享也是ok的。

另外,给大家提一下,我最近把博客重新增加了板块,正在维护几个有意思的长期连载专栏,其中一个就是《玩转IDEA》,这次换了工具,直接采用电子文档的形式,阅读体验更好,​对这些内容感兴趣的,可以关注起来!点击直达:《玩转IDEA》

]]>
使用Java 17中的record替代Lombok的部分功能 https://java.didispace.com/article/java-17-records-avoid-lombok.html https://java.didispace.com/article/java-17-records-avoid-lombok.html 使用Java 17中的record替代Lombok的部分功能 使用Java 17中的record替代Lombok的部分功能 在DD长期更新的Java新特性专栏中,已经介绍过Java 16中开始支持的新特性:record的使用。 Java Wed, 10 Jan 2024 13:10:00 GMT 使用Java 17中的record替代Lombok的部分功能

在DD长期更新的Java新特性专栏中,已经介绍过Java 16中开始支持的新特性:record的使用。

之前只是做了介绍,但没有结合之前的编码习惯或规范来聊聊未来的应用变化。最近正好因为互相review一些合作伙伴的代码,产生了一些讨论话题,主要正针对于有了record之后,其实之前有些用Lombok的场景,是可以替换掉了。

今天我们就来小小的总结下,我们可以在哪些地方,利用record来替换Lombok

Lombok的威力

Lombok是我一直都喜欢使用的工具,因为它可以让我们的代码变的更加整洁。比如:当我们要写一个User对象的时候,如果不使用Lombok,往往需要写这么多内容:

在有了Lombok之后呢,通过使用@Data注解,可以将以上内容缩减到只需要下面这几行即可:

@Data注解涵盖了@Getter@Setter@EqualsAndHashCode@toString,所以一个注解就可以实现成员变量的Getter和Setter,equals和hashcode方法的重写,以及toString的重写。大大降低了代码量,让代码看上去更加整洁。

Lombok的问题

虽然Lombok可以帮助我们少些很多代码,但它依然有一些缺点,比如:

  1. Lombok并非Java官方提供,而是第三方依赖,依靠社区维护。对于较新的Java版本通常都会存在兼容性问题,容易产生一些不可预知的奇怪错误。
  2. IDE的兼容限制,并不是所有的IDE都可以完美兼容Lombok,所以可能也会因此产生一些奇怪的错误。

使用record来替代

在之前的Java 新特性:record一文中,已经提到过record类可以根据类的字段自动生成:构造函数、equals()、hashCode() 和 toString()。这个功能就跟上面我们演示的Lombok中的@Data非常类似。

写法的话也非常简单,只需要这样一行即可搞定:

可以看到该代码的整洁度比Lombok的实现更加干净。同时,最关键的一点,这是Java原生支持的,不需要引入任何第三方依赖!

record类定义完成了,具体使用的话就跟平时使用其他类一样,去创建实例和调用方法即可,比如下面这样:

只是,我们在使用的时候需要了解record自动生成的代码与Lombok的区别,就能马上上手。

比如,从上面的例子中我们可以看到一个区别:获取成员变量email的时候,这里并不想传统getter那样以getEmail()的形式生成。

哪些情况替代不了?

record类已经很强大,但目前并不能完全替代Lombok。主要原因如下:

  1. record中定义的成员变量是final类型的,初始化后就不能修改了
  2. record类不能被继承,所以也无法进一步扩展

因此,在用record替代Lombok的时候,更多用来定义静态变量,而不是可能会变化的实例变量。但是,由于record中也可以定义函数,所以对于一些对成员计算获得的内容,也可以实现和使用。

总结

Lombokrecord都可以帮助我们编写更加整洁的代码。前者是第三方库,可能存在一些不可预知的问题和IDE兼容问题,但功能更加全面和强大;后者属于Java原生的能力,功能虽弱一些,但用好它也能帮助我们减少很多代码的编写,且IDE兼容性更好。

好了,今天的分享就到这里。如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!更多Java新特性教程可以点击直达!,欢迎收藏与转发支持!

]]>
启动1000万个虚拟线程需要多少时间?需要多少平台线程? https://java.didispace.com/article/java-21-virtaul-threads.html https://java.didispace.com/article/java-21-virtaul-threads.html 启动1000万个虚拟线程需要多少时间?需要多少平台线程? 启动1000万个虚拟线程需要多少时间?需要多少平台线程? 之前,在Java新特性专栏中,我们简单介绍了Java 21正式发布的虚拟线程。 昨天,正好看到一个讲解此内容的视频,非常不错,所以DD这里给大家翻译好了,感兴趣的可以看看。可以进一步了解虚拟线程。 Java Wed, 25 Oct 2023 12:10:00 GMT 启动1000万个虚拟线程需要多少时间?需要多少平台线程?

之前,在Java新特性专栏中,我们简单介绍了Java 21正式发布的虚拟线程

昨天,正好看到一个讲解此内容的视频,非常不错,所以DD这里给大家翻译好了,感兴趣的可以看看。可以进一步了解虚拟线程。

]]>
详解Java G1垃圾回收器 https://java.didispace.com/article/java-g1.html https://java.didispace.com/article/java-g1.html 详解Java G1垃圾回收器 详解Java G1垃圾回收器 G1垃圾回收器是在Java7 update 4之后引入的一个新垃圾回收器,主要目的是用来替代CMS。 G1最大的特点是引入分区的思路,弱化了分代的概念,合理利用垃圾收集各个周期的资源,解决了其他收集器甚至CMS的众多缺陷。从而实现进一步降低暂停时间的同时,兼顾良好的吞吐量。 那么G1垃圾回收器的细节是怎么样的呢? 这里DD找到一个不错的视频,里面包含想的图示说明和代码案例,可以帮助您更好的理解G1垃圾回收器: Java Tue, 24 Oct 2023 12:10:00 GMT 详解Java G1垃圾回收器

G1垃圾回收器是在Java7 update 4之后引入的一个新垃圾回收器,主要目的是用来替代CMS。

G1最大的特点是引入分区的思路,弱化了分代的概念,合理利用垃圾收集各个周期的资源,解决了其他收集器甚至CMS的众多缺陷。从而实现进一步降低暂停时间的同时,兼顾良好的吞吐量。

那么G1垃圾回收器的细节是怎么样的呢?

这里DD找到一个不错的视频,里面包含想的图示说明和代码案例,可以帮助您更好的理解G1垃圾回收器:

]]>
如何在Java中读取超过内存大小的文件 https://java.didispace.com/article/java-process-large-file.html https://java.didispace.com/article/java-process-large-file.html 如何在Java中读取超过内存大小的文件 如何在Java中读取超过内存大小的文件 读取文件内容,然后进行处理,在Java中我们通常利用 Files 类中的方法,将可以文件内容加载到内存,并流顺利地进行处理。但是,在一些场景下,我们需要处理的文件可能比我们机器所拥有的内存要大。此时,我们则需要采用另一种策略:部分读取它,并具有其他结构来仅编译所需的数据。 接下来,我们就来说说这一场景:当遇到大文件,无法一次载入内存时候要如何处理。 模拟场景 假设,当前我们需要开发一个程序来分析来自服务器的日志文件,并生成一份报告,列出前 10 个最常用的应用程序。 每天,都会生成一个新的日志文件,其中包含时间戳、主机信息、持续时间、服务调用等信息,以及可能与我们的特定方案无关的其他数据。 Java Fri, 29 Mar 2024 14:10:00 GMT 如何在Java中读取超过内存大小的文件

读取文件内容,然后进行处理,在Java中我们通常利用 Files 类中的方法,将可以文件内容加载到内存,并流顺利地进行处理。但是,在一些场景下,我们需要处理的文件可能比我们机器所拥有的内存要大。此时,我们则需要采用另一种策略:部分读取它,并具有其他结构来仅编译所需的数据。

接下来,我们就来说说这一场景:当遇到大文件,无法一次载入内存时候要如何处理。

模拟场景

假设,当前我们需要开发一个程序来分析来自服务器的日志文件,并生成一份报告,列出前 10 个最常用的应用程序。

每天,都会生成一个新的日志文件,其中包含时间戳、主机信息、持续时间、服务调用等信息,以及可能与我们的特定方案无关的其他数据。

我们的代码将收到日志文件列表,我们的目标是编制一份报告,列出最常用的 10 个服务。但是,要包含在报告中,服务必须在提供的每个日志文件中至少有一个条目。简而言之,一项服务必须每天使用才有资格包含在报告中。

基础实现

解决这个问题的最初方法是考虑业务需求并创建以下代码:

该方法接收文件列表作为参数,核心流程如下:

  • 创建一个包含每个文件条目的映射,其中Key是 LocalDate,Value是文件行列表。
  • 使用所有文件中的唯一服务名称创建字符串列表。
  • 生成所有服务的统计信息列表,将文件中的数据组织到结构化地图中。
  • 筛选统计信息,获取排名前 10 的服务调用。
  • 打印结果。

可以注意到,这种方法将太多数据加载到内存中,不可避免地会导致 OutOfMemoryError

改进实现

就如文章开头说的,我们需要采用另一种策略:逐行处理文件的模式。

  • 首先,它声明一个Map(compiledMap),其中一个String作为键,代表服务名称,以及一个Counter对象(稍后解释),它将存储统计信息。
  • 接下来,它逐一处理这些文件并相应地更新compileMap。
  • 然后,它利用流功能来: 仅过滤具有全天数据的计数器;按调用次数排序;最后,检索前 10 名。

在看整个处理的核心processFile方法之前,我们先来分析一下Counter类,它在这个过程中也起到了至关重要的作用:

  • 它包含三个属性:serviceName、numberOfCalls 和 daysWithCalls
  • numberOfCalls 属性通过 add 方法递增,该方法为 serviceName 的每个处理行调用。
  • daysWithCalls 属性是一个 Java BitSet,一种用于存储布尔属性的内存高效结构。它使用要处理的天数进行初始化,每个位代表一天,初始化为 false。
  • setDay 方法将 BitSet 中与给定日期位置相对应的位设置为 true。

allDaysSet 方法负责检查 BitSet 中的所有日期是否都设置为 true。它通过将 BitSet 转换为布尔流,然后使用逻辑 AND 运算符减少它来实现此目的。

  • 该过程使用Files类的lines方法逐行读取文件,并将其转换为流。这里的关键特征是lines方法是惰性的,这意味着它不会立即读取整个文件;相反,它会在流被消耗时读取文件。
  • toLogLine 方法将每个字符串文件行转换为具有用于访问日志行信息的属性的对象。
  • 处理文件行的主要过程比预期的要简单。它从与serviceName关联的compileMap中检索(或创建)Counter,然后调用Counter的add和setDay方法。

正如我们所看到的,在 Java 中处理大文件而不将整个文件加载到内存中并不是什么复杂的事情。 Files类提供了逐行处理文件的方法,我们还可以在文件处理过程中利用哈希来存储数据,这有助于节省内存。

]]>
8个实用的Java Streams API https://java.didispace.com/article/java-streams-api-features.html https://java.didispace.com/article/java-streams-api-features.html 8个实用的Java Streams API 8个实用的Java Streams API 分享8个开箱即用的API,方便日常处理集合。 1. 快速过滤空值:Stream.ofNullable 该方法是在 Java 9 中引入的,有助于过滤集合中的所有空值,从而可能使我们避免空指针异常。 在下面的示例中,有一个包含 null 的List。此时,我们可以使用Stream.ofNullable方法对其进行过滤。 List&lt;String&gt; names = Arrays.asList(&quot;Alice&quot;, null, &quot;Bob&quot;, null, &quot;Charlie&quot;); List&lt;String&gt; nonNuLLNames = names.stream() .flatMap(Stream::ofNullable) .collect(Collectors.toList()); System.out.println(nonNuLLNames); Java Tue, 04 Jun 2024 11:10:00 GMT 8个实用的Java Streams API

分享8个开箱即用的API,方便日常处理集合。

1. 快速过滤空值:Stream.ofNullable

该方法是在 Java 9 中引入的,有助于过滤集合中的所有空值,从而可能使我们避免空指针异常。

在下面的示例中,有一个包含 null 的List。此时,我们可以使用Stream.ofNullable方法对其进行过滤。

执行上述代码,将输出:

2. 流式迭代:Stream.iterate()

Stream.iterate()方法用于创建无限的序列流。它采用种子和一元函数,将函数应用于前一个元素。

在下面的例子中,我们的种子是0,一元运算函数是 n -> n+2。

执行上述代码,将输出:

注意:由于Stream.iterate()生成的是无限序列流。因此我们应该定义终止条件,例如:limit、findFirst 或 findAny 等,以避免无限循环。

3. 集合转换:collectingAndThen()

collectingAndThen()方法是在 Java 8 中引入的。它是一种特殊的收集器,允许您对另一个收集器的结果执行特殊类型的转换。

在下面的示例中,我们的收集器通过首先使用索引到大写操作进行映射,然后使该映射成为不可修改的Map进行转换。

执行上述代码,将输出:

4. 删除和截取:dropWhile()takeWhile()

dropWhile()takeWhile()方法是在 java9 中引入的,用于连续处理流。

  • takeWhile():返回符合条件的元素流
  • dropWhile():从元素流中删除符合条件的元素

在下面的示例中,我们删除小于3的元素,然后返回元素小于6的元素流。

执行上述代码,将输出:

5. 整数流:IntStream

IntStream 在 Java 8 中引入,用于快速生成整数流,常用有的以下两个方法:

  • IntStream.range() 方法生成一个整数流,该整数流不包含结尾数字
  • IntStream.rangeClosed() 方法生成一个整数流,该整数流包含结尾数字

下面的例子,可以清晰的看到区别:

6. 应用多个收集器:teeing()

Java 12 中引入的teeing()方法是为了我们可以在元素流上一起应用两个单独的收集器而创建的。

在下面的示例中,我们使用teeing()计算元素流的最大值和最小值,然后将结果以Map形式返回。

执行上述代码,将输出:

7. 合并流:Stream.concat()

Stream.concat()方法可以用来连接两个流并生成一个新流。

执行上述代码,将输出:

8. 分组:Collectors.partitioningBy

Collectors.partitioningBy可以用来对流进行分组。

在下面的示例中,我们根据元素的字符串长度分为两个不同的组。

执行上述代码,将输出:

今天的分享就到这里。如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!

]]>
玩转IDEA https://java.didispace.com/idea-tips/ https://java.didispace.com/idea-tips/ 玩转IDEA 玩转IDEA IDEA是目前Java体系最为强大的开发工具,但也因为强大,有很多功能可能你并不知道。 所以,本文档讲帮助你了解IDEA更多牛x的功能、还会给你推荐很多有意思的插件! IntelliJ IDEA Sun, 10 Apr 2022 00:00:00 GMT 玩转IDEA

IDEA是目前Java体系最为强大的开发工具,但也因为强大,有很多功能可能你并不知道。

所以,本文档讲帮助你了解IDEA更多牛x的功能、还会给你推荐很多有意思的插件!

]]>
玩转IntelliJ IDEA:新建项目的默认配置 https://java.didispace.com/idea-tips/common/project-default-config.html https://java.didispace.com/idea-tips/common/project-default-config.html 玩转IntelliJ IDEA:新建项目的默认配置 玩转IntelliJ IDEA:新建项目的默认配置 今天一大早,群里(点击加群)有小伙伴问了这样的一个问题: 在我们使用IDEA开发项目的时候,通常都会有很多配置项需要去设置,比如对于Java项目来说,一般就包含:JDK配置、Maven配置等。那么如果想要设置一个默认的项目配置的话,要如何做呢? IntelliJ IDEA Wed, 27 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:新建项目的默认配置

今天一大早,群里(点击加群)有小伙伴问了这样的一个问题:

在我们使用IDEA开发项目的时候,通常都会有很多配置项需要去设置,比如对于Java项目来说,一般就包含:JDK配置、Maven配置等。那么如果想要设置一个默认的项目配置的话,要如何做呢?

先来找到入口,在File菜单中找到New Projects Setup菜单项,细节如下图所示:

这里的几个功能都是用来配置新建项目时要做的一些默认选项。

新建项目的基础默认配置

通过Preferences for New Projects...可以配置新建项目的基础默认配置,包括外观、编辑器、版本控制、构建、执行、部署等一系列的基础内容:

Preferences for New Projects...

这里也包括群友(点击加群)问的,如何设置默认Maven版本的配置,就可以在这里通过搜索Maven来找到配置的地方:

默认Maven配置

新建项目的运行模版

第二个菜单项Run Configuration Templates...可以用来配置我们常用的运行配置模版,比如:如果你也用一些agent来辅助开发调试的话,就可以在下图VM options输入框中加入启动参数,这样你就不需要为每个新项目手工配置了。

Run Configuration Templates

默认SDK的设置

第三个菜单项Structure...可以用来配置新建项目的默认SDK:

Structure...

项目模版的管理

上面的所有配置主要是作为默认配置来使用,但默认配置只能有一种,可以视为最常用的配置,其他配置只是偶尔使用的时候,还比较有效。但有时候我们又有可能有多种不同的常用配置,这个时候仅仅依靠默认配置就不太够了。

此时下面的两个菜单项Save Project as TemplateManage Project Templates功能则提供了更好的支持。我们可以通过Save Project as Template将一个现存的项目报错为模版,而在Manage Project Templates里可以对模版进行管理。

然后当我们要新建项目的时候,就可以在左侧最下方找到我们创建的各种项目模板来实现新项目的创建:

通过模版创建项目

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
IDEA 护眼配置方案 https://java.didispace.com/idea-tips/common/protect-eyes.html https://java.didispace.com/idea-tips/common/protect-eyes.html IDEA 护眼配置方案 IDEA 护眼配置方案 很多人都喜欢使用黑色的主题样式,包括我自己,使用了差不多三年的黑色主题,但是个人觉得在进行视窗转换的时候很废眼睛。 比如IDEA是全黑的,然后需要看PDF或者WORD又变成白色的了,这样来回切换导致眼睛很累,毕竟现在网页以及大部分软件的界面都是白色的。那么还是老老实实的使用原来比较顺眼的模式吧。 1、编辑器界面如下(图片太小可通过电脑查看) 主题使用最基本亮主题就可以,当然也可以去主题官网下载。 IntelliJ IDEA Wed, 25 May 2022 00:00:00 GMT IDEA 护眼配置方案

很多人都喜欢使用黑色的主题样式,包括我自己,使用了差不多三年的黑色主题,但是个人觉得在进行视窗转换的时候很废眼睛。

比如IDEA是全黑的,然后需要看PDF或者WORD又变成白色的了,这样来回切换导致眼睛很累,毕竟现在网页以及大部分软件的界面都是白色的。那么还是老老实实的使用原来比较顺眼的模式吧。

1、编辑器界面如下(图片太小可通过电脑查看)

主题使用最基本亮主题就可以,当然也可以去主题官网下载。

图 1

图 2

2、修改字体

图 3

这款字体想必是程序猿标配了。

3、设置Console字体

图 4

4、设置背景颜色(这是主要步骤)

有研究表明这个颜色色系比较温和,对眼睛刺激很小。

颜色代码:C6EECB

图 5

5、设置只读文件背景颜色

图 6

6、设置控制台背景颜色和标准输出背景色

图 7

图 8

7、设置行号区域背景色

图 9

喜欢的赶紧用上吧!

版权声明:本文为CSDN博主「Lewis-q398529803」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_46017976/article/details/112363497

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IntelliJ IDEA配置侧边栏显示文件最后更新时间 https://java.didispace.com/idea-tips/common/view-last-modify-time.html https://java.didispace.com/idea-tips/common/view-last-modify-time.html IntelliJ IDEA配置侧边栏显示文件最后更新时间 IntelliJ IDEA配置侧边栏显示文件最后更新时间 昨天分享了自动生成spring.factories和org.springframework.boot.autoconfigure.AutoConfiguration.imports文件的方法,然后看到有网友留言问了几个问题,下面是其中一个: IntelliJ IDEA Wed, 25 May 2022 00:00:00 GMT IntelliJ IDEA配置侧边栏显示文件最后更新时间

昨天分享了自动生成spring.factories和org.springframework.boot.autoconfigure.AutoConfiguration.imports文件的方法,然后看到有网友留言问了几个问题,下面是其中一个:

图 1

这个功能只需要配置一下就可以了,具体配置位置:

图 2

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
玩转IntelliJ IDEA:调试的操作回退(2) https://java.didispace.com/idea-tips/debug/debug-backward-jump-to-line.html https://java.didispace.com/idea-tips/debug/debug-backward-jump-to-line.html 玩转IntelliJ IDEA:调试的操作回退(2) 玩转IntelliJ IDEA:调试的操作回退(2) 上一篇关于调试操作回退的介绍中,我们采用了Reset Frame(Drop Frame)来实现。但该操作有一定的局限性,所以,这篇我们将介绍一个插件来帮助弥补Reset Frame做不到的一些回退操作。 视频演示:点击这里查看 IntelliJ IDEA Tue, 03 May 2022 00:00:00 GMT 玩转IntelliJ IDEA:调试的操作回退(2)

上一篇关于调试操作回退的介绍中,我们采用了Reset Frame(Drop Frame)来实现。但该操作有一定的局限性,所以,这篇我们将介绍一个插件来帮助弥补Reset Frame做不到的一些回退操作。

视频演示:点击这里查看

插件:Jump To Line

这个插件可以帮助我们在调试的时候,向前或向后跳到想要执行的语句处。这里就包括了Reset Frame无法回退的位置,比如下面这个小片段:

Jump To Line回退操作

更详细的操作演示可以点击这里查看视频

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
玩转IntelliJ IDEA:条件断点 https://java.didispace.com/idea-tips/debug/debug-condition-point.html https://java.didispace.com/idea-tips/debug/debug-condition-point.html 玩转IntelliJ IDEA:条件断点 玩转IntelliJ IDEA:条件断点 今天给大家分享一个IDEA调试过程中的一个小技巧。 先来说说场景,你有没有碰到类似的情况,一个循环结构里,中间某一个情况可能会出错。比如下面的代码结果中,可能执行到第27次的时候,会出现问题。 for(int i = 0; i &lt; 100; i++) { // 业务逻辑 System.out.println(i); } IntelliJ IDEA Mon, 18 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:条件断点

今天给大家分享一个IDEA调试过程中的一个小技巧。

先来说说场景,你有没有碰到类似的情况,一个循环结构里,中间某一个情况可能会出错。比如下面的代码结果中,可能执行到第27次的时候,会出现问题。

那么这个时候,你会怎么调试的呢?是不是像下面这样加个断点

然后狂点绿色小箭头,到将来出错的那一次?

其实IDEA中有个功能,可以给断点增加条件,这样就不用那么麻烦了。

操作也很简单,只需要右键已经添加的断点小红点,此时会弹出一个表单,里面有condition这一项,具体如下图:

这里就可以输入你希望这个断点生效的条件,比如我这里输入了i == 27,那么当这个循环执行到i等于27的时候,程序就会停下。

这样,你就不需要靠疯狂的点执行让他不断跳过,来到你想要的循环阶段了。

当然,条件断点不光在循环中可以用,还有很多复杂的调试场景可以使用。

本文还配有视频版本的演示,如果文字内容没能消化话,也可以点击这里查看视频内容。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
IntelliJ IDEA如何优雅的调试Java Stream操作 https://java.didispace.com/idea-tips/debug/debug-stream.html https://java.didispace.com/idea-tips/debug/debug-stream.html IntelliJ IDEA如何优雅的调试Java Stream操作 IntelliJ IDEA如何优雅的调试Java Stream操作 什么是Stream操作 Stream操作是Java 8推出的一大亮点,它与java.io包里的InputStream和OutputStream是完全不同的概念。Java 8中的Stream是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的 聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。 同时,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。通常,编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java8中首次出现的java.util.stream是一个函数式语言 + 多核时代综合影响的产物。 IntelliJ IDEA Thu, 19 May 2022 00:00:00 GMT IntelliJ IDEA如何优雅的调试Java Stream操作

什么是Stream操作

Stream操作是Java 8推出的一大亮点,它与java.io包里的InputStream和OutputStream是完全不同的概念。Java 8中的Stream是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的 聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。

同时,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。通常,编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java8中首次出现的java.util.stream是一个函数式语言 + 多核时代综合影响的产物。

虽然java.util.stream很强大,但依然还是有很多开发者在实际工作中很少使用,其中吐槽最多的一个原因就是不好调试,一开始确实是这样,因为stream这样的流式操作在DEBUG的时候,是一行代码,直接下一步的时候,其实一下就过去了好多操作,这样我们就很难判断到底是里面的哪一行出了问题。

不过,现在的话,在强大的IDEA支持下,stream的调试其实也没那么难了,下面就来学习一下在IDEA中如何调试stream操作吧。

调试Stream操作

视频演示:点击这里查看

先来看下面这样的这段代码:

这段代码的逻辑是通过stream去过滤list集合中的元素,由于有两个filter,所以当出现问题的时候,可能不知道具体是哪个filter中出了问题。

借助强大的IDEA,我们在遇到stream的时候,只需要点击下图中的按钮:

此时会弹出一个Stream操作的跟踪窗口:

该窗口中的标签就是这个stream操作的每一步,我们可以通过点击标签去查看每一步执行前和执行后的结果去判断这里的filter是否执行正确。

是不是一下感觉简单了很多呢?

到这里,也许有的小伙伴动手在尝试的话,可能会问了,怎么没有图里的那个按钮呢?

这里可能跟IDEA的版本有关,目前最新的版本都自带了这个功能,但如果你还在用老版本的IDEA的话,可以通过手工安装下面这个插件Java Stream Debugger来拥有这个功能:

好了,今天的分享就到这里,如果你还没有用过这个调试功能的话, 赶紧打开IDEA试一试吧!

]]>
玩转IntelliJ IDEA:优雅地抛异常 https://java.didispace.com/idea-tips/debug/debug-throw-exception.html https://java.didispace.com/idea-tips/debug/debug-throw-exception.html 玩转IntelliJ IDEA:优雅地抛异常 玩转IntelliJ IDEA:优雅地抛异常 抛异常相信大家都会吧?只需要这样就可以了: throw new RuntimeException(&quot;didispace.com&quot;); IntelliJ IDEA Sun, 17 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:优雅地抛异常

抛异常相信大家都会吧?只需要这样就可以了:

但是,在开发过程中有一些情况,我们需要测试程序对异常的处理逻辑是否正确,这个时候就需要我们在程序运行时主动的抛出异常才会触发相关逻辑来验证正确性,比较常见的场景有:事务是否会回滚Web层的统一异常处理等等。

这个时候,你是如何去制造异常,来支持你的调试呢?

下面我就以前写的Spring Boot教程里一个事务处理的例子为场景,给大家看看一些常见的调试操作以及今天要讲的更优雅的操作。

案例说明

先介绍下场景,这是一个用Spring Data JPA实现的数据库操作案例,右侧UserService里一个事务操作,里面含有5句User表的插入语句。

因为@Transactional注解存在,所以saveSomeUsers函数下的数据插入要么都成功,要么都失败。成功很好测试,要测试失败的话,则需要我们让这个函数抛出异常才能触发回滚操作。

撸起袖子就是抛

为了抛出异常以验证事务是否能回滚,很多小伙伴是这样干的:

直接在这个函数里手工抛出异常,很粗暴很直接,是可以完成目标。虽然这种方法在单元测试中作为一种场景是可以的,但如果在复杂的业务过程中这样做就不那么优雅了,因为你测试好还要删掉它,如果忘记了,那就是直接写了个Bug。

优雅地抛异常

实际上IDEA提供了自由抛异常的功能,只需要在Debug的时候,右键前几天介绍的回退操作Reset Frame位置,就可以看到如下图箭头所标的Throw Exception操作了。

然后在弹出框中,你就可以编写你想要抛出的异常了:

是不是很简单呢?赶紧打开IDEA试一试吧!这里视频教程也同步更新了,点击就可以查看,我正在连载IDEA专题的视频内容,感兴趣的小伙伴可以关注我哟!

]]>
玩转IntelliJ IDEA:调试的操作回退 https://java.didispace.com/idea-tips/debug/drop-frame-and-reset-frame.html https://java.didispace.com/idea-tips/debug/drop-frame-and-reset-frame.html 玩转IntelliJ IDEA:调试的操作回退 玩转IntelliJ IDEA:调试的操作回退 大家在Debug程序的时候,是否遇到过因为“下一步”按太快,而导致跳过了想要深入分析的那段代码?是不是很想要有“回到上一步”这样的操作呢? 在IDEA中就提供了一个帮助你回退代码的机会,但这个方法并不是万能的。好了,下面就来具体说说这个功能的使用! 使用Reset Frame回退操作 不知道你在Debug的时候,是否有注意过下图标出的按钮Reset Frame,这就是今天要介绍的主角。 IntelliJ IDEA Sat, 16 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:调试的操作回退

大家在Debug程序的时候,是否遇到过因为“下一步”按太快,而导致跳过了想要深入分析的那段代码?是不是很想要有“回到上一步”这样的操作呢?

在IDEA中就提供了一个帮助你回退代码的机会,但这个方法并不是万能的。好了,下面就来具体说说这个功能的使用!

使用Reset Frame回退操作

不知道你在Debug的时候,是否有注意过下图标出的按钮Reset Frame,这就是今天要介绍的主角。

什么情况不能回退

比如:下面这样的顺序结构,是无法会退的:

什么情况可以回退

再来看看下面这种情况:

这里有两个函数,test2函数会调用add函数。当程序执行到int c = add(a, b)这句的话,会进入到add函数。此时,add函数中执行的内容就可以通过Reset Frame来回退回上一层函数进入的那句语句。

如果文字你看着理解困难,这里DD录了个视频,可以看看具体操作帮助理解,当然自己实操一把会更有感觉哦!

找不到Reset Frame?找找Drop Frame

这里顺带提一句,可能有小伙伴会问:怎么我Debug的时候找不到Reset Frame呢?

其实这个跟版本有关,Reset Frame是IDEA 2022.1版本之后才有的。但不要担心,该版本之前也有这个功能,只是名字不叫这个,而是叫Drop Frame,就是下图所示这个按钮。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
复仇者联盟与IntelliJ IDEA也很配哦~ https://java.didispace.com/idea-tips/appearance/IntelliJ-IDEA-with-Avengers-bg.html https://java.didispace.com/idea-tips/appearance/IntelliJ-IDEA-with-Avengers-bg.html 复仇者联盟与IntelliJ IDEA也很配哦~ 之前转载过几位网友推荐的一些关于IntelliJ IDEA的插件。其中有一款插件几乎每位网友都会推荐它,我也一直在使用,那就是:Background Image Plus。该插件并不同于其他的效率工具,它唯一的功能就是帮助我们方便的修改IntelliJ IDEA的背景,让我们的代码编辑器变得与众不同。但是,也因为这样一个简单的功能,让我们代码编辑器变得不那么单调。 趁着《复仇者联盟4》的上线,给大家分享一下,我收藏的漫威壁纸,挥别漫威电影宇宙十年陪伴我们的青春。 插件使用 如果您还不知道如何安装这款插件,如何使用这些插件,建议优先查看本小节。 IntelliJ IDEA Wed, 01 May 2019 21:40:00 GMT 之前转载过几位网友推荐的一些关于IntelliJ IDEA的插件。其中有一款插件几乎每位网友都会推荐它,我也一直在使用,那就是:Background Image Plus。该插件并不同于其他的效率工具,它唯一的功能就是帮助我们方便的修改IntelliJ IDEA的背景,让我们的代码编辑器变得与众不同。但是,也因为这样一个简单的功能,让我们代码编辑器变得不那么单调。

趁着《复仇者联盟4》的上线,给大家分享一下,我收藏的漫威壁纸,挥别漫威电影宇宙十年陪伴我们的青春。

插件使用

如果您还不知道如何安装这款插件,如何使用这些插件,建议优先查看本小节。

安装插件

打开setting文件选择Plugins选项

  • Ctrl + Alt + S
  • File -> Setting

分别是安装JetBrains插件,第三方插件,本地已下载的插件包。详情见往期关于settings的文章。

如何设置

  1. 安装成功之后重启
  2. 点击菜单栏的VIew标签
  3. 点击Set Background Image(没安装插件是没有这个标签的)
  4. 在弹框中路由选择到本地图片,点击OK即可。

壁纸效果

先通过本文看看我收集的那些适合作为IntelliJ IDEA背景的壁纸效果:

我最喜欢的钢铁侠系列

身材控最爱的黑寡妇系列

一个不过瘾系列

如果您喜欢这些壁纸,或者还想看看我其他收藏的系列壁纸。那么请关注微信公众号:程序猿DD“、,回复:复仇者联盟,即可领取我收藏的30张适合IntelliJ IDEA使用的复仇者联盟壁纸啦!

]]>
盘点10个最受欢迎IntelliJ IDEA主题,必有一款适合你! https://java.didispace.com/idea-tips/appearance/theme-top10-20230307.html https://java.didispace.com/idea-tips/appearance/theme-top10-20230307.html 盘点10个最受欢迎IntelliJ IDEA主题,必有一款适合你! 选择一款适合自己的主题,这样每天工作才不会累!下面给大家精选了一批优秀的主题,并配上案例截图。如果有你喜欢的,那就赶紧去下载吧! Darcula 这是IntelliJ IDEA默认的暗色主题,适合长时间使用,减少眼睛疲劳。 Material Theme UI 一款基于谷歌Material Design的主题,拥有鲜艳的颜色和现代化的UI设计。 IntelliJ IDEA Tue, 07 Mar 2023 11:41:40 GMT 选择一款适合自己的主题,这样每天工作才不会累!下面给大家精选了一批优秀的主题,并配上案例截图。如果有你喜欢的,那就赶紧去下载吧!

Darcula

这是IntelliJ IDEA默认的暗色主题,适合长时间使用,减少眼睛疲劳。

Material Theme UI

一款基于谷歌Material Design的主题,拥有鲜艳的颜色和现代化的UI设计。

One Dark

一款受欢迎的VS Code主题,也可以在IntelliJ IDEA上使用。拥有深色背景和明亮的代码高亮。

Solarized

一款经典的主题,具有柔和的颜色和对比度,使得代码更容易阅读。

Nord

一款冷色调主题,具有清晰的代码高亮和现代化的UI设计。

Dracula

另一个受欢迎的暗色主题,拥有紫色和粉色的配色方案。

Monokai

一款受欢迎的代码高亮主题,拥有鲜艳的颜色和对比度。

Gruvbox

一款温暖的主题,具有棕色和黄色的配色方案,适合长时间使用。

Atom One Dark

一款Atom编辑器的主题,也可以在IntelliJ IDEA上使用。具有深色背景和明亮的代码高亮。

Obsidian

一款黑色主题,具有简洁的UI设计和清晰的代码高亮。

欢迎扫描下方二维码,关注公众号:TJ君,订阅每日推荐,获取更多好用效率工具!

]]>
定制IntelliJ IDEA的内存设置 https://java.didispace.com/idea-tips/performance/customize-memory.html https://java.didispace.com/idea-tips/performance/customize-memory.html 定制IntelliJ IDEA的内存设置 定制IntelliJ IDEA的内存设置 在和同事的一次讨论中发现,对 IntelliJ IDEA 内存采用不同的设置方案,会对 IDE 的速度和响应能力产生不同的影响。 Don’t be a Scrooge and give your IDE some more memory IntelliJ IDEA Tue, 10 May 2022 00:00:00 GMT 定制IntelliJ IDEA的内存设置

在和同事的一次讨论中发现,对 IntelliJ IDEA 内存采用不同的设置方案,会对 IDE 的速度和响应能力产生不同的影响。

2022-05-11T023519

Don’t be a Scrooge and give your IDE some more memory

不要做守财奴,给IDE多留点内存吧。

昨天,大家就是否自定义IntelliJ IDEA 的内存设置进行了讨论,有些人选择默认设置,有些人会对默认的设置进行简单的变更,还有一些开发者会基于他们的需求进行全面复杂的设置。笔者目前的工作是处理几个微服务项目和一个老项目,而客户的核心业务需求非常大。对 IntelliJ IDEA 内存进行简单设置以后,笔者明显感受到了该 IDE 在速度和响应方面的改善。但当时笔者并未进行具体的测量,所以这只是主观感受而已。

不过,参与讨论的一位开发者给笔者发了一份他的设置,虽然是针对同个项目,该设置却极其复杂。笔者对自己的设置并无不满,但非常好奇,这些完全不同的设置对比 JetBrains 提供的默认设置,会有怎样的不同。

目标

笔者的计划是,在一个接近日常开发项目的场景下(加载一个大项目、加载2、3个微服务、git pull 后刷新大项目),测试各个设置带来的效果,并选出内存消耗和速度都达到最优时的最佳设置。

测试机器和项目

  • 笔记本电脑:MacBook Pro Retina
  • 2.3GHz Intel Core i7,
  • 16GB 1600Mhz DDR3
  • SSD Disc
  • OS X Yosemite

项目

大项目—— Monolith ,70万行代码( Java[1] 8 和 Groovy ),303个Gradle模块

两个微服务——约有10000——20000行代码( Java 8 和 Groovy )的小项目,各有一个Gradle模块

测试场景

  1. 在 Idea 中关闭所有项目
  2. 基于测试文件 idea.vmoptions 进行设置
  3. 重启电脑
  4. 启动后关闭所有不相关的项目( communicators 等等)
  5. 打开 Idea(测试时间)
  6. 打开大项目(测试时间)
  7. 检查 jstat -gcutil
  8. 打开两个微服务项目(测试时间)
  9. 检查 jstat -gcutil
  10. 返回大项目然后点击“刷新 Gradle 项目”按钮(测试时间)
  11. 检查 jstat -gcutil

jstat -gcutil

jstat 是 JDK 自带的工具,主要利用 JVM 内建的指令对 Java 应用程序的资源和性能进行实时的命令行监控,还包括对 Heap size 和垃圾回收状况的监控。它有许多选项来收集各种数据,但这里只会用到:

-gcutil :

这个命令的输出结果如下:

在本文中,最重要的参数是 GC 事件( YGC 和 FGC )次数和收集时间( YGCT 和 FGCT )。

测试设置

笔者设置了四种不同的设置,为了好记,给它们起了不同的名字。

默认(灰色标识)

JetBrains 提供的默认设置:

Big(大)(红色标识)

给 Xmx 配 4096MB, ReservedCodeCacheSize 设置 1024MB,这已经是相当多的内存了:

Balanced(平衡的)(蓝色标识)

Xmx 和 Xms 都分配 2GB ,这是相当平衡的内存消耗:

ophisticated(复杂的)(橘色标识)

和上面一样, Xmx 和 Xms 都分配2GB,但是给 GC 和内存管理指定不同的垃圾回收器和许多不同的标志:

以上便是笔者的测试设置,为了执行该测试用例,还需要在~/Library/Preferences/IntelliJIdea15/下创建一个idea.vmoptions文件(这是 Mac OS 系统下的路径设置,基于你的操作系统进行设置)

现在,执行测试用例并比较结果。

结果

Idea启动时间

2022-05-11T023537

正如上图所示,启动时间并不依赖于内存设置。Idea 在所有场景下的测试时间都是10秒,无论内存分配有多少。这并不足为奇,因为在此早期阶段,这些设置并不会影响到应用的行为。

如果你想了解更多关于Java新特性的内容的话,给你推荐一个免费的玩转IDEA专栏:https://www.didispace.com/idea-tips/,文档形式看Java新特性,阅读学习体验更佳哦!

加载大项目花费的时间

现在加载 Monolith 项目及其70万行代码。终于,出现了一些的差异。默认设置所花费的时间几乎是其它的3倍。很明显,如此庞大的代码库需要更多的内存。如果我们执行:

会发现,对比其它设置, GC 在默认设置下会变得异常忙碌。

2022-05-11T023551

2022-05-11T023554

不仅 GC 释放内存的总时间非常高(几乎达到了50倍),而且 Full GC 的平均执行时间也非常非常长。大量的时间都花在了 Full GC 上面,这是 IDE 响应速度低的主要原因。

在IDEA中打开两个微服务

现在加载这两个微服务项目,在 IDEA 中打开并且对比他们所消耗的时间。

2022-05-11T023603

在这个测试用例下,差异还是非常明显的,复杂设置表现最佳,而默认设置仍旧输给了其他两种设置。

再次使用jstat –gcutil

加载完两个微服务项目后,来检查一下同时打开3个项目的情况下, GC 的表现情况。经测试发现,3个不同的自定义设置表现几乎差不多,而默认设置简直弱爆了。

2022-05-11T023610

2022-05-11T023616

最后的角逐:重新加载Monolith

现在,笔者需要从仓库中获得 Monolith 项目的最新版本,并且刷新 Gradle 模块,这样, IDEA 能看到所有的新类。

2022-05-11T023628

重要提示:代表默认设置的灰色条形柱非常高,因为 IDEA 在刷新过程中崩溃了,笔者无法测量实际时间。显然,默认分配的内存不足以执行该操作。

但从三个自定义例子中可以发现,大内存配置花费的时间是最短的。所以,内存分配还是起到了作用。

最后一次使用jstat-gcutil

因为 IDEA 在默认设置下无法刷新项目,所以,这次测试默认设置就不包括在里面。

2022-05-11T023638

2022-05-11T023644

从上图可以看出,三者之间的差异不大,但是 Big 配置下的 Full GC 执行时间最快。此外, Xmx 内存大些对响应能力提升的帮助非常明显。

总结

在这次简短的实验中,大家可以发现,即使对 IntelliJ IDEA 内存进行微调,都可以大大提升 IDE 性能。当然,内存分配越多,执行效果就越好。但是,你也会发现, IDE 之外许多其他应用程序也需要消耗内存,所以,大家的目标应该是在提高性能和内存消耗之间找到一个平衡。

笔者认为,在大多数情况下,把 Xmx 值设置在 2G 和 3G 之间是最佳的。如果你有更多的时间可以用 jstat 和 jvisualm 检查用不同的 JVM 设置如何影响性能和内存占用。

原文:https://dzone.com/articles/the-one-and-only-reason-to-customize-intellij-idea

]]>
玩转IntelliJ IDEA:换M1芯片后的使用建议 https://java.didispace.com/idea-tips/performance/m1-performance.html https://java.didispace.com/idea-tips/performance/m1-performance.html 玩转IntelliJ IDEA:换M1芯片后的使用建议 玩转IntelliJ IDEA:换M1芯片后的使用建议 昨天群里(点击加群)有小伙伴问,换了M1芯片的Macbook Pro之后,IDEA就一直很卡的。正好前段时间,我也换了最新的MacBook Pro,也碰到了类似的问题。 这里就简单讲一下换到M1平台后,使用IDEA要注意的两个点: IDEA版本的选择 第一个要注意的点是IDEA版本要注意下, 不要选择默认的Intel版本。 IntelliJ IDEA Tue, 26 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:换M1芯片后的使用建议

昨天群里(点击加群)有小伙伴问,换了M1芯片的Macbook Pro之后,IDEA就一直很卡的。正好前段时间,我也换了最新的MacBook Pro,也碰到了类似的问题。

这里就简单讲一下换到M1平台后,使用IDEA要注意的两个点:

IDEA版本的选择

第一个要注意的点是IDEA版本要注意下, 不要选择默认的Intel版本。

JDK版本的选择

在下载JDK的时候,一定要选择arrch64的JDK

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
如何设置IntelliJ IDEA的内存和启动参数 https://java.didispace.com/idea-tips/performance/set-memory-vm-options.html https://java.didispace.com/idea-tips/performance/set-memory-vm-options.html 如何设置IntelliJ IDEA的内存和启动参数 如何设置IntelliJ IDEA的内存和启动参数 上一篇,通过一篇国外大佬的IDEA性能测试,得处一个结论:内存分配越多,执行效果就越好。但是,除了IDEA之外,许多其他应用程序也需要消耗内存。所以,大家的目标应该是在提高性能和内存消耗之间找到一个平衡。 马上就有读者问了,那么IDEA的内存怎么设置呢? 设置方法很简单,只需要从菜单中找到:Help IntelliJ IDEA Sat, 28 May 2022 00:00:00 GMT 如何设置IntelliJ IDEA的内存和启动参数

上一篇,通过一篇国外大佬的IDEA性能测试,得处一个结论:内存分配越多,执行效果就越好。但是,除了IDEA之外,许多其他应用程序也需要消耗内存。所以,大家的目标应该是在提高性能和内存消耗之间找到一个平衡。

马上就有读者问了,那么IDEA的内存怎么设置呢?

设置方法很简单,只需要从菜单中找到:Help

Help菜单

这里有两个菜单项是本篇重点:

设置最大内存

Chanage Memory Setting,这是一个可视化的配置菜单项,用来设置IDEA的最大内存

Chanage Memory Setting

而该菜单本质其实还是往下面这个Edit Custom VM Options功能的配置文件中写其中一个参数而已。

配置虚拟机参数

Edit Custom VM Options,这个配置就比较通用了,用来配置IDEA运行的虚拟机各项细节参数:

Edit Custom VM Options

都是Java开发者,相信对这些参数也不会陌生了吧。

这里那么参数中,其实影响最大的还是如上一篇定制IntelliJ IDEA的内存设置文章中提到的内存分配相关参数最为核心,这里大家还是根据自己机器的最大内存和同时运行的其他软件的情况来做调整吧。

]]>
代码缩略图:CodeGlance Pro https://java.didispace.com/idea-tips/plugin/code-glance.html https://java.didispace.com/idea-tips/plugin/code-glance.html 代码缩略图:CodeGlance Pro 代码缩略图:CodeGlance Pro 当代码很长的时候,为了快速下翻是不是很羡慕Sublime和VS Code右侧的缩略图,通过点击大概位置就可以快速的定位代码。 在IDEA中只需要安装插件:CodeGlance Pro,马上也能拥有它 注意:CodeGlance有好几个版本,Pro是目前2022年最新的,建议安装这个。 IntelliJ IDEA Sun, 29 May 2022 00:00:00 GMT 代码缩略图:CodeGlance Pro

当代码很长的时候,为了快速下翻是不是很羡慕Sublime和VS Code右侧的缩略图,通过点击大概位置就可以快速的定位代码。

在IDEA中只需要安装插件:CodeGlance Pro,马上也能拥有它

CodeGlance Pro

注意:CodeGlance有好几个版本,Pro是目前2022年最新的,建议安装这个。

安装完成后,重启IDEA,效果如下:

CodeGlance Pro

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
一个自动帮你完成JavaDoc注释的IDEA插件 https://java.didispace.com/idea-tips/plugin/easy-javadoc.html https://java.didispace.com/idea-tips/plugin/easy-javadoc.html 一个自动帮你完成JavaDoc注释的IDEA插件 一个自动帮你完成JavaDoc注释的IDEA插件 大家好,我是TJ!有段时间没给大家推荐好用工具了,主要是最近工作摸鱼太厉害了,所以也没去探索和接触新东西。 前几天,TJ被领导喷了,原因是代码里注释太少,导致写的SDK在生成JavaDoc文档的时候,有价值的说明内容太少,以后维护不方便。于是马上着实去优化这个是,现在是AI时代了,肯定不能死做,第一反应就是去找找看是否有直接可以用的工具。 于是,我找到了这么个IDEA插件:Easy Javadoc 大家有需要的可以直接打开IDEA,在plugins市场里搜索,就能获得。 IntelliJ IDEA Mon, 04 Sep 2023 10:00:00 GMT 一个自动帮你完成JavaDoc注释的IDEA插件

大家好,我是TJ!有段时间没给大家推荐好用工具了,主要是最近工作摸鱼太厉害了,所以也没去探索和接触新东西。

前几天,TJ被领导喷了,原因是代码里注释太少,导致写的SDK在生成JavaDoc文档的时候,有价值的说明内容太少,以后维护不方便。于是马上着实去优化这个是,现在是AI时代了,肯定不能死做,第一反应就是去找找看是否有直接可以用的工具。

于是,我找到了这么个IDEA插件:Easy Javadoc

大家有需要的可以直接打开IDEA,在plugins市场里搜索,就能获得。

在安装完插件之后,您只需要记住下面这些快捷键,然后就可以去代码里自动生成了:

下面跟着动图演示,来体验一下该插件快速生成JavaDoc的能力:

可以看到,它的主要功能就是根据函数名称、参数名称等代码层面的信息,通过翻译,自动生成相关的中文注释。所以,虽然有插件的辅助,但开发者还是要有良好的编码习惯,写能让人看得懂的参数定义、方法定义。这样,后续的其他自动化生成工具就都能完美的用上,来提高我们的工作效率了。

由于该插件会用到翻译功能,所以各位用户还要去选择和配置一下你需要使用的翻译API,每个供应商每月都有免费额度,对于个人来说,都足够使用了,下面是主流的一些翻译API,需要的可以自取:

  • 百度翻译申请地址:https://api.fanyi.baidu.com/doc/21
  • 腾讯翻译申请地址:https://cloud.tencent.com/document/product/551/7372
  • 阿里云翻译申请地址:https://www.aliyun.com/product/ai/alimt
  • 有道智云翻译申请地址:https://ai.youdao.com/
  • 微软翻译申请地址:https://azure.microsoft.com/
  • 谷歌翻译(需要翻墙)申请地址:https://cloud.google.com/

好了,今天的分享就到这里,感兴趣的可以根据下面相关链接了解更多内容:

  • 插件地址:https://plugins.jetbrains.com/plugin/12977-easy-javadoc
  • 开源项目:https://github.com/starcwang/easy_javadoc

欢迎关注公众号:TJ君,订阅每日推荐,获取更多好用效率工具!

]]>
File Expander:在IDEA里直接查阅Jar包内容 https://java.didispace.com/idea-tips/plugin/fileexpander.html https://java.didispace.com/idea-tips/plugin/fileexpander.html File Expander:在IDEA里直接查阅Jar包内容 平日里大家想看一个jar包里的内容会怎么做呢?直接解压缩到本地?反编译到本地查看?或者下载一些专门查看jar包的工具?是不是觉得稍稍有点麻烦呢? TJ君肯定是想着能让大家在各方面使用更方便,于是今天带来这款插件,可以让大家直接在IDEA查看各种jar包、压缩包,是不是有点好奇呢? 我们来看下具体的效果: 先看看查看jar包的效果: 可以轻松的看到里面每一个文件及对应代码。 IntelliJ IDEA Wed, 12 Jan 2022 11:19:51 GMT 平日里大家想看一个jar包里的内容会怎么做呢?直接解压缩到本地?反编译到本地查看?或者下载一些专门查看jar包的工具?是不是觉得稍稍有点麻烦呢?

TJ君肯定是想着能让大家在各方面使用更方便,于是今天带来这款插件,可以让大家直接在IDEA查看各种jar包、压缩包,是不是有点好奇呢?

我们来看下具体的效果:

先看看查看jar包的效果:

可以轻松的看到里面每一个文件及对应代码。

再来看看压缩文件的效果:

是不是轻松方便?插件支持各种不同款式的压缩包格式,例如.zip、.gz、.tar、.tgz、.7z、.zip、.jar、.war、.epc等都可以。

插件也不大,一共就105KB,可以说虽然简单小巧,但是实用好用,可以解决不少人的使用难题。

不过TJ君费解的是,今天TJ君怎么都上不了IDEA的插件市场,试了各种方式都不行。所以TJ君将插件包的安装介质给大家准备好了,直接在IDEA里面引入安装就可以了。

喜欢这个插件的小伙伴,赶紧来试试吧!

扫描下方二维码,关注公众号“TJ君”,回复“0111”,获取仓库地址!

]]>
Java Stream的调试插件 https://java.didispace.com/idea-tips/plugin/java-stream-debug.html https://java.didispace.com/idea-tips/plugin/java-stream-debug.html Java Stream的调试插件 Java Stream的调试插件 Stream操作是Java 8推出的一大亮点!虽然java.util.stream很强大,但依然还是有很多开发者在实际工作中很少使用,其中吐槽最多的一个原因就是不好调试,一开始确实是这样,因为stream这样的流式操作在DEBUG的时候,是一行代码,直接下一步的时候,其实一下就过去了好多操作,这样我们就很难判断到底是里面的哪一行出了问题。不过,现在的话,在强大的IDEA插件支持下,stream的调试其实也没那么难了,下面就来学习一下在IDEA中如何调试stream操作吧。 插件:Java Stream Debugger IntelliJ IDEA Fri, 20 May 2022 00:00:00 GMT Java Stream的调试插件

Stream操作是Java 8推出的一大亮点!虽然java.util.stream很强大,但依然还是有很多开发者在实际工作中很少使用,其中吐槽最多的一个原因就是不好调试,一开始确实是这样,因为stream这样的流式操作在DEBUG的时候,是一行代码,直接下一步的时候,其实一下就过去了好多操作,这样我们就很难判断到底是里面的哪一行出了问题。不过,现在的话,在强大的IDEA插件支持下,stream的调试其实也没那么难了,下面就来学习一下在IDEA中如何调试stream操作吧。

插件:Java Stream Debugger

如果你用的IDEA版本比较新的话,这个插件已经是自带的了,就不需要安装了。如果还没安装的话,就手工安装一下,然后继续下面的操作。

调试Stream操作

视频演示:点击这里查看

先来看下面这样的这段代码:

这段代码的逻辑是通过stream去过滤list集合中的元素,由于有两个filter,所以当出现问题的时候,可能不知道具体是哪个filter中出了问题。

借助强大的IDEA,我们在遇到stream的时候,只需要点击下图中的按钮:

此时会弹出一个Stream操作的跟踪窗口:

该窗口中的标签就是这个stream操作的每一步,我们可以通过点击标签去查看每一步执行前和执行后的结果去判断这里的filter是否执行正确。

是不是一下感觉简单了很多呢?

好了,今天的分享就到这里,如果你还没有用过这个调试功能的话, 赶紧打开IDEA试一试吧!

]]>
几个适合Java开发者的免费IDEA插件 https://java.didispace.com/idea-tips/plugin/javaer-top-5-free-plugins.html https://java.didispace.com/idea-tips/plugin/javaer-top-5-free-plugins.html 几个适合Java开发者的免费IDEA插件 今天,给大家推荐几个好用且免费的IntelliJ IDEA插件。如果你还没有用过,可以尝试一下,也许对你的日常工作会有一定的效率提升噢! RESTFul-Tool 如果你是一个RESTful服务的开发者,那么这个一定要试一下。它是一套非常丰富的RESTful服务开发工具,对 Spring MVC 和 Spring Boot 支持也是非常友好,开发者可以直接通过插件找到自己编写的RESTful接口: IntelliJ IDEA Wed, 17 Jul 2024 22:00:00 GMT 今天,给大家推荐几个好用且免费的IntelliJ IDEA插件。如果你还没有用过,可以尝试一下,也许对你的日常工作会有一定的效率提升噢!

RESTFul-Tool

如果你是一个RESTful服务的开发者,那么这个一定要试一下。它是一套非常丰富的RESTful服务开发工具,对 Spring MVC 和 Spring Boot 支持也是非常友好,开发者可以直接通过插件找到自己编写的RESTful接口:

同时也能非常方便的进行测试:

Spring Boot Assistant

如果你跟我一样,是一个Spring Boot开发人员,那么这个插件也是非常推荐的。有了这个插件之后,可以在我们编写程序的时候提出更多针对Spring Boot的有用提示。

Test Data

Test Data插件可以提高编写单元测试的效率,因为它可以为我们生成多种类型的测试数据,包括文本、UUID、数字、日期和时间,以及自定义类型,如JSON、CSV和SQL等流行的数据类型。

SonarLint

如果你喜欢SonarQube,那么SonarLint一定要看一下。SonarLint 是一款面向开发人员的开源工具,旨在确保代码符合开发和生产环境的标准。它有助于在您编写时实时纠正代码异味,不仅提供建议,还提供对问题及其相关风险的详细见解。

PlantUML

上面都跟代码相关,最后推荐一个与图相关的插件。PlantUML插件可以帮助我们好利用简单直观的语言,毫不费力地绘制各种类型的图表。

你还知道什么好用的插件吗?欢迎留言区分享!

]]>
Jump To Line:跳转任意行 https://java.didispace.com/idea-tips/plugin/jump-to-line.html https://java.didispace.com/idea-tips/plugin/jump-to-line.html Jump To Line:跳转任意行 Jump To Line:跳转任意行 上一篇关于调试操作回退的介绍中,我们采用了Reset Frame(Drop Frame)来实现。但该操作有一定的局限性,所以,这篇我们将介绍一个插件来帮助弥补Reset Frame做不到的一些回退操作。 视频演示:点击这里查看 IntelliJ IDEA Tue, 17 May 2022 00:00:00 GMT Jump To Line:跳转任意行

上一篇关于调试操作回退的介绍中,我们采用了Reset Frame(Drop Frame)来实现。但该操作有一定的局限性,所以,这篇我们将介绍一个插件来帮助弥补Reset Frame做不到的一些回退操作。

视频演示:点击这里查看

插件:Jump To Line

这个插件可以帮助我们在调试的时候,向前或向后跳到想要执行的语句处。这里就包括了Reset Frame无法回退的位置,比如下面这个小片段:

Jump To Line回退操作

更详细的操作演示可以点击这里查看视频

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
推荐一款在IDEA里画UML图的插件 https://java.didispace.com/idea-tips/plugin/plantuml.html https://java.didispace.com/idea-tips/plugin/plantuml.html 推荐一款在IDEA里画UML图的插件 平时你画UML图都用什么?Processon、Visio这些相信大家已经都很熟悉了。今天TJ要给大家介绍的是一个特别的画图工具,它是IDEA中的一个插件,有了它你可以把画图与编码都集成到IDEA中一起完成,是不是感觉很棒呢?下面就来一起认识下今天要介绍的IDEA插件:PlantUML! PlantUML,是一款开源的图绘制项目,支持通过编写文本来快速生成各种UML图形,目前支持时序图、用例图、类图、对象图、组件图、部署图、状态图、定时图;同时也支持用来生成非UML图,像JSON数据、YAML数据、架构图、思维导图等等,都可以用它来完成。 简单的说,就是你直接通过编程来画出你要的各种图,是不是特别适合我们程序猿呢? IntelliJ IDEA Mon, 11 Oct 2021 14:18:00 GMT 平时你画UML图都用什么?Processon、Visio这些相信大家已经都很熟悉了。今天TJ要给大家介绍的是一个特别的画图工具,它是IDEA中的一个插件,有了它你可以把画图与编码都集成到IDEA中一起完成,是不是感觉很棒呢?下面就来一起认识下今天要介绍的IDEA插件:PlantUML!

PlantUML,是一款开源的图绘制项目,支持通过编写文本来快速生成各种UML图形,目前支持时序图、用例图、类图、对象图、组件图、部署图、状态图、定时图;同时也支持用来生成非UML图,像JSON数据、YAML数据、架构图、思维导图等等,都可以用它来完成。

简单的说,就是你直接通过编程来画出你要的各种图,是不是特别适合我们程序猿呢?

光说可能不够形象,直接上例子,例如像一些时序图,你就可以这样实现:

PlantUML

图案左半边,就是你输入的文本,右半边就是根据文本生成的效果,像这种时序图,语法规则其实很简单,可以简单的用 -> 来绘制参与者之间传递的消息,而不必显式地声明参与者。也可以使用 -->绘制一个虚线箭头。如果想调整箭头的方向可以使用 <-<--

而对于像类图这样的一些展示效果,你可以通过声明不同的类型展示不同的样式,一目了然:

PlantUML

PlantUML

熟练具体的编写语法规则之后,是不是对于程序猿来说,比直接用手画更加简单呢?

该插件就在前几天刚更新到了5.6.1版本,作者也是在不断的优化更新。

PlantUML

安装该插件需要直接在IDEA插件中搜索PlantUML,或者直接从插件官网下载,然后在IDEA安装即可。

如果不想自己下载的小伙伴,TJ君也给你准备好了最新版本的插件介质,只要关注文末公众号回复关键字获取即可,同时TJ君还会提供一份学习宝典,供小伙伴们快速上手PlantUML相关语法,让我们一起更好的画图吧!

扫描下方二维码,关注公众号“TJ君”,回复“PLANT”,获取仓库地址!

]]>
Rainbow Fart:把鼓励师装进你的IDEA里! https://java.didispace.com/idea-tips/plugin/rainbow-fart.html https://java.didispace.com/idea-tips/plugin/rainbow-fart.html Rainbow Fart:把鼓励师装进你的IDEA里! TJ君今天在和同事聊天,期间说起小孩子的教育,说现在的教育方式都是以鼓励为主,要不停的告诉小孩子正能量告诉他们是最棒的才能更好地激发他们的学习热情。 想想TJ君小时候的残酷生活,现在小孩子真是生活在幸福里的花朵。 不过话说回来,是不是希望自己在编码的时候也有人一直在鼓励你呢?嘿嘿,正所谓千穿万穿马屁不穿,那么TJ君今天介绍的这个好东东你就一定不能错过了。 TJ君今天给大家介绍的是一款程序员鼓励插件,可以在你编码的时候不停的语音鼓励你,让你事半功倍。 IntelliJ IDEA Fri, 13 Oct 2023 11:47:50 GMT TJ君今天在和同事聊天,期间说起小孩子的教育,说现在的教育方式都是以鼓励为主,要不停的告诉小孩子正能量告诉他们是最棒的才能更好地激发他们的学习热情。

想想TJ君小时候的残酷生活,现在小孩子真是生活在幸福里的花朵。

不过话说回来,是不是希望自己在编码的时候也有人一直在鼓励你呢?嘿嘿,正所谓千穿万穿马屁不穿,那么TJ君今天介绍的这个好东东你就一定不能错过了。

TJ君今天给大家介绍的是一款程序员鼓励插件,可以在你编码的时候不停的语音鼓励你,让你事半功倍。

插件的雏形最早是一款vscode的插件,不过有大神jadepeng写了一个IDEA版本的,让我们这些使用idea的小伙伴也可以享受。

下载安装后,在插件设置界面,可以将voice package type属性设置为builtin,这样可以选择内置语音包,也可以将voice package type属性设置为custom,这样子就可以使用各种自定义的语音包(不过需要自己去寻找下载哦),如果voice package type选择TTS,则是合成的语音包~

如果觉得语音出现频率过于频繁,也可以根据不同语音包的关键字提示进行修改,这里就不一一阐述。

TJ君觉得,能有人一直在旁边鼓励你就仿佛找了一个程序员鼓励师一样,一定对大家的帮助很有帮助哦!所以快来试试吧!

扫描下方二维码,关注公众号“TJ君”,回复“鼓励你”,获取仓库地址!

]]>
IDEA API调试插件:Restful Fast Request https://java.didispace.com/idea-tips/plugin/restful-fast-request.html https://java.didispace.com/idea-tips/plugin/restful-fast-request.html IDEA API调试插件:Restful Fast Request IDEA API调试插件:Restful Fast Request 目前 SpringBoot 系列框架非常流行,大多数开发都是基于前后端分离的模式进行开发,这种过程中势必会涉及到大批量的 API 调试,到目前为止,IntelliJ IDEA 是 Java 软件开发最多使用的开发工具,最近我在 IntelliJ IDEA 插件市场下找到了一块非常好用的插件 Restful Fast Request,细节非常到位,说它是 IDEA 版的 Postman 也不为过,推荐给大家! IntelliJ IDEA Wed, 25 May 2022 00:00:00 GMT IDEA API调试插件:Restful Fast Request

目前 SpringBoot 系列框架非常流行,大多数开发都是基于前后端分离的模式进行开发,这种过程中势必会涉及到大批量的 API 调试,到目前为止,IntelliJ IDEA 是 Java 软件开发最多使用的开发工具,最近我在 IntelliJ IDEA 插件市场下找到了一块非常好用的插件 Restful Fast Request,细节非常到位,说它是 IDEA 版的 Postman 也不为过,推荐给大家!

什么是 Restful Fast Request

Restful Fast Request 是 idea 版 Postman。它是一个强大的 restful api 工具包插件,可以根据已有的方法帮助您快速生成 url 和 params。 Restful Fast Request = API调试工具 + API管理工具 + API搜索工具。它有一个像 Postman 一样界面来完成请求、检查服务器响应、存储你的 api 请求和导出 api 请求。插件帮助你在 IDEA 界面内更快更高效地调试你的 API

支持的框架

安装

图 1

配置

基础配置

刚开始使用需要配置项目名 [例如 card]、环境名 [例如 local、dev],然后配置对应的域名

图 2

String 生成配置

可以使得生成出来的字符串随机动态

图 3

类型映射配置

参考

https://dromara.gitee.io/fast-request/guide/getstarted/dataMapping.html

使用

调试 API

点击接口左侧的小火箭按钮即可直接生成调用接口所需的信息,点击绿色的 Send 按钮即可发送请求

图 4

下载文件

点击蓝色图标 Send and Download

图 5

保存 API

点击生成完参数,并进行适量修改后,可以对该 API 进行保存,方便后续再次调试的时候使用

图 5

SearchEveryWhere 支持

通过 SearchEveryWhere 可以快速搜索对应的 API,可以通过 url 关键字、请求方式 + url 关键字、方法描述来搜索 API

图 6

快速添加 Token 到 Header

发送请求后可以通过 response 中的 Json 页签,选中字段,点击添加,将 token 快速添加到了项目级别的头参数中,极大地节省了手动复制操纵的行为。

API 导出到 Postman

可以将已经保存的 API 导出到 postman, 非常方便

APIs 列表

展示了保存的 API,同时也可以进行各种不同策略的搜索,点击右侧的定位图标可以快速定位到对应的代码,也可以直接点击发送按钮,对保存的 API 发起请求

图 13

API 导入导出

可以将保存的 API 导入及导出,跟不同的开发之间分享

Curl 拷贝

点击小火箭生成完参数后,可以通过点击 curl 图标快速生成对应 api 的 crul

图 7

Swagger 默认值解析支持

支持 swagger2、swagger3 默认值解析

支持的注解

swagger2

swagger3

API 自动生成注释

字段注释需要符合标准注释规范,使用 /* 描述 /

可以通过点击隐藏或显示 Description

图 8

API 生成 Markdown 文档

当我们在开发 API 的时候,例如在跟第三方对接接口的时候往往需要 API 文档,那么可以通过该功能快速导出 API 对应的文档

API 预览

API 预览可以快速预览当前 Controller 下的 API,并且可以快速定位代码。聚焦窗口后输入关键字,根据 API 的路径关键字可以快速搜索

项目全局参数

可以进行配置,设置项目级别下的 Headers、Url Params、Url-Encoded Params、Cookie 等全局参数

自动 Cookie 存储

当一些需要 cookie 支持的项目,当发送完请求后,插件会自动地将 Cookie 放入项目级别参数 Cookie 中,后续需要 Cookie 的请求就可以使用该 Cookie 了

图 10

历史请求预览

该功能可以让我们查阅历史请求的 API 以及对于的参数、url 等信息

图 11

Html 预览

可以对 html 形式的响应在 IDEA 内进行预览

图 12

总结

Restful Fast Request 这个插件,体验确实不错。深入体验,确实能发现很多惊喜,并且提供了免费版和收费版,收费版中又做了很多细致化的功能,提升了很大的生产力,而且加入技术群直接打 6 折,确实值得入手一把

]]>
文件树增强:Show Comment,显示类注释 https://java.didispace.com/idea-tips/plugin/show-comment.html https://java.didispace.com/idea-tips/plugin/show-comment.html 文件树增强:Show Comment,显示类注释 文件树增强:Show Comment,显示类注释 前段时间刷朋友圈看到好友做了一个IDEA插件,具体功能是在侧边文件树中,显示Java类的注释信息,效果下面这样: 觉得不错的小伙伴,可以在插件里搜索:Show Comment 安装使用: IntelliJ IDEA Wed, 08 Jun 2022 00:00:00 GMT 文件树增强:Show Comment,显示类注释

前段时间刷朋友圈看到好友做了一个IDEA插件,具体功能是在侧边文件树中,显示Java类的注释信息,效果下面这样:

Show Comment

觉得不错的小伙伴,可以在插件里搜索:Show Comment 安装使用:

Show Comment

视频介绍:https://www.bilibili.com/video/BV1YY411M7gZ/,欢迎关注我的B站和视频号「程序猿DD」,持续分享好用的IDEA插件和使用小技巧。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IDEA

]]>
GitHub Copilot的最佳免费平替 https://java.didispace.com/idea-tips/plugin/tongyi-lingma.html https://java.didispace.com/idea-tips/plugin/tongyi-lingma.html GitHub Copilot的最佳免费平替 在如今这个人工智能高速发展的时代,每个行业都在被AI技术影响而改变。层出不穷的AI辅助工具,让我们看到了机器正在取代一部分基础的日常工作。对于我们开发者而言,当前最炙手可热的就是GitHub Copilot,市面上最好的开发者辅助工具。GitHub Copilot所提供的代码补全、建议、解释等能力非常强大,可以有效地提高编程速度。但是,GitHub Copilot是基于OpenAI所构建,后者的成本并不小,所以GitHub Copilot成为一款付费工具是非常自然的。 那么,对于预算有限的开发者而言,是否有合适的免费平替呢?答案是肯定的!今天,就给大家推荐最近我一直在用,且觉得还不错的插件:通义灵码。推荐的理由,我总结为以下几点: IntelliJ IDEA Wed, 20 Dec 2023 14:18:00 GMT 在如今这个人工智能高速发展的时代,每个行业都在被AI技术影响而改变。层出不穷的AI辅助工具,让我们看到了机器正在取代一部分基础的日常工作。对于我们开发者而言,当前最炙手可热的就是GitHub Copilot,市面上最好的开发者辅助工具。GitHub Copilot所提供的代码补全、建议、解释等能力非常强大,可以有效地提高编程速度。但是,GitHub Copilot是基于OpenAI所构建,后者的成本并不小,所以GitHub Copilot成为一款付费工具是非常自然的。

那么,对于预算有限的开发者而言,是否有合适的免费平替呢?答案是肯定的!今天,就给大家推荐最近我一直在用,且觉得还不错的插件:通义灵码。推荐的理由,我总结为以下几点:

  1. 极低的上手门槛
  2. 强大的代码补全和编码提示
  3. 快捷好用的智能问答

极低的上手门槛

一些众所周知的原因,相信体验过GitHub Copilot的开发者一定都是经过一番折腾才用上其强大能力的。这对于一些初学者用户来说门槛非常高,同时对于一些有审查要求的环境更是不可能使用。

与此相比,通义灵码的上手门槛极低:

  • 安装简单:用户只需要在JetBrains系IDE或VS Code的插件市场里搜索:TONGYI Lingma,就能完成一键安装

JetBrains系IDE安装

VS Code安装

  • 极易上手:无需配置,自动提示。插件在开发者编码过程中会自动根据上下文做出提示建议,如提示建议不错,直接按Tab采纳即可。如果需要手动唤出提示,也只需要通过快捷键+P快速弹出提示(Windows快捷键:Alt + P)。除了这两个最常用的操作之后,还有一些操作可参见下表:
macOS Windows
接受行间代码建议 Tab Tab
废弃行间代码建议 esc esc
查看上一个行间推荐结果 [ Alt [
查看下一个行间推荐结果 ] Alt ]
手动触发行间代码建议 P Alt P

强大的代码补全和编码提示

代码补全是开发者日常工作最高频的操作,虽然很多强大IDE工具都自带了代码补全的能力,但这也仅限于一些语法层面的简单补全,不包含联系编码上下文所推理出的,更有贴近用户编码意图的智能补全和提示。所以,这也是现在很多AI辅助工具吸引人的地方,它们可以提供更为出色的,甚至惊艳的补全效果。

那么通义灵码在代码补全方面,是否可以平替GitHub Copilot呢?这里DD根据很多博主介绍GitHub Copilot的场景来测试了一下,供大家参考:

行级补全

之前讲过,行级补全在大部分IDE中已经包含,但AI工具的行级补全更为强大,它的强大之处在于能够根据你的输入来推理逻辑补全。

比如:我要定义一个B站视频的URL,只要参数名中含有B站视频URL相关的描述,就会直接给出模版。这样的能力是完全不同于IDE所提供的行级补全的。

函数级补全

函数级补全是DD看到GitHub Copilot演示案例中最常见的强大能力,开发者只需要输入有含义的函数名称,具体的实现就自动提示了:

所以,必须在通义灵码中也尝试一下!

先尝试了一下简单的冒泡排序:

轻松完成!

再尝试一下稍微有点难度的快排算法:

似乎失败了?只给出了一些简单提示,并没能得到完整的逻辑。后面,DD又尝试了几次,最终获得了一个完整结果,具体如下:

所以,在函数级补全这个功能上,可能还存在一些差距,有待后续提高吧。

自然语言补全

自然语言补全的主要场景就是写注释,AI工具自动生成代码。

这里DD也找了个场景测试了一下。比如下面是Spring Boot中一个文件上传的后端处理逻辑,我尝试通过自然语言的方式来描述逻辑,通义灵码迅速补全了与注释相关的代码:

上下文感知能力

对于上下文的感知是AI工具的重要特色,也是这类工具时不时惊艳到我们的核心。

比如,下面这种场景,在我第一碰到时,还是有被AI的理解能力所吓到:

可以看到,当我要为这个Controller添加Swagger的API说明时,它居然理解了这个Controller内做的都是微信支付的操作,所以给出了tags="微信支付"的提示。

随着这段时间的使用,出现过很多惊艳到我的补全提示,比如当我要写一个操作FTP的API时,出现了这样一幕:

可以看到,在我创建了FtpController之后,通义灵码自动找到了同项目中的FtpService,并给出了依赖提示,这一操作非常符合预期。之后,通过换行操作,通义灵码又给出了进一步的提示,这步提示也非常神奇,因为它的内容已经不仅仅是对当前上下文的理解,而是结合上下文与依赖内容的理解,并给出了调用依赖内容的提示。

通过这段时间的实践,我认为通义灵码的感知能力已经非常不错,它可以很好的理解项目中的各个元素,并找到它们之间的关系,然后在开发者编码过程中给出一些可能需要的提示。同时,我也发现养成良好编码习惯的优势也在这里有所体现。因为在拥有良好项目结构和命名规范的工程下编码时,此类AI工具给出的提示就相当有水准,也许这样更有助于AI理解我们的工程吧。

快捷好用的智能问答

通义灵码插件在IDE中自带一个智能问答的窗口,具体位置和基本使用方法如下:

图中我还问了一个问题:让通义灵码帮我写一个文件操作类,它就给了我一个不错的代码封装和使用案例。如果你觉得不错的话,就可以通过回答右上方的按钮,以不同的方式添加到工程中:

图中按钮从左到右功能依次为:插入、复制、新建文件

是不是很棒呢?要知道GitHub的Chat可不是直接可以用的,相信还有不少小伙伴还在排队吧?

通义灵码的智能问答窗口除了处理基本问答之外,其实还有一些更有意思的功能,比如:解释代码和生成单元测试

上面我们体验了代码补全能力,但是它补全的内容到底对不对呢?必须赶紧验证一下,顺便再体验一下通义灵码的另外2个实用功能:

  • 解释代码
  • 生成单元测试

下面就来看看上面生成的能否经受住它自己的考验 ^_^

操作很简单,只需要选中上面生成的代码片段,点击鼠标右键,可以看到解释代码和生成单元测试:

先来试试解释代码,点击之后会在IDE右侧弹出问答框,具体如下:

没啥问题,通过第一关考验!

下面再尝试一下:生成单元测试。马上就获得了如下代码:

直接添加文件之后,运行起来。成功通过测试!上面自动补全的代码是正确的!

总结

最后,聊聊这段时间使用通义灵码的感受。其实,刚开始尝试的时候也是碰到一些问题,尤其对于关于AI辅助的补全能力,会有一些不太适应。可能补全能力与项目内容和自己日常的编码习惯有关,随着每天不断的使用,插件似乎在理解项目内容和我的习惯,并不断给出更让我满意的提示内容。所以,这个使用过程是越用越顺的。现在已经是我必不可少的效率神器了。

虽然,通义灵码总体能力上离GitHub Copilot还有一些差距,但大部分辅助编码能力已经非常接近GitHub Copilot。同时,它的生成速度很快,而且跟IDE适配很好,ide里直接chat也很爽,加之阿里通义千问模型的支持。在一众免费的AI编码辅助工具之中脱颖而出,可以说是GitHub Copilot的最佳平替了。

如果您正在寻找AI辅助编码工具,但又觉得GitHub Copilot上手折腾麻烦或者觉得太贵,那么建议免费尝试一下通义灵码,相信不会让你失望。另外,DD看到社区有其他开发者反馈初学者使用非常丝滑,尤其是对于Python。所以,如果你是初学者或者Pyhon开发,那么也推荐试试。

]]>
玩转IntelliJ IDEA:Markdown编辑器 https://java.didispace.com/idea-tips/editor/markdown-editor.html https://java.didispace.com/idea-tips/editor/markdown-editor.html 玩转IntelliJ IDEA:Markdown编辑器 玩转IntelliJ IDEA:Markdown编辑器 直接执行命令 作为一名开发者,相信大部分人都喜欢用Markdown来写文章和写文档。 如果你经常用开源项目或者自己维护开源项目,肯定对于项目下的README文件也相当熟悉了吧,通常我们会在这里介绍项目的功能、如何使用等内容。 对于一些需要用命令执行的开源项目的话,也会附上一些命令行的操作提示。 这样我们就可以一边看文档,一边敲命令来安装和使用这个开源项目,当然你也可以选择复制命令去终端执行。 但是,你知道吗?在IDEA的Markdown编辑器中还有简单的方式! IntelliJ IDEA Wed, 13 Apr 2022 00:00:00 GMT 玩转IntelliJ IDEA:Markdown编辑器

直接执行命令

作为一名开发者,相信大部分人都喜欢用Markdown来写文章和写文档。

如果你经常用开源项目或者自己维护开源项目,肯定对于项目下的README文件也相当熟悉了吧,通常我们会在这里介绍项目的功能、如何使用等内容。

对于一些需要用命令执行的开源项目的话,也会附上一些命令行的操作提示。

这样我们就可以一边看文档,一边敲命令来安装和使用这个开源项目,当然你也可以选择复制命令去终端执行。

但是,你知道吗?在IDEA的Markdown编辑器中还有简单的方式!

你注意过这个小绿色箭头不?

其实我们只需要直接点击他,命令就可以直接执行了!

Get这个技能了吗?视频分享地址:https://www.bilibili.com/video/BV1244y137hb ,欢迎点赞、关注、分享,三连支持!

]]>
IDEA中无法import自己工程中类的问题解决方法 https://java.didispace.com/idea-tips/questions/idea-import-project-class-failed.html https://java.didispace.com/idea-tips/questions/idea-import-project-class-failed.html IDEA中无法import自己工程中类的问题解决方法 今天开个很久没搞的工程,刚开的时候一片红,很自然的想到,要去配置一下项目的JDK,但是配置好之后,又出了个诡异问题:项目可以运行,但是import项目内部自己写的类的时候,都出现了红色错误。虽然import显示错误,但是实际类是存在的!! 就像下面这样: 那么碰到这类问题之后要如何解决呢?下面说说解决步骤: 第一步:菜单中选择File - Invalidate Caches/Restart... IntelliJ IDEA Sat, 02 Jan 2021 01:16:23 GMT 今天开个很久没搞的工程,刚开的时候一片红,很自然的想到,要去配置一下项目的JDK,但是配置好之后,又出了个诡异问题:项目可以运行,但是import项目内部自己写的类的时候,都出现了红色错误。虽然import显示错误,但是实际类是存在的!!

就像下面这样:

那么碰到这类问题之后要如何解决呢?下面说说解决步骤:

第一步:菜单中选择File - Invalidate Caches/Restart...

第二步:在弹出框中,选择Invalidate and Restart

静静等待IDEA重启,此时就可以看到红色import错误没有啦!

]]>
IDEA中如何在一个工作空间中管理多个项目 https://java.didispace.com/idea-tips/questions/idea-multiple-projects-in-one-project.html https://java.didispace.com/idea-tips/questions/idea-multiple-projects-in-one-project.html IDEA中如何在一个工作空间中管理多个项目 你身边有没有这种顽固的Eclipse忠实用户:IDEA不能一个窗口管理多个项目!太不方便了! 对于一个窗口同时管理多个项目的需求,在我们日常开发时候是经常需要的。尤其当我们在分布式环境下,在一个窗口中调试起来就能方便很多。 如此强大的IDEA真的不支持吗?!当然不是!是你不会用! 下面我们就来说说如何在一个工作空间中管理多个项目的配置方式: 第一步:先创建一个新的空白工程 IntelliJ IDEA Sat, 16 Jan 2021 08:48:00 GMT 你身边有没有这种顽固的Eclipse忠实用户:IDEA不能一个窗口管理多个项目!太不方便了!

对于一个窗口同时管理多个项目的需求,在我们日常开发时候是经常需要的。尤其当我们在分布式环境下,在一个窗口中调试起来就能方便很多。

如此强大的IDEA真的不支持吗?!当然不是!是你不会用!

下面我们就来说说如何在一个工作空间中管理多个项目的配置方式:

第一步:先创建一个新的空白工程

在弹出的项目名称和路径输入框中根据你的喜好输入即可。

第二步:添加模块

添加模块的方式有两种:

New Module:如果你要管理的是一个新项目,那么可以通过这个选项创建一个新项目,并纳入当前的项目管理界面中。

对于我们这些Spring开发者来说,可以继续用Spring Initializr来初始化你的项目,这样创建出来的项目会成为当前这个项目的模块来管理。

Import Module:如果你要管理的项目已经从git上拉下来了,可以直接用这个选项进行导入即可:

如果没有特殊配置,那就各种next完成导入。

第三步:在后续要继续添加一起管理的项目的时候,只需要在菜单中找到这两种方式。

  1. File -> New -> Module...:这个是新建项目
  2. File -> New -> Module from Existing Sources...:这个是导入项目

不断重复上面的动作,我们就可以把很多我们要一起调试的项目放到一起来使用了:

]]>
IDEA升级到2021.3之后,Maven私有仓库不能用的解决 https://java.didispace.com/idea-tips/questions/idea2021-3-maven-private-repo-not-work.html https://java.didispace.com/idea-tips/questions/idea2021-3-maven-private-repo-not-work.html IDEA升级到2021.3之后,Maven私有仓库不能用的解决 更新到Intellij IDEA 2021.3之后,Maven出问题了!无法从Maven私有仓库下载依赖了。 提示要从maven-default-http-blocker下载,难道不应该去私仓下载吗? 原因 原来IDEA更新到2021.3后内置Maven的版本提升到了3.8.1。 IntelliJ IDEA Thu, 09 Dec 2021 12:39:56 GMT 更新到Intellij IDEA 2021.3之后,Maven出问题了!无法从Maven私有仓库下载依赖了。

提示要从maven-default-http-blocker下载,难道不应该去私仓下载吗?

原因

原来IDEA更新到2021.3后内置Maven的版本提升到了3.8.1

Maven3.8.1发布一个变更(CVE-2021-26291):

由于使用 HTTP 的自定义存储库可能导致中间人攻击。现在越来越多的存储库使用 HTTPS,但情况并非总是如此。这意味着 Maven Central 包含带有自定义存储库的 POM,这些存储库通过 HTTP 引用 URL。这使得通过此类存储库下载的内容成为攻击目标。开发人员可能没有意识到某些下载使用了不安全的 URL。由于上传到 Maven Central 的 POM 是不可变的,因此需要对 Maven 进行更改。

为了解决这个问题,从3.8.1开始setting.xml会增加一个默认镜像maven-default-http-blocker来阻止从HTTP链接下载不安全的依赖库。

因为我们的Maven私有仓库是内网部署的,并没有去设置HTTPS,导致这个问题也就不足为奇了。

解决办法

既然找到了原因,解决这个问题就很简单了。最简单的方法就是降级IDEA版本或者不使用内置的Maven;最好的方法就是升级到HTTPS。如果你想维持现状就需要把setting.xml中的默认镜像(上面给出的xml标签)给删除掉。

如果你是Toolbox安装的话,在Windows下路径为:

我猜想都应该在安装目录的插件文件夹下的\maven\lib\maven3\conf路径下,你可以找找看。

]]>
升级IDEA后Lombok不能用了,如何解决? https://java.didispace.com/idea-tips/questions/resolve-lombok-is-disabled.html https://java.didispace.com/idea-tips/questions/resolve-lombok-is-disabled.html 升级IDEA后Lombok不能用了,如何解决? 今天到工作室比较晚,在电脑前吃着早饭,看到提示IDEA提示升级,寻思已经有好久没有升过级了。一样等着,就升级下吧。 升级完毕重启之后,突然发现好多错误,原来的应用也没法启动了。仔细一看报错信息,是由于Lombok相关的注解似乎都没有生效。 比如:用到@Slf4j的类里,会有类似这样的报错: java: 找不到符号 符号: 变量 log 位置: 类 com.didispace.UserService Java Wed, 07 Jul 2021 10:08:00 GMT 今天到工作室比较晚,在电脑前吃着早饭,看到提示IDEA提示升级,寻思已经有好久没有升过级了。一样等着,就升级下吧。

升级完毕重启之后,突然发现好多错误,原来的应用也没法启动了。仔细一看报错信息,是由于Lombok相关的注解似乎都没有生效。

比如:用到@Slf4j的类里,会有类似这样的报错:

IDEA还提示,现在使用的编译器不支持lombok

搜索一番,是由于IDEA版本导致的Lombok失效,不过这个问题后来解决了。 所以,我们只需要更新lombok版本,使用1.18.14及之后的版本即可:

如果是Spring Boot用户,往往不写版本号,因为2.x开始,就Spring Boot就把lombok的版本一起纳入了。有些Spring Boot的老版本就比较容易出现这个问题,比如DD这边出问题的工程就是使用的2.1.3,这里默认引入的lombok版本是1.18.6。

因为Lombok版本低,所以在IDEA升级之后就出了这样的问题。手工维护版本到1.18.14之后,得到解决。


如果上面的办法无法解决你的问题,那么再看看下面这些,或许可以帮你解决问题:

  1. Lombok插件是否安装、是否开启

  1. Annotation Processors中的Enable annotation processing是否勾选

  1. 在Compiler中增加参数配置:-Djps.track.ap.dependencies=false

]]>
IDEA重构技巧:更改签名 https://java.didispace.com/idea-tips/refactor/change-signature.html https://java.didispace.com/idea-tips/refactor/change-signature.html IDEA重构技巧:更改签名 IDEA重构技巧:更改签名 来看看如何安全地更改类或方法的签名。 我们在 BugReport 中的方法 binaryStrings 接受一个 String 参数: public boolean binaryStrings(String b) { Stack&lt;Character&gt; s = new Stack&lt;&gt;(); for (char c : b.toCharArray()) if (s.empty() || !s.peek().equals(c)) s.push(c); else s.pop(); return s.empty(); } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:更改签名

来看看如何安全地更改类或方法的签名。

我们在 BugReport 中的方法 binaryStrings 接受一个 String 参数:

我们可以在方法 binaryStrings 中添加一个参数,例如,一个 int 类型的计数器。 同样,这也是一种就地重构,并将在间距区域中使用 R 图标高亮显示。 我们可以点击间距中的图标,更新方法签名,向参数添加默认值,以便让方法的任何调用者都使用默认值。

我们也可以在 macOS 上使用⌥⏎ 或在 Windows/Linux 上使用 Alt+Enter 更新方法签名并添加默认参数值。

我们也可以在 macOS 上使用 ⌘F6 或在 Windows/Linux 上使用 Ctrl+F6 调用 Change Signature 对话框更改法签名。 让我们添加一个布尔参数 state,默认值为 "true"。 我们也可以使用此对话框更改参数顺序。 它还可以选择通过重载进行委托。 重构后,方法将被重载。

我们可以使用这个 MyMap 类查看更改类签名对它的影响。 我们可以在 macOS 上使用 ⌘F6,或者在 Windows/Linux 上使用 Ctrl+F6 来修改类签名。 我们向其添加两个通用参数:一个名为 K,默认值 Integer;一个名为 V,默认值 String。 重构类后,MyMap 的用法将改变。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:提取常量 https://java.didispace.com/idea-tips/refactor/extract-constant.html https://java.didispace.com/idea-tips/refactor/extract-constant.html IDEA重构技巧:提取常量 IDEA重构技巧:提取常量 在代码库中,通常建议使用常量而不是文字值,那么我们来看看如何重构代码以引入常量。 public static boolean beautifulBinaryStrings(String s) { while (!s.equals(s = s.replaceAll(&quot;AA|BB&quot;, &quot;&quot;))) { System.out.println(s); } return s.isEmpty(); } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:提取常量

在代码库中,通常建议使用常量而不是文字值,那么我们来看看如何重构代码以引入常量

我们的方法 beautifulBinaryStrings 使用字符串文字值。 我们可以在 macOS 上使用快捷键 ⌥⌘C,或者在 Windows/Linux 上使用 Ctrl+Alt+C 将这个值提取到常量。

IntelliJ IDEA 根据文字值建议常量名称。 我们将选择第一个建议。 根据需要,您也可以选择将这个常量移到其他类中。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:提取字段 https://java.didispace.com/idea-tips/refactor/extract-field.html https://java.didispace.com/idea-tips/refactor/extract-field.html IDEA重构技巧:提取字段 IDEA重构技巧:提取字段 您可以通过此重构引入或提取字段并将其初始化。 我们的 ViewImpl 类中的方法 getItemsList 使用常量 0 和 4 来获取一个列表的子集。 public class ViewImpl implements View { @Override public List&lt;Integer&gt; getItemsList() { return List.of(1, 2, 3, 4, 5).subList(0,4); } } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:提取字段

您可以通过此重构引入或提取字段并将其初始化。

我们的 ViewImpl 类中的方法 getItemsList 使用常量 0 和 4 来获取一个列表的子集。

除了将其定义为常量,您还可以在 macOS 上使用 ⌥⌘F,或者在 Windows/Linux 上使用 Ctrl+Alt+F 来引入字段存储这些值,以便它们在不同实例中拥有不同值。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:提取方法 https://java.didispace.com/idea-tips/refactor/extract-method.html https://java.didispace.com/idea-tips/refactor/extract-method.html IDEA重构技巧:提取方法 IDEA重构技巧:提取方法 Extract Method 重构可以使您的方法更短、更易读。 public boolean binaryStrings(String b) { Stack&lt;Character&gt; s = new Stack&lt;&gt;(); for (char c : b.toCharArray()) if (s.empty() || !s.peek().equals(c)) s.push(c); else s.pop(); return s.empty(); } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:提取方法

Extract Method 重构可以使您的方法更短、更易读。

让我们在 binaryStrings 方法中选择可以分组的代码。 我们可以在 macOS 上使用快捷键 ⌥⌘M,或者在 Windows/Linux 上使用 Ctrl+Alt+M 将这段代码提取到另一方法。
本块所用局部变量或方法参数将作为参数传递。 输入方法名称后,例如 manipulateStack,我们提取的代码块就会被替换成方法的调用。

您也可以通过以下方式提取方法:选择代码,在 macOS 上使用 ⌥⏎ 或者在 Windows/Linux 上使用 Alt+Enter,然后选择 Extract Method。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:提取参数 https://java.didispace.com/idea-tips/refactor/extract-parameter.html https://java.didispace.com/idea-tips/refactor/extract-parameter.html IDEA重构技巧:提取参数 IDEA重构技巧:提取参数 通过 Extract Parameter 重构,您可以在方法中选择一个常量或表达式,并将其定义为参数传递给方法。 在本示例中,我们还为 getItemsList 方法引入了第二个字段,名为 toIndex。 public class ViewImpl implements View { private final int fromIndex; private final int toIndex; public ViewImpl() { fromIndex = 0; toIndex = 4; } public List&lt;Integer&gt; getItemsList() { return List.of(1, 2, 3, 4, 5).subList(fromIndex, toIndex); } } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:提取参数

通过 Extract Parameter 重构,您可以在方法中选择一个常量或表达式,并将其定义为参数传递给方法。 在本示例中,我们还为 getItemsList 方法引入了第二个字段,名为 toIndex

getItemsList 方法中,您可以将表达式 List.of(1,2,3,4,5) 作为参数传递给此方法。 方法参数的类型与所选表达式的类型相同。

您也可以选中 Delegate via method overloading 复选框,以保留原始方法并允许引入第二个方法。 这意味着任何一个方法都可以根据调用者来使用。

Extract parameter 可以帮助您将表达式移到最合理的位置,使方法或方法调用更易读。 使用易于理解的参数名称也有助于提高可读性。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:提取变量 https://java.didispace.com/idea-tips/refactor/extract-variable.html https://java.didispace.com/idea-tips/refactor/extract-variable.html IDEA重构技巧:提取变量 IDEA重构技巧:提取变量 我们也可以根据需要提取变量。 有时,我们可以将表达式移到一个适当命名的变量中,使代码更易读。 public ContextActionsWithAltEnter(double cityPopulation) { if (cityPopulation &gt; 0x1.2016eb678a2p43 &amp;&amp; cityPopulation &lt; 987677.8) { if (cityPopulation % 5 == 0) { this.cityPopulation /= 2; } } this.cityPopulation = cityPopulation; } IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:提取变量

我们也可以根据需要提取变量

有时,我们可以将表达式移到一个适当命名的变量中,使代码更易读。

ContextActionsWithAltEnter 构造函数中的 if 语句看起来有些复杂。 我们可以选择表达式,在 macOS 上使用 ⌥⌘V,或者在 Windows/Linux 上使用 Ctrl+Alt+V。 确保给它起一个有用的名字,如 lowerLimit。 我们也可以将第二个条件提取到一个变量中,并将其命名为 upperLimit。 根据需要,您可以选择将提取的变量定义为 final,如果使用的是 Java 10 或更高版本,可以定义为 var

表达式现在看起来显然更易读了。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:内联方法 https://java.didispace.com/idea-tips/refactor/inline-method.html https://java.didispace.com/idea-tips/refactor/inline-method.html IDEA重构技巧:内联方法 IDEA重构技巧:内联方法 内联方法重构 是 Extract Method 重构的逆转。 我们可以在 macOS 上使用快捷键 ⌥⌘N ,或者在 Windows/Linux 上使用 Ctrl+Alt+N 来内联刚刚创建的方法 manipulateStack。 IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:内联方法

内联方法重构 是 Extract Method 重构的逆转。

我们可以在 macOS 上使用快捷键 ⌥⌘N ,或者在 Windows/Linux 上使用 Ctrl+Alt+N 来内联刚刚创建的方法 manipulateStack

我们可以内联方法内容然后删除方法,也可以保留方法。

在此示例中,我们删除了方法。

但为什么要内联方法呢? 比如,我们可以用它来移除不必要的重定向,或者我们也可能想要内联严重重构的方法,然后再次提取。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:重命名元素 https://java.didispace.com/idea-tips/refactor/rename.html https://java.didispace.com/idea-tips/refactor/rename.html IDEA重构技巧:重命名元素 IDEA重构技巧:重命名元素 直接在类文件中手动重命名并不安全。 例如,如果我们在编辑器中将 Bug 类重命名为 ABug,可能会错过更新使用它的所有其他代码。 从 IntelliJ IDEA 2020.2 开始,您会在编辑器中看到“相关问题”的错误消息。 IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:重命名元素

直接在类文件中手动重命名并不安全。 例如,如果我们在编辑器中将 Bug 类重命名为 ABug,可能会错过更新使用它的所有其他代码。 从 IntelliJ IDEA 2020.2 开始,您会在编辑器中看到“相关问题”的错误消息。

就地重命名重构在间距中高亮显示。 点击间距中的 R 图标,我们可以预览 Bug 到 ABug 所有用法的重命名。

IntelliJ IDEA 还可以查找名称相似的变量,让我们选择要更新的变量。
另外,在编辑器中更改类名称时,我们可以使用快捷键 ⌥⏎ 或 Alt+Enter 重复这些步骤。

您也可以在 macOS 上使用 ⇧F6,或在 Windows/Linux 上使用 Shift+F6 来调用重命名重构,IntelliJ IDEA 将为您的类、方法和变量建议替代名称。 如果选择新的名称,IntelliJ IDEA 会安全地完成重构。

例如,如果我们将字段 description 重命名为 desc,IntelliJ IDEA 会检测此字段是否用于 gettersetter 方法,并询问我们是否更新。 它还会更新该字段在方法参数名称中的用法。

Refactor variable name

让我们使用一个名为 View 的接口,它定义了一个方法 getItems。 我们可以在 macOS 上使用 ⌘B,或者在 Windows/Linux 上使用 Ctrl+B导航到它的用法。 此接口由类 ViewImpl 实现。

在名为 View 的接口中,在 macOS 上使用 ⇧F6 或在 Windows/Linux 上使用 Shift+F6,将方法 getItems 重命名为 getItemsList。 当我们按 Enter 时,它的实现会在 ViewImpl 类中更新。

Refactor variable name

您还可以访问项目窗口,并在 macOS 上使用 ⇧F6 或在 Windows/Linux 上使用 Shift+F6 在文件名上更改类、包、文件或目录的名称。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
IDEA重构技巧:安全删除 https://java.didispace.com/idea-tips/refactor/safe-delete.html https://java.didispace.com/idea-tips/refactor/safe-delete.html IDEA重构技巧:安全删除 IDEA重构技巧:安全删除 如果您不想再在项目中使用某个文件或符号,您应该把它安全删除。 选择要删除的文件或类,然后使用 ⌘⌦,或者在 Windows/Linux 上使用 Alt+Delete。 IntelliJ IDEA 在确保资源可被安全删除之后才会将其删除。 IntelliJ IDEA Thu, 02 Nov 2023 12:10:32 GMT IDEA重构技巧:安全删除

如果您不想再在项目中使用某个文件或符号,您应该把它安全删除

选择要删除的文件或类,然后使用 ⌘⌦,或者在 Windows/Linux 上使用 Alt+Delete。 IntelliJ IDEA 在确保资源可被安全删除之后才会将其删除。

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
最常用的IntelliJ IDEA快捷键(含Windows、MacOS双版本) https://java.didispace.com/idea-tips/shortcutkeys/allinone.html https://java.didispace.com/idea-tips/shortcutkeys/allinone.html 最常用的IntelliJ IDEA快捷键(含Windows、MacOS双版本) 最常用的IntelliJ IDEA快捷键(含Windows、MacOS双版本) 本文Mac快捷键风格为Intellij IDEA Classic,如不是则首先需要在Preferences中切换 一. Mac符号缩写 Mac电脑键盘的符号缩写说明如下,下面可能会用到 IntelliJ IDEA Thu, 02 Nov 2023 11:10:32 GMT 最常用的IntelliJ IDEA快捷键(含Windows、MacOS双版本)

本文Mac快捷键风格为Intellij IDEA Classic,如不是则首先需要在Preferences中切换

一. Mac符号缩写

Mac电脑键盘的符号缩写说明如下,下面可能会用到

标记 按键
Command
Shift
Caps Lock
Option
Control
Return/Enter
Delete
向前删除键(Fn+Delete)
上箭头
下箭头
左箭头
右箭头
Page Up(Fn+↑)
Page Down(Fn+↓)
Home Fn + ←
End Fn + →
右制表符(Tab键)
左制表符(Shift+Tab)
Escape (Esc)
电源开关键

二. 基础操作

1. 基础定位与编辑

操作 Windows Mac(OS X)
剪切 Ctrl + X ⌘X
复制 Ctrl + C ⌘C
粘贴 Ctrl + V ⌘V
从最近的缓冲区粘贴(弹出面板供选择) Ctrl + Shift + V ⌘⇧V
撤销 Ctrl + Z ⌘Z
删除光标所在行代码 Ctrl + Y ⌘Y
复制光标所在行,并把复制内容插入下一行 Ctrl + D ⌘D
递进式选择代码块。连续按会扩大选中范围,从词到句到段 Ctrl + W ⌘W
在当前文件跳转到某一行的指定处 Ctrl + G ⌘G
字面量大小写切换 Ctrl + Shift + U ⌘⇧U
注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 Ctrl + / ⌘/
块注释 Ctrl + Shift + / ⌘⇧/
基础代码补全,默认被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号(KeyMap->Main menu –> Code –> Completion->Basic) Ctrl + Space ⌃Space
智能代码补全 Ctrl + Shift + Space ⌃⇧Space
删除光标后面的单词或是中文句 Ctrl + Delete ⌥Fn⌫
删除光标前面的单词或是中文句 Ctrl + BackSpace ⌥⌦
光标跳转到当前单词(中文句)/当前行的左侧开头位置 Ctrl/Alt + 左方向键 ⌥←/⌘←
光标跳转到当前单词(中文句)/当前行的右侧开头位置 Ctrl/Alt + 右方向键 ⌥→/⌘→

2. 代码块级编辑操作

操作 Windows Mac(OS X)
展开代码块 Ctrl + 加号 ⌘+
折叠代码块 Ctrl + 减号 ⌘-
代码块全部折叠 Ctrl + Shift + 减号 ⌘⇧-
移动光标到当前所在代码的花括号开始/结束位置 Ctrl + ]/Ctrl +[ ⌘] / ⌘[
选择光标处到代码块结束/开始的范围 Ctrl + Shift + ]/ Ctrl + Shift + [ ⌘⇧] / ⌘⇧[
重写父类方法 Ctrl + O ⌘O
实现方法 Ctrl + I ⌘I
包围代码(使用if..else, try..catch, for, synchronized等包围选中的代码) Ctrl + Alt + T ⌘⌥T
生成代码(set/get方法,构造函数等) Alt + Insert ⌃↩/⌃N
插入自定义动态代码模板 Ctrl + J ⌘J
动态代码模板环绕 Ctrl + Alt + J ⌘⌥J
格式化代码 Ctrl + Alt + L ⌘⌥L
优化import Ctrl + Alt + O ⌘⌥O

三. 查询替换定位

此处主要处理对象为变量(field)方法(method)

1. 查看定义与文档

操作 Windows Mac(OS X)
显示代码简要信息 Ctrl + 鼠标悬浮代码上 ⌘鼠标悬浮代码上
快速查看文档(用在变量上,则显示变量初始化语句) Ctrl + Q ⌃J/⌃鼠标中键
方法参数提示显示 Ctrl + P ⌘P
在打开的文件标题上,弹出该文件路径 Ctrl + 左键单击 ⌘鼠标左键

2. 查询使用情况

操作 Windows Mac(OS X)
查看选择目标在项目中的使用 Alt + F7 ⌥F7(Fn)
查看选择目标在本文件中的使用 Ctrl + F7 ⌘F7(Fn)
查看选择目标在本文件中的使用(高亮显示) Ctrl + Shift + F7 ⌘⇧F7(Fn)
依次遍历每个选中的目标 F3 F3(Fn)

3. 跳转定义与调用处

操作 Windows Mac(OS X)
进入选择目标的定义处或使用处 Ctrl + B/ Ctrl + 鼠标左键 ⌘B/ ⌘鼠标左键
进入选择目标的实现处 Ctrl + Alt + B/ Ctrl + Alt + 鼠标左键 ⌘⌥B/ ⌘⌥鼠标左键
前往选择目标的父类的方法 / 接口定义 Ctrl + U ⌘U
跳转到返回类型的声明处 Ctrl + Shift + B ⌘⇧B

4. 高级查询/定位/替换(复杂查询,会直接弹出对话框)

操作 Windows Mac(OS X)
文本查找(当前文件) Ctrl + F ⌘F
文本替换(当前文件) Ctrl + R ⌘R
文本查找(全局) Ctrl + Shift + F ⌃⇧Fn F
文本替换(全局) Ctrl + Shift + R ⌃⇧ R
根据输入的类名,查找类文件 Ctrl + N ⌘N
根据输入的文件名,查找文件 Ctrl + Shift + N ⌘⇧ N
查找在类中的方法 Ctrl + Alt + Shift + N ⌘⌥⇧N
查询任何东西 双击Shift 双击⇧
查找动作(说明书,很好用,当不记得快捷键时可以用这个查询) Ctrl + Shift + A ⇧⌘A

5. 错误与异常查询

操作 Windows Mac(OS X)
依次定位每个错误或者警告 F2 F2(Fn)
在光标所在的错误代码处显示错误信息 Ctrl + F1 ⌘F1(Fn)
显示意向动作和快速修复代码 Alt + Enter ⌥↩
查看外部文档(在某些代码上会触发打开浏览器显示相关文档) 未知 (⇧)F1(Fn)

四. 导航

1. 代码文件结构

操作 Windows Mac(OS X)
弹出当前文件结构层,可以在弹出的层上直接输入进行筛选(可用于搜索类中的方法) Ctrl + F12 ⌘F12 (Fn)
显示当前类的层次结构 Ctrl + H ⌃H
显示方法层次结构 Ctrl + Shift + H ⌘⇧H
显示调用层次结构 Ctrl + Alt + H ⌃⌥H

2. 操作记录查询

操作 Windows Mac(OS X)
显示最近打开的文件记录列表 Ctrl + E ⌘E
显示最近修改的文件记录列表 Ctrl + Shift + E ⌘ ⇧E
查看最近的变更记录 Alt + Shift + C ⌥⇧C

3. 跳转回退

操作 Windows Mac(OS X)
退回 / 前进到上一个操作的地方(windows有可能与系统快捷键翻转屏幕冲突,需要修改:桌面右键->图形选项->选项和支持,将旋转屏幕的几个快捷键修改即可) Ctrl + Alt + 方向左键/方向右键 ⌘⌥← / ⌘⌥→
跳转到最后一次编辑的地方 Ctrl + Shift + BackSpace ⌘⇧⌫

4. 面板切换

操作 Windows Mac(OS X)
左右切换打开的编辑tab页 Ctrl + ← / Ctrl + → 未知
显示所有的编辑tab页 Ctrl + tab ⌃⇥
返回到前一个工具窗口 F12 F12

5. 标签与收藏夹

操作 Windows Mac(OS X)
选中文件/文件夹,使用助记符设定/取消书签 Ctrl + F11 ⌘F11 (Fn)
直接设置数字标签 Ctrl + Shift + 1,2,3...9 ⌃⇧1,2,3...9
定位到对应数值的书签位置 Ctrl + 1,2,3...9 1,2,3...9
添加到收藏夹 Alt + Shift + F ⌥⇧F
查看已经设置的标签与收藏夹(Favorites面板--Bookmarks中可以查看) Alt + 2(Favorites面板) ⌘2(Favorites面板)
删除favorites、Bookmarks 在Favorites面板中,选中要删除的对象,按delete 在Favorites面板中,选中要删除的对象,按⌫

五. 重构

操作 Windows Mac(OS X)
复制文件到指定目录 F5 F5
移动文件到指定目录 F6 F6
安全重命名文件、变量等 Shift + F6 ⇧F6
更改签名 Ctrl + F6 ⌘F6
将选中的代码提取为方法 Ctrl + Alt + M ⌘⌥M
提取变量 Ctrl + Alt + V ⌘⌥V
提取字段 Ctrl + Alt + F ⌘⌥F
提取常量 Ctrl + Alt + C ⌘⌥C
提取参数 Ctrl + Alt + P ⌘⌥P

六.  调试

操作 Windows Mac(OS X)
进入下一步,如果当前行断点是一个方法,则不进入当前方法体内 F8 F8(Fn)
进入下一步,如果当前行断点是一个方法,则进入当前方法体内, 如果该方法体还有方法,则不会进入该内嵌的方法中 F7 F7(Fn)
智能步入,断点所在行上有多个方法调用,会弹出进入哪个方法 Shift + F7 ⇧F7 (Fn)
智能跳出 Shift + F8 ⇧F8 (Fn)
恢复程序运行,如果该断点下面代码还有断点则停在下一个断点上 F9 F9(Fn)
运行到光标处,如果光标前有其他断点会进入到该断点 Alt + F9 ⌥F9(Fn)
计算表达式(可以更改变量值使其生效) Alt + F8 ⌥F8 (Fn)
切换断点(若光标当前行有断点则取消断点,没有则加上断点) Ctrl + F8 ⌘F8 (Fn)
查看断点信息 Ctrl + Shift + F8 ⌘⇧F8 (Fn)

七. 系统功能

操作 Windows Mac(OS X)
打开相应编号的工具窗口 Alt + 1...9 ⌘1...⌘9
切换全屏模式 未知 ⌃⌘F
切换最大化编辑器 双击tab全屏 ⌘⇧F12/双击tab全屏
检查当前文件与当前的配置文件 Alt + Shift + I ⌥⇧I
快速切换当前的scheme(切换主题、代码样式等) 未知 ⌃`
打开IDEA系统设置 Ctrl + Alt + S ⌘,
打开项目结构对话框 Ctrl + Alt + Shift + S ⌘;
关闭活动run/messages/find/... tab 未知 ⌘⇧F4

八. 代码版本管理

操作 Windows Mac(OS X)
提交代码到版本控制器 Ctrl + K ⌘K
从版本控制器更新代码 Ctrl + T ⌘T

九. 快捷键查看工具

1. 查看某特定快捷键的具体功能

使用IDEA自带的工具: Setting(Windows快捷键Ctrl+Alt+S) --> Keymap --> Find Shortcut --> 按入快捷键,即可筛选出快捷键对应的功能。

如下图:

2. 查看某功能对应的快捷键

通过安装使用IDEA插件:Key Promoter X来实现查找功能

安装方式:Settings --> plugins --> Marketplace,搜索Key Promoter X并安装

使用方式:安装并重启激活插件后,每当点击IDEA中各个按钮、功能时,如果此功能存在对应的快捷键,Key Promoter X在IDEA右下角都会提示此快捷键;

如果没有,则可能会提示可以设置相应的快捷键操作

也可以通过打开右侧Key Promoter X面板查看曾经使用和提醒过的功能对应的快捷键

本文转载自:https://blog.csdn.net/u010086122/article/details/100122085

好了,今天的分享就到这里,如果这个小技巧对你有用,那就帮忙点赞、在看、分享、关注,四连支持一下吧!

如果你觉得这个系列还不错,可以关注我在连载的这个专栏:玩转IntelliJ IDEA,分享各种使用技巧与好用插件!

]]>
使用IntelliJ IDEA中的Live Templates配置自定义模板 https://java.didispace.com/idea-tips/shortcutkeys/live-templates.html https://java.didispace.com/idea-tips/shortcutkeys/live-templates.html 使用IntelliJ IDEA中的Live Templates配置自定义模板 平时用IntelliJ IDEA写代码的时候,你有没有用过这些快捷方式: 输入main,会弹出自动补全完整的main结构: 输入sout,会弹出自动补全完整的System.out语句: IntelliJ IDEA Tue, 29 Oct 2024 17:00:00 GMT 平时用IntelliJ IDEA写代码的时候,你有没有用过这些快捷方式:

输入main,会弹出自动补全完整的main结构:

输入sout,会弹出自动补全完整的System.out语句:

那么问题来了:

  1. 还有哪些快捷方式?
  2. 如何定义自己想要的?

初识 Live Templates

该功能来自于IntelliJ IDEA的Live Templates配置,你可以通过菜单进入Setting,然后搜索Live Templates找到它:

点开Java就能看预定义的模板了:

不是很多,可以挑你常用的记一下即可。

如果要定义要用的模板,可以点击上面的+

选择Live Tempalte之后在下面会看到一个编辑框:

根据自己需要填写要创建的快捷模板内容。最后记得保存,就可以成功创建了。

尝试在编码框内输入上面定义的快捷方式:ddfor,就可以用到上面定义的模板代码了:

使用进阶

上面仅介绍了Live Template最基本的使用方式。如果还不能满足你的要求,下面几项提示也许可以帮到你。

使用分组

如果对这个功能的需求比较多,需要定义比较多模板,尤其是做基础架构给大家定规范做工具的话,还可以在创建Live Template的时候使用Group来创建一些独立的组来方便管理。

使用参数

很多时候我们创建模版还会需要一些动态的信息,比如自定义模板注释的时候,需要使用:时间、用户等动态信息。

在Live Template的模板定义中是支持使用参数的,使用$$来引用,两个$中间放参数名。Live Template提供了一些预定义的参数,同时也支持用户自定义变量。

关于这块使用参数和有哪些预定义参数,读者可以自行查阅官方文档:Live template variables

导入导出

如果你想使用别人的模板,或者想把自己的模板分享给被人,那么可以使用导入导出功能。

功能位置如下图:

然后选择你要导出导入的配置内容里选择Live Templates即可

好了,今天的分享就到这里,希望内容对您有用 ^_^

]]>
Java 9 - 21:新特性解读(持续连载) https://java.didispace.com/java-features/ https://java.didispace.com/java-features/ Java 9 - 21:新特性解读(持续连载) Java 9 - 21:新特性解读(持续连载) 2022年3月下旬的时候,Java已经更新到了18。但我们似乎很多开发者的Java认识还都停留在Java 8,所以DD计划做一个新的专栏内容,专注分享Java前沿知识,内容将涵盖从Java 9 - 最新版本的各种有意思的新特性解读,持续连载!收藏起来! 以下内容中,不是每一个点都会特别开一篇来介绍,能简单说明且与我们日常开发关系不大的,就不单独开篇了。 对于Preview功能,如果您不知道如何运行,可以查看Java新特性中的Preview功能如何运行和调试 Java Wed, 20 Apr 2022 00:00:00 GMT Java 9 - 21:新特性解读(持续连载)

2022年3月下旬的时候,Java已经更新到了18。但我们似乎很多开发者的Java认识还都停留在Java 8,所以DD计划做一个新的专栏内容,专注分享Java前沿知识,内容将涵盖从Java 9 - 最新版本的各种有意思的新特性解读,持续连载!收藏起来!

以下内容中,不是每一个点都会特别开一篇来介绍,能简单说明且与我们日常开发关系不大的,就不单独开篇了。

对于Preview功能,如果您不知道如何运行,可以查看Java新特性中的Preview功能如何运行和调试

Java 21

2023年9月20日,Oracle公司宣布Java 21正式发布。该版本是继JDK 17之后最新的长期支持版本(LTS),将获得至少8年的支持!

Java 21 号称具有数千项性能、稳定性和安全性改进。新的 JDK 21 包括对 15 项改进的抢先体验,这些增强功能是在 Oracle CloudWorld 2023 会议上宣布的,包括支持虚拟线程以提高整体吞吐量,以及增加对向量应用编程接口(API)的支持,从而更轻松地构建涉及人工智能 AI 模型的 Java 应用。

该版本主要有以下特性,我们将在Java新特性专栏中,持续连载解读各项更新,欢迎关注收藏!

以下是预览和孵化特性

  • 430: String Templates (Preview)
  • 442: Foreign Function & Memory API (Third Preview)
  • 443: Unnamed Patterns and Variables (Preview)
  • 445: Unnamed Classes and Instance Main Methods (Preview)
  • 446: Scoped Values (Preview):还在测试中的一项新功能,可让您共享线程内和线程间无法更改的数据。这比使用线程局部变量更好,特别是当您使用大量虚拟线程时。线程局部变量存在一些问题,例如它们可能会更改太多、持续时间太长以及使用成本昂贵。作用域值(Scoped Values)允许您在大型程序的各个部分之间安全地共享数据,而无需使用方法参数。这个想法在JDK 20中得到了测试。
  • 448: Vector API (Sixth Incubator)
  • 453: Structured Concurrency (Preview)

Java 20

该版本推出的均为孵化与预览功能,所以这里不做单独的详细解读,大部分内容均放在Java 21中介绍。

以下内容在Java 21中正式定稿:

以下内容在Java 21中继续迭代:

  • 429: Scoped Values (Incubator)
  • 434: Foreign Function & Memory API (Second Preview)
  • 437: Structured Concurrency (Second Incubator)
  • 438: Vector API (Fifth Incubator)

Java 19

该版本推出的均为孵化与预览功能,所以这里不做单独的详细解读,大部分内容均放在Java 21中介绍。

  • 422: Linux/RISC-V Port

以下预览特性在Java 21中正式定稿:

以下内容在Java 21中继续迭代:

  • 424: Foreign Function & Memory API (Preview)
  • 426: Vector API (Fourth Incubator)
  • 428: Structured Concurrency (Incubator)

Java 18

Java 17

  • 306: Restore Always-Strict Floating-Point Semantics
  • 356: Enhanced Pseudo-Random Number Generators
  • 382: New macOS Rendering Pipeline
  • 391: macOS/AArch64 Port
  • 398: Deprecate the Applet API for Removal
  • 403: Strongly Encapsulate JDK Internals
  • 406: Pattern Matching for switch (Preview)
  • 407: Remove RMI Activation
  • 409: Sealed Classes
  • 410: Remove the Experimental AOT and JIT Compiler
  • 411: Deprecate the Security Manager for Removal
  • 412: Foreign Function & Memory API (Incubator)
  • 414: Vector API (Second Incubator)
  • 415: Context-Specific Deserialization Filters

Java 16

  • 338: Vector API (Incubator)
  • 347: Enable C++14 Language Features
  • 357: Migrate from Mercurial to Git
  • 369: Migrate to GitHub
  • 376: ZGC: Concurrent Thread-Stack Processing
  • 380: Unix-Domain Socket Channels
  • 386: Alpine Linux Port
  • 387: Elastic Metaspace
  • 388: Windows/AArch64 Port
  • 389: Foreign Linker API (Incubator)
  • 390: Warnings for Value-Based Classes
  • 392: Packaging Tool
  • 393: Foreign-Memory Access API (Third Incubator)
  • 394: Pattern Matching for instanceof
  • 395: Records
  • 396: Strongly Encapsulate JDK Internals by Default
  • 397: Sealed Classes (Second Preview)

Java 15

  • 339: Edwards-Curve Digital Signature Algorithm (EdDSA)
  • 360: Sealed Classes (Preview)
  • 371: Hidden Classes
  • 372: Remove the Nashorn JavaScript Engine
  • 373: Reimplement the Legacy DatagramSocket API
  • 374: Disable and Deprecate Biased Locking
  • 375: Pattern Matching for instanceof (Second Preview)
  • 377: ZGC: A Scalable Low-Latency Garbage Collector
  • 378: Text Blocks
  • 379: Shenandoah: A Low-Pause-Time Garbage Collector
  • 381: Remove the Solaris and SPARC Ports
  • 383: Foreign-Memory Access API (Second Incubator)
  • 384: Records (Second Preview)
  • 385: Deprecate RMI Activation for Removal

Java 14

  • 305: Pattern Matching for instanceof (Preview)
  • 343: Packaging Tool (Incubator)
  • 345: NUMA-Aware Memory Allocation for G1
  • 349: JFR Event Streaming
  • 352: Non-Volatile Mapped Byte Buffers
  • 358: Helpful NullPointerExceptions
  • 359: Records (Preview)
  • 361: Switch Expressions (Standard)
  • 362: Deprecate the Solaris and SPARC Ports
  • 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
  • 364: ZGC on macOS
  • 365: ZGC on Windows
  • 366: Deprecate the ParallelScavenge + SerialOld GC Combination
  • 367: Remove the Pack200 Tools and API
  • 368: Text Blocks (Second Preview)
  • 370: Foreign-Memory Access API (Incubator)

Java 13

  • 350: Dynamic CDS Archives
  • 351: ZGC: Uncommit Unused Memory
  • 353: Reimplement the Legacy Socket API
  • 354: Switch Expressions (Preview)
  • 355: Text Blocks (Preview)

Java 12

  • 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)
  • 230: Microbenchmark Suite
  • 325: Switch Expressions (Preview)
  • 334: JVM Constants API
  • 340: One AArch64 Port, Not Two
  • 341: Default CDS Archives
  • 344: Abortable Mixed Collections for G1
  • 346: Promptly Return Unused Committed Memory from G1

Java 11

  • 181: Nest-Based Access Control
  • 309: Dynamic Class-File Constants
  • 315: Improve Aarch64 Intrinsics
  • 318: Epsilon: A No-Op Garbage Collector
  • 320: Remove the Java EE and CORBA Modules
  • 321: HTTP Client (Standard)
  • 323: Local-Variable Syntax for Lambda Parameters
  • 324: Key Agreement with Curve25519 and Curve448
  • 327: Unicode 10
  • 328: Flight Recorder
  • 329: ChaCha20 and Poly1305 Cryptographic Algorithms
  • 330: Launch Single-File Source-Code Programs
  • 331: Low-Overhead Heap Profiling
  • 332: Transport Layer Security (TLS) 1.3
  • 333: ZGC: A Scalable Low-Latency Garbage Collector(Experimental)
  • 335: Deprecate the Nashorn JavaScript Engine
  • 336: Deprecate the Pack200 Tools and API

Java 10

  • 286: Local-Variable Type Inference
  • 296: Consolidate the JDK Forest into a Single Repository
  • 304: Garbage-Collector Interface
  • 307: Parallel Full GC for G1
  • 310: Application Class-Data Sharing
  • 312: Thread-Local Handshakes
  • 313: Remove the Native-Header Generation Tool (javah)
  • 314: Additional Unicode Language-Tag Extensions
  • 316: Heap Allocation on Alternative Memory Devices
  • 317: Experimental Java-Based JIT Compiler
  • 319: Root Certificates
  • 322: Time-Based Release Versioning

Java 9

  • 102: Process API Updates
  • 110: HTTP 2 Client
  • 143: Improve Contended Locking
  • 158: Unified JVM Logging
  • 165: Compiler Control
  • 193: Variable Handles
  • 197: Segmented Code Cache
  • 199: Smart Java Compilation, Phase Two
  • 200: The Modular JDK
  • 201: Modular Source Code
  • 211: Elide Deprecation Warnings on Import Statements
  • 212: Resolve Lint and Doclint Warnings
  • 213: Milling Project Coin
  • 214: Remove GC Combinations Deprecated in JDK 8
  • 215: Tiered Attribution for javac
  • 216: Process Import Statements Correctly
  • 217: Annotations Pipeline 2.0
  • 219: Datagram Transport Layer Security (DTLS)
  • 220: Modular Run-Time Images
  • 221: Simplified Doclet API
  • 222: jshell: The Java Shell (Read-Eval-Print Loop)
  • 223: New Version-String Scheme
  • 224: HTML5 Javadoc
  • 225: Javadoc Search
  • 226: UTF-8 Property Files
  • 227: Unicode 7.0
  • 228: Add More Diagnostic Commands
  • 229: Create PKCS12 Keystores by Default
  • 231: Remove Launch-Time JRE Version Selection
  • 232: Improve Secure Application Performance
  • 233: Generate Run-Time Compiler Tests Automatically
  • 235: Test Class-File Attributes Generated by javac
  • 236: Parser API for Nashorn
  • 237: Linux/AArch64 Port
  • 238: Multi-Release JAR Files
  • 240: Remove the JVM TI hprof Agent
  • 241: Remove the jhat Tool
  • 243: Java-Level JVM Compiler Interface
  • 244: TLS Application-Layer Protocol Negotiation Extension
  • 245: Validate JVM Command-Line Flag Arguments
  • 246: Leverage CPU Instructions for GHASH and RSA
  • 247: Compile for Older Platform Versions
  • 248: Make G1 the Default Garbage Collector
  • 249: OCSP Stapling for TLS
  • 250: Store Interned Strings in CDS Archives
  • 251: Multi-Resolution Images
  • 252: Use CLDR Locale Data by Default
  • 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
  • 254: Compact Strings
  • 255: Merge Selected Xerces 2.11.0 Updates into JAXP
  • 256: BeanInfo Annotations
  • 257: Update JavaFX/Media to Newer Version of GStreamer
  • 258: HarfBuzz Font-Layout Engine
  • 259: Stack-Walking API
  • 260: Encapsulate Most Internal APIs
  • 261: Module System
  • 262: TIFF Image I/O
  • 263: HiDPI Graphics on Windows and Linux
  • 264: Platform Logging API and Service
  • 265: Marlin Graphics Renderer
  • 266: More Concurrency Updates
  • 267: Unicode 8.0
  • 268: XML Catalogs
  • 269: Convenience Factory Methods for Collections
  • 270: Reserved Stack Areas for Critical Sections
  • 271: Unified GC Logging
  • 272: Platform-Specific Desktop Features
  • 273: DRBG-Based SecureRandom Implementations
  • 274: Enhanced Method Handles
  • 275: Modular Java Application Packaging
  • 276: Dynamic Linking of Language-Defined Object Models
  • 277: Enhanced Deprecation
  • 278: Additional Tests for Humongous Objects in G1
  • 279: Improve Test-Failure Troubleshooting
  • 280: Indify String Concatenation
  • 281: HotSpot C++ Unit-Test Framework
  • 282: jlink: The Java Linker
  • 283: Enable GTK 3 on Linux
  • 284: New HotSpot Build System
  • 285: Spin-Wait Hints
  • 287: SHA-3 Hash Algorithms
  • 288: Disable SHA-1 Certificates
  • 289: Deprecate the Applet API
  • 290: Filter Incoming Serialization Data
  • 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
  • 292: Implement Selected ECMAScript 6 Features in Nashorn
  • 294: Linux/s390x Port
  • 295: Ahead-of-Time Compilation
  • 297: Unified arm32/arm64 Port
  • 298: Remove Demos and Samples
  • 299: Reorganize Documentation

对文章形式感兴趣的可以关注我的网站程序猿DD、或公众号程序猿DD。对视频形式感兴趣的可以关注我的B站程序猿DD、或视频号程序猿DD

]]>
Java新特性中的Preview功能如何运行和调试 https://java.didispace.com/java-features/javac-enable-preview.html https://java.didispace.com/java-features/javac-enable-preview.html Java新特性中的Preview功能如何运行和调试 Java新特性中的Preview功能如何运行和调试 在每个Java新版本发布的特性中,都会包含一些Preview(预览)功能,这些功能主要用来给开发者体验并收集建议。所以,Preview阶段的功能并不是默认开启的。 如果想体验某个Java版本中的Preview功能,您还需要做一些设置才能把程序跑起来。 下面以IDEA 2023.2为例,演示为Java 21开启Preview功能。 第一步:打开setting配置编译参数,按如下图所示:选择Java版本以及增加开启preview的配置参数--enable-preview Java Wed, 04 Oct 2023 00:00:00 GMT Java新特性中的Preview功能如何运行和调试

在每个Java新版本发布的特性中,都会包含一些Preview(预览)功能,这些功能主要用来给开发者体验并收集建议。所以,Preview阶段的功能并不是默认开启的。

如果想体验某个Java版本中的Preview功能,您还需要做一些设置才能把程序跑起来。

下面以IDEA 2023.2为例,演示为Java 21开启Preview功能。

第一步:打开setting配置编译参数,按如下图所示:选择Java版本以及增加开启preview的配置参数--enable-preview

第二步:配置Run/Debug参数,VM参数中增加--enable-preview

再执行相关测试代码的时候,就可以看到已经包含了--enable-preview参数,preview功能得到正常运行

]]>
Java 10 新特性:局部变量的类型推断 https://java.didispace.com/java-features/java10/jep286-local-variable-type-inference.html https://java.didispace.com/java-features/java10/jep286-local-variable-type-inference.html Java 10 新特性:局部变量的类型推断 Java 10 新特性:局部变量的类型推断 在Java当引入泛型的时候,我们申明具体类型的时候需要这样写(等号两边都需要): List&lt;String&gt; list = new ArrayList&lt;String&gt;(); Map&lt;String, String&gt; map = new HashMap&lt;String,String&gt;(); Java Sat, 21 May 2022 00:00:00 GMT Java 10 新特性:局部变量的类型推断

在Java当引入泛型的时候,我们申明具体类型的时候需要这样写(等号两边都需要):

后来在Java 7推出之后,简化为(只需要在左边申明类型即可):

而这次Java 10中,对类型的推断进一步优化,只需要这样即可(类型在等号右边决定):

对于var的使用还有几点要注意的:

  1. 定义的时候必须初始化
  2. 只能用于定义局部变量
  3. 不能用于定义成员变量、方法参数、返回类型
  4. 每次只能定义一个变量,不能复合声明变量

好了,今天的分享就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏

]]>
Java 11 :移除JavaEE和CORBA模块 https://java.didispace.com/java-features/java11/jep320-remove-JavaEE-CORBA.html https://java.didispace.com/java-features/java11/jep320-remove-JavaEE-CORBA.html Java 11 :移除JavaEE和CORBA模块 Java 11 :移除JavaEE和CORBA模块 对于Java EE和CORBA模块在Java 9开始就不推荐使用了。而从Java 11开始正式删除了这部分内容,所以当升级到Java 11或更高的版本的话,务必要先更急以下内容相关的代码: 移除的包: java.xml.ws (JAX-WS) java.xml.bind (JAXB) java.activation (JAF) java.xml.ws.annotation (Common Annotations) java.corba (CORBA) java.transaction (JTA) java.se.ee (以上6个模块的聚合模块) Java Mon, 23 May 2022 00:00:00 GMT Java 11 :移除JavaEE和CORBA模块

对于Java EE和CORBA模块在Java 9开始就不推荐使用了。而从Java 11开始正式删除了这部分内容,所以当升级到Java 11或更高的版本的话,务必要先更急以下内容相关的代码:

移除的包

  • java.xml.ws (JAX-WS)
  • java.xml.bind (JAXB)
  • java.activation (JAF)
  • java.xml.ws.annotation (Common Annotations)
  • java.corba (CORBA)
  • java.transaction (JTA)
  • java.se.ee (以上6个模块的聚合模块)

移除的工具

  • wsgen and wsimport (from jdk.xml.ws)
  • schemagen and xjc (from jdk.xml.bind)
  • idlj, orbd, servertool, and tnamesrv (from java.corba)
]]>
Java 14 新特性:switch表达式增强 https://java.didispace.com/java-features/java14/jep361-switch-expressions.html https://java.didispace.com/java-features/java14/jep361-switch-expressions.html Java 14 新特性:switch表达式增强 Java 14 新特性:switch表达式增强 面对这样的if语句,你是不是很难受呢? if (flag == 1) { log.info(&quot;didispace.com: 1&quot;); } else if (flag == 2) { log.info(&quot;didispace.com: 2&quot;); } else if (flag == 3) { log.info(&quot;didispace.com: 3&quot;); } else if (flag == 4) { log.info(&quot;didispace.com: 4&quot;); } else { log.info(&quot;didispace.com: x&quot;); } Java Fri, 06 May 2022 00:00:00 GMT Java 14 新特性:switch表达式增强

面对这样的if语句,你是不是很难受呢?

是不是想到用switch来改进一下?

舒服了吗?是不是感觉还是不那么舒服呢?

试试Java 14中对Switch表达式的增强功能,继续改造:

这下是不是舒服了?在Java 14的switch表达式增强中,引入了对Lambda语法的支持,让每个case分支变得更为简洁。同时,容易遗忘的break也可以省略了。

Tips:这里的JEP 361特性,经历了JDK 12、JDK 13两个预览版本之后才在JDK 14中定稿,所以部分功能在JDK 12和JDK 13中也会看到,但真正使用,还是建议在JDK 14之后的版本中应用。

本期视频:https://www.bilibili.com/video/BV1gY411A7kG/

好了,今天的分享就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏

]]>
Java 15 新特性:隐藏类 https://java.didispace.com/java-features/java15/jep371-hidden-classes.html https://java.didispace.com/java-features/java15/jep371-hidden-classes.html Java 15 新特性:隐藏类 Java 15 新特性:隐藏类 什么是隐藏类 隐藏类,是一种不能被其他类直接使用的类。引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们。可能有点抽象,不要紧,下面我们通过一个例子来直观的认识它! 本文首发:Java 15 新特性:隐藏类 本期视频:Java 15 新特性:隐藏类 Java Sat, 07 May 2022 00:00:00 GMT Java 15 新特性:隐藏类

什么是隐藏类

隐藏类,是一种不能被其他类直接使用的类。引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们。可能有点抽象,不要紧,下面我们通过一个例子来直观的认识它!

本文首发:Java 15 新特性:隐藏类 本期视频:Java 15 新特性:隐藏类

隐藏类案例

第一步:先创建一个普通的Java类

第二步:编译一下,或得编译后的class文件。然后使用Base64对文件内容Encode,你可以用各种工具,也可以用下面代码来获取:

执行一下,获取到内容如下:

这个内容就是第一步写的类。

第三步:通过反射加载上面生成的类,并调用隐藏类中的hello函数,代码如下:

这里的CLASS_INFO内容就是上一步我们处理好的隐藏类内容,先通过Base64将该内容解码,然后通过反射机制来将这个隐藏类的代理创建出来。

可以看到这里创建隐藏类的时候用的是java.lang.invoke.MethodHandles.Lookup#defineHiddenClass,而创建普通类则是用ClassLoader::defineClass的。而这里的三个参数分别是:

  • bytes:符合java虚拟机规范的字节码
  • initialize:是否要初始化类
  • options:java类的类型,详见java.lang.invoke.MethodHandles.Lookup.ClassOption

再下面的操作就是对这个类的一些内容输出和方法执行。最后我们可以尝试执行下这个测试内容,最终会获得如下输出:

  • 第一行:输出了这个隐藏类的类名
  • 第二行:输出了这个隐藏类下的方法名称
  • 第三行:调用隐藏类下的hello方法获得的返回内容

是不是还挺简单?如果你跟我一样平时会参与一些基础框架的开发工作的话,一定觉得这个功能还挺不错的吧,又多了一种动态功能的实现手段!

好了,今天的分享就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏

]]>
Java 15 新特性:文本块 https://java.didispace.com/java-features/java15/jep378-text-blocks.html https://java.didispace.com/java-features/java15/jep378-text-blocks.html Java 15 新特性:文本块 Java 15 新特性:文本块 假设有这样一个场景,我们需要做一个工具。用来自动生成项目文档,文档可以通过浏览器查看,所以最后产出物肯定是一堆html文件。为了让这些html文件更容易读,良好的格式肯定要保持,该换行的换行、该缩进的缩进。 那么,在组织最后内容的时候,你可能就会这样子来写: String html = &quot;&lt;html&gt;\n&quot; + &quot;&lt;body&gt;\n&quot;+ &quot; &lt;h1&gt;Java 15 新特性:文本块 | 程序猿DD&lt;/h1&gt;\n&quot;+ &quot; &lt;p&gt;didispace.com&lt;/p&gt;\n&quot;+ &quot;&lt;/body&gt;\n&quot;+ &quot;&lt;/html&gt;\n&quot;; Java Fri, 29 Apr 2022 00:00:00 GMT Java 15 新特性:文本块

假设有这样一个场景,我们需要做一个工具。用来自动生成项目文档,文档可以通过浏览器查看,所以最后产出物肯定是一堆html文件。为了让这些html文件更容易读,良好的格式肯定要保持,该换行的换行、该缩进的缩进。

那么,在组织最后内容的时候,你可能就会这样子来写:

当然,也许你也会改进一下,用StringBuilder或者StringBuffer来优化,但不论用什么来写,都逃不了一些要转义的内容,比如上面拼接内容时候的换行\n

一旦存在大量要转义内容的时候,也就增加了我们编写内容的复杂度。复杂度越高,我们就越容易犯错。

所以,在Java 15中增加了一个新特性:文本块(Text Blocks),来帮助我们更便捷的实现多行字符串文字的处理。

对于上面的字符串内容,Java 15中,我们只需要这样写:

好不好简单不少呢?如果没用过的话,赶紧操作试试看吧!

本期视频:https://www.bilibili.com/video/BV1du411k7Bp/

如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性教程

]]>
Java 16 新特性:instanceof增强 https://java.didispace.com/java-features/java16/jep394-pattern-matching-for-instanceof.html https://java.didispace.com/java-features/java16/jep394-pattern-matching-for-instanceof.html Java 16 新特性:instanceof增强 Java 16 新特性:instanceof增强 instanceof这个关键词,主要用来判断某个对象是不是某个类的实例。 比如,有时候我们要处理一个类似这样的数据集: Map&lt;String, Object&gt; data = new HashMap&lt;&gt;(); data.put(&quot;key1&quot;, &quot;aaa&quot;); data.put(&quot;key2&quot;, 111); Java Wed, 04 May 2022 00:00:00 GMT Java 16 新特性:instanceof增强

instanceof这个关键词,主要用来判断某个对象是不是某个类的实例。

比如,有时候我们要处理一个类似这样的数据集:

这个Map中的Value值因为可能是不同的对象,所以定义的是Object。这个时候,当我们get出来的时候,就需要去判断和转换之后再去处理。

比如,我们取出key1value,然后截取一段字符串的操作,就需要这样写:

先判断获取的value是否是String,再做强制类型转换,然后再对字符串进行操作。这是传统的写法,而在Java 16的增强之后,对于instanceof的判断以及类型转换可以合二为一了,所以改进后的写法可以如下:

是不是简单不少呢?如果没用过的话,赶紧操作试试看吧!

Tips:该功能经历了2个Preview版本(JDK 14中的JEP 305、JDK 15中的JEP 375),最终定稿于JDK 16中的JEP 394。

本期视频:Java 16 新特性:instanceof增强

如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏

]]>
Java 16 新特性:record类 https://java.didispace.com/java-features/java16/jep395-records.html https://java.didispace.com/java-features/java16/jep395-records.html Java 16 新特性:record类 Java 16 新特性:record类 以前我们定义类都是用class关键词,但从Java 16开始,我们将多一个关键词record,它也可以用来定义类。record关键词的引入,主要是为了提供一种更为简洁、紧凑的final类的定义方式。 下面就来具体了解record类的细节。 声明record类 声明record类的基础语法: record range(int start, int end){} Java Tue, 10 May 2022 00:00:00 GMT Java 16 新特性:record类

以前我们定义类都是用class关键词,但从Java 16开始,我们将多一个关键词record,它也可以用来定义类。record关键词的引入,主要是为了提供一种更为简洁、紧凑的final类的定义方式。

下面就来具体了解record类的细节。

声明record类

声明record类的基础语法:

我们知道class类可以在单独文件中生命,也可以在其他类中申明。那么record类也一样,它有这几种申明方式:

  1. 单独文件申明:
  1. 在类内部申明:
  1. 函数内申明:

record类详解

在知道了如何申明之后,你一定会想用record申明的就那么点元素,它到底会具备什么能力呢?

因为record关键词申明类主要是为了简化一些类的申明,所以它本质就是一类特殊的class,或者说是某一个模版的class。

record申明的类,具备这些特点:

  1. 它是一个final
  2. 自动实现equalshashCodetoString函数
  3. 成员变量均为public属性

所以,对于之前写的range类,它等价于一个这样的类:

因为一些函数是隐藏的,在range定义的时候,我们看不到,所以我们可以尝试写这样一段测试代码来验证一下:

定义成员函数

因为record申明的本质也是类,那么定义成员函数肯定也是可以的。

比如,我们可以这样在record类中定义成员函数:

然后,就可以这样调用它:

本期视频:https://www.bilibili.com/video/BV1vY4y1b71m/

如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我,持续更新Java新特性专栏

]]>