<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: [yun]</title>
    <description>The latest articles on Forem by [yun] (@andylow).</description>
    <link>https://forem.com/andylow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F612443%2F2af7aae4-43ec-4155-9bd1-896328454886.jpeg</url>
      <title>Forem: [yun]</title>
      <link>https://forem.com/andylow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/andylow"/>
    <language>en</language>
    <item>
      <title>Java 25：值得关注的新特性</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sat, 04 Oct 2025 08:08:30 +0000</pubDate>
      <link>https://forem.com/andylow/java-25zhi-de-guan-zhu-de-xin-te-xing-4cm3</link>
      <guid>https://forem.com/andylow/java-25zhi-de-guan-zhu-de-xin-te-xing-4cm3</guid>
      <description>&lt;p&gt;上一篇我们聊了&lt;a href="https://dev.to/andylow/jdk-8-20-zui-zhong-yong-de-xin-zeng-te-xing-36jc"&gt;《JDK 8 -&amp;gt; 20 最重用的新增特性》&lt;/a&gt;，&lt;br&gt;
这次我们就来看看跨到Java 25有的现代化蜕变。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Java 每 6 个月一个版本，但并不是每次更新都值得你停下手里的项目去研究。&lt;br&gt;
这篇文章帮你抓重点：&lt;br&gt;
从 Java 20 → Java 25，哪些特性是真正「能提升生产力」的？&lt;br&gt;
哪些语法变化会让你少写几行代码？&lt;br&gt;
哪些性能优化会让你的服务启动更快？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;📆 最新 LTS：Java 25（2025 年 9 月发布）&lt;br&gt;
🌍 官方项目页：&lt;a href="https://openjdk.org/projects/jdk/25/" rel="noopener noreferrer"&gt;https://openjdk.org/projects/jdk/25/&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🎯 为什么 Java 25 值得关注
&lt;/h2&gt;

&lt;p&gt;Java 25 是继 Java 21 之后的新 LTS 版本。&lt;br&gt;
这意味着：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;你可以放心升级、长期支持、放上生产没问题。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;从 Java 20 开始，平台的演进方向很清晰：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;🧩 简化语法（Pattern Matching, Records, 简化 main）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🧵 并发模型现代化（Loom, Scoped Values, Structured Concurrency）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⚙️ 性能内核再优化（AOT, GC, JIT 混合）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔍 可观察性增强（JFR, Profiling）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔐 安全 API 补齐（KDF, PEM 支持）&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Java 25 正是把这些「预览特性」打磨成稳定、实用的版本。&lt;br&gt;
所以，这次不是“多几个语法糖”那么简单，而是一次全面成熟化。&lt;/p&gt;


&lt;h2&gt;
  
  
  📊 一图看完 Java 25 的主要更新
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;th&gt;实际意义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;语言&lt;/td&gt;
&lt;td&gt;🧠 原始类型模式匹配 (JEP 507)&lt;/td&gt;
&lt;td&gt;第三预览&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;switch&lt;/code&gt; / &lt;code&gt;instanceof&lt;/code&gt; 支持 &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; 等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;语言&lt;/td&gt;
&lt;td&gt;📦 模块导入声明 (JEP 511)&lt;/td&gt;
&lt;td&gt;预览&lt;/td&gt;
&lt;td&gt;终于能 &lt;code&gt;import module&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;语言&lt;/td&gt;
&lt;td&gt;✨ Compact Source Files / Instance Main (JEP 512)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;Java 也能像脚本一样写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;并发&lt;/td&gt;
&lt;td&gt;🧵 Structured Concurrency (JEP 505)&lt;/td&gt;
&lt;td&gt;第五预览&lt;/td&gt;
&lt;td&gt;虚拟线程的理想搭档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;并发&lt;/td&gt;
&lt;td&gt;🧭 Scoped Values (JEP 506)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;安全替代 &lt;code&gt;ThreadLocal&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;性能&lt;/td&gt;
&lt;td&gt;🚀 AOT + Method Profiling (JEP 514 / 515)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;JVM 冷启动快 30–70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GC&lt;/td&gt;
&lt;td&gt;🧹 Compact Object Headers (JEP 519)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;对象头更小，省内存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GC&lt;/td&gt;
&lt;td&gt;🌱 Generational Shenandoah (JEP 521)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;更稳定的低延迟 GC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;监控&lt;/td&gt;
&lt;td&gt;🔬 JFR Method Timing (JEP 520)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;性能分析更精细&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;加密&lt;/td&gt;
&lt;td&gt;🔐 Key Derivation API (JEP 510)&lt;/td&gt;
&lt;td&gt;正式&lt;/td&gt;
&lt;td&gt;原生支持 PBKDF2 / HKDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;加密&lt;/td&gt;
&lt;td&gt;🗝️ PEM Encodings (JEP 470)&lt;/td&gt;
&lt;td&gt;预览&lt;/td&gt;
&lt;td&gt;内置 PEM 格式支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;平台&lt;/td&gt;
&lt;td&gt;💀 移除 32-bit x86&lt;/td&gt;
&lt;td&gt;移除&lt;/td&gt;
&lt;td&gt;正式告别 32 位时代&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  🚀 真正有感觉的 6 大实用更新
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1️⃣ 冷启动提速：AOT + Method Profiling (JEP 514 / 515)
&lt;/h3&gt;

&lt;p&gt;JVM 启动性能终于不再是短板。&lt;br&gt;
现代应用越来越依赖微服务、云原生部署、容器环境，冷启动 / 弹性伸缩时的启动延迟是痛点。&lt;/p&gt;

&lt;p&gt;Java 25 做了两件事来治这病：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;JEP 515 – 方法剖析 (Method Profiling)&lt;br&gt;
JVM 可以在启动时直接用历史 Profile 信息预热 JIT 编译。&lt;br&gt;
换句话说，它一上来就知道“哪些方法是热点”，少走弯路。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JEP 514 – AOT 命令行增强&lt;br&gt;
简化了 AOT 缓存生成命令，让开发者更容易用上启动优化。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;💡 建议：&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;若是 Serverless / 短生命周期 应用，强烈建议试试。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;生产前先做 A/B 测试，有些 Profile 不匹配会反降性能。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;加入启动日志对比：-XX:+PrintCompilation / JFR 记录。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;profile 数据要定期更新，否则会“学坏”。&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 先生成 profile 数据&lt;/span&gt;
java &lt;span class="nt"&gt;-XX&lt;/span&gt;:+RecordProfilingData &lt;span class="nt"&gt;-jar&lt;/span&gt; MyService.jar

&lt;span class="c"&gt;# 再次启动时使用&lt;/span&gt;
java &lt;span class="nt"&gt;-XX&lt;/span&gt;:UseProfilingDataFile&lt;span class="o"&gt;=&lt;/span&gt;profile.jfr &lt;span class="nt"&gt;-jar&lt;/span&gt; MyService.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2️⃣ 更轻的对象：Compact Object Headers (JEP 519)
&lt;/h3&gt;

&lt;p&gt;对象头从 128 bits → 64 bits，平均内存节省 5–15%。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;一句话：对象更小、内存更省。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;💡 提示：&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;现在是正式功能，不再需要 UnlockExperimentalVMOptions。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;可通过 -XX:+UseCompactObjectHeaders 开启。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;兼容性要测：有些 JNI 或 Unsafe 代码可能依赖旧布局。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3️⃣ 新的线程上下文：Scoped Values (JEP 506)
&lt;/h3&gt;

&lt;p&gt;ThreadLocal 终于有安全、轻量的替代方案。&lt;/p&gt;

&lt;p&gt;🔧 Before（传统写法）&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ThreadLocal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThreadLocal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"andy"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;问题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;忘记 remove() 容易内存泄漏。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在虚拟线程（Loom）中成本高。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚡️ After（Java 25 Scoped Values）&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ScopedValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;runWhere&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"andy"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 自动作用域控制&lt;br&gt;
✅ 无需清理&lt;br&gt;
✅ 完全兼容虚拟线程&lt;/p&gt;

&lt;p&gt;&lt;em&gt;💡 建议：&lt;/em&gt;&lt;br&gt;
用在 request context、trace id、tenant info 等「临时上下文数据」非常香。&lt;/p&gt;
&lt;h3&gt;
  
  
  4️⃣ Pattern Matching for Primitive Types (JEP 507)
&lt;/h3&gt;

&lt;p&gt;终于可以在 switch 中匹配 int, double 等原始类型。&lt;/p&gt;

&lt;p&gt;🔧 Before（传统写法）&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡️ After&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"other"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;更自然、更一致。&lt;br&gt;
仍属预览特性（需 --enable-preview）。&lt;/p&gt;
&lt;h3&gt;
  
  
  5️⃣ 更轻的脚本体验：Compact Source Files (JEP 512)
&lt;/h3&gt;

&lt;p&gt;“写个 Hello World 还得套个类？”&lt;br&gt;
Java 25 终于说：不用了。&lt;/p&gt;

&lt;p&gt;🔧 Before&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Java!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡️ After&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Java 25!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 无需类声明&lt;br&gt;
✅ 自带 println / readln&lt;br&gt;
✅ 默认导入常用包（java.util, java.io 等）&lt;/p&gt;

&lt;p&gt;非常适合脚本、小工具、教学 demo。&lt;/p&gt;
&lt;h3&gt;
  
  
  6️⃣ 安全 API 补齐：KDF + PEM 支持 (JEP 510 / 470)
&lt;/h3&gt;

&lt;p&gt;再也不用 BouncyCastle 了。&lt;/p&gt;

&lt;p&gt;🔧 Before&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SecretKeyFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecretKeyFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PBKDF2WithHmacSHA256"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 依赖第三方或手动写 PEM 解析&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚡️ After&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KeyDerivationFunction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HKDF"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;derived&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deriveKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"context-info"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PemEncoded&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key.pem"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ 原生支持 PBKDF2、HKDF&lt;br&gt;
✅ 官方 PEM 解析（再也不用 Apache Commons SSL）&lt;br&gt;
✅ 更安全、更兼容 FIPS&lt;/p&gt;




&lt;h2&gt;
  
  
  🧭 升级建议（20/21 → 25）
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;步骤&lt;/th&gt;
&lt;th&gt;建议动作&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1️⃣&lt;/td&gt;
&lt;td&gt;先在测试环境切 JDK 25&lt;/td&gt;
&lt;td&gt;检查依赖兼容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2️⃣&lt;/td&gt;
&lt;td&gt;对性能敏感模块基准测试&lt;/td&gt;
&lt;td&gt;验证 GC / 启动速度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3️⃣&lt;/td&gt;
&lt;td&gt;尝试 &lt;code&gt;--enable-preview&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;提前熟悉 Pattern Matching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4️⃣&lt;/td&gt;
&lt;td&gt;启用 Compact Headers&lt;/td&gt;
&lt;td&gt;检查内存节省比例&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5️⃣&lt;/td&gt;
&lt;td&gt;集成 JFR 新功能&lt;/td&gt;
&lt;td&gt;改进性能监控体系&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6️⃣&lt;/td&gt;
&lt;td&gt;评估 AOT + Profile 启动&lt;/td&gt;
&lt;td&gt;Serverless 项目推荐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7️⃣&lt;/td&gt;
&lt;td&gt;移除 32 位依赖&lt;/td&gt;
&lt;td&gt;避免启动错误&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  💬 总结：要不要上 Java 25？
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;建议&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🚀 新项目&lt;/td&gt;
&lt;td&gt;直接上 Java 25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🏢 Java 21 LTS 生产项目&lt;/td&gt;
&lt;td&gt;准备迁移&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧓 Java 17 / 8 老项目&lt;/td&gt;
&lt;td&gt;是时候动手了 😅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧠 TL;DR — 最推荐的 5 个特性
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;排名&lt;/th&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🥇&lt;/td&gt;
&lt;td&gt;AOT + Method Profiling&lt;/td&gt;
&lt;td&gt;冷启动提速&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🥈&lt;/td&gt;
&lt;td&gt;Compact Object Headers&lt;/td&gt;
&lt;td&gt;节省内存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🥉&lt;/td&gt;
&lt;td&gt;Scoped Values&lt;/td&gt;
&lt;td&gt;并发安全上下文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#4&lt;/td&gt;
&lt;td&gt;JFR Profiling&lt;/td&gt;
&lt;td&gt;精准监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#5&lt;/td&gt;
&lt;td&gt;Compact Source Files&lt;/td&gt;
&lt;td&gt;轻量脚本体验&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;👉 你升级 Java 25 了吗？&lt;br&gt;
冷启动真的快了吗？你最喜欢哪个新特性呢？&lt;br&gt;
欢迎在评论区聊聊你的实测体验 🙌&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>从“能用”到“好用”：高效运用CloudBees CD/RO 的使用心得</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sun, 22 Jun 2025 17:07:33 +0000</pubDate>
      <link>https://forem.com/andylow/cong-neng-yong-dao-hao-yong-gao-xiao-yun-yong-cloudbees-cdro-de-shi-yong-xin-de-21j6</link>
      <guid>https://forem.com/andylow/cong-neng-yong-dao-hao-yong-gao-xiao-yun-yong-cloudbees-cdro-de-shi-yong-xin-de-21j6</guid>
      <description>&lt;p&gt;在软件交付的世界里，CI/CD 流水线已经不是什么新鲜事。我们用 Jenkins、GitLab CI 或其他工具构建、测试、打包我们的应用。但当交付的规模和复杂度上升时，尤其是在需要协调多个应用、跨多个环境、并涉及严格发布流程的企业场景下，简单的 CI 流水线就显得力不存心了。&lt;/p&gt;

&lt;p&gt;这就是 CloudBees CD/RO (Continuous Delivery / Release Orchestration) 发挥作用的地方。它不仅仅是一个执行脚本的工具，更是一个强大的平台，用于建模、管理和可视化你的整个软件交付流程。&lt;/p&gt;

&lt;p&gt;然而，很多团队仅仅是用它来替代旧的部署脚本，没有真正发挥其潜力。今天，我想分享一些心得，帮助你从“能用” CloudBees CD/RO，迈向“好用”和“高效”。&lt;/p&gt;

&lt;h2&gt;
  
  
  1. 核心概念：像写代码一样思考你的部署
&lt;/h2&gt;

&lt;p&gt;CloudBees CD/RO 的核心是其强大的对象模型。要高效使用它，首先必须理解并接受这个模型。把它想象成部署世界的“面向对象编程”：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application (应用): 这是你要部署的东西。它不是代码库，而是包含了部署逻辑（Components）和流程（Processes）的集合。一个应用可以包含一个后端服务、一个前端UI和一个数据库脚本。&lt;/li&gt;
&lt;li&gt;Environment (环境): 这是你要部署到的地方（如 DEV, QA, PROD）。它不关心“如何部署”，只关心“部署到哪”，并存储该环境特定的配置，如服务器地址、数据库凭证等。&lt;/li&gt;
&lt;li&gt;Process (流程): 这是“如何做”的定义。例如，一个 Deploy 流程可能包含“从 Artifactory 拉取构件”、“停止应用服务器”、“部署文件”、“启动应用服务器”等步骤。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;高效实践的关键在于： 将部署逻辑（Process）与环境配置（Environment）彻底分离。你的部署流程应该是一套代码，无需任何修改就能在所有环境中运行。&lt;/p&gt;

&lt;h2&gt;
  
  
  2. “一切皆代码”：全面拥抱 DSL
&lt;/h2&gt;

&lt;p&gt;如果你还在 UI 上拖拖拽拽来创建流程，请立刻停下来。CloudBees CD/RO 提供了强大的 Groovy/Kotlin DSL（领域特定语言），让你能够以代码的形式定义所有配置。&lt;/p&gt;

&lt;p&gt;为什么必须用 DSL？&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;版本控制: 你可以将你的整个发布流程和应用模型存储在 Git 中，享受版本控制、分支、合并带来的所有好处。&lt;/li&gt;
&lt;li&gt;代码审查: 对发布流程的任何修改都必须通过 Pull Request 和同行评审，极大地提高了变更的可靠性。&lt;/li&gt;
&lt;li&gt;可复用性: 你可以编写通用的 DSL 模块，并在多个项目中共享。&lt;/li&gt;
&lt;li&gt;自动化: 可以通过脚本自动创建和更新成百上千个应用，这在微服务架构中至关重要。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;示例：用 DSL 定义一个简单的应用&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: project/applications/my-web-app.groovy&lt;/span&gt;

&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="s1"&gt;'my-web-app'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;projectName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'My Awesome Project'&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Main web application'&lt;/span&gt;

    &lt;span class="c1"&gt;// 定义一个组件，指向构件仓库&lt;/span&gt;
    &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s1"&gt;'war-file'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;artifactName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'my-app'&lt;/span&gt;
        &lt;span class="n"&gt;artifactVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'$[pipeline.buildNumber]'&lt;/span&gt; &lt;span class="c1"&gt;// 使用运行时参数&lt;/span&gt;
        &lt;span class="n"&gt;retrievalMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'artifact'&lt;/span&gt;
        &lt;span class="n"&gt;artifactType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'REPOSITORY'&lt;/span&gt;
        &lt;span class="n"&gt;repositoryName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'artifactory-prod'&lt;/span&gt; &lt;span class="c1"&gt;// 指向配置好的仓库&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 定义一个部署流程&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="s1"&gt;'deploy'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;formalParameter&lt;/span&gt; &lt;span class="s1"&gt;'target_server'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;required:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="s1"&gt;'entry'&lt;/span&gt;

        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="s1"&gt;'retrieve_artifact'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
            &lt;span class="n"&gt;subprocedure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'retrieve'&lt;/span&gt;
            &lt;span class="n"&gt;subprocedureType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'component'&lt;/span&gt;
            &lt;span class="n"&gt;actualParameter&lt;/span&gt; &lt;span class="s1"&gt;'componentName'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'war-file'&lt;/span&gt;
            &lt;span class="n"&gt;actualParameter&lt;/span&gt; &lt;span class="s1"&gt;'target'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/tmp'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="s1"&gt;'deploy_to_tomcat'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scp /tmp/my-app-$[artifactVersion].war $[/myJob/target_server]:/opt/tomcat/webapps/"&lt;/span&gt;
            &lt;span class="n"&gt;shell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'bash'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;通过 evalDsl 命令，你就可以将这段代码应用到你的 CloudBees CD/RO 服务器上。&lt;/p&gt;

&lt;h2&gt;
  
  
  3. 可重用性是关键：构建模块化的流程
&lt;/h2&gt;

&lt;p&gt;不要在应用流程（Application Process）中编写具体的执行逻辑。相反，你应该创建通用的程序（Procedures），然后在应用流程中调用它们。&lt;/p&gt;

&lt;p&gt;反模式 ❌:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;在 my-web-app 的 deploy 流程中硬编码所有 Tomcat 部署细节。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最佳实践 ✅:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;创建一个名为 Tomcat/Deploy 的通用 Procedure。&lt;/li&gt;
&lt;li&gt;这个 Procedure 接受参数，如 &lt;code&gt;warFilePath&lt;/code&gt;, &lt;code&gt;targetServer&lt;/code&gt;, &lt;code&gt;tomcatManagerUser&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在 my-web-app 的 deploy 流程中，简单地调用这个通用 Procedure，并传入参数。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这样做的好处是显而易见的。当你需要部署另一个 Java Web 应用时，你只需复用 Tomcat/Deploy 这个 Procedure，而无需重写任何逻辑。如果 Tomcat 的部署方式需要更新，你只需要修改这一个地方。&lt;/p&gt;

&lt;p&gt;参数化是你的好朋友:&lt;br&gt;
CloudBees CD/RO 的参数系统非常强大。学会使用 &lt;code&gt;$[propertyName]&lt;/code&gt; 语法来引用属性。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$[formal_parameter_name]&lt;/code&gt;：引用流程的输入参数。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$[credential:credName.userName]&lt;/code&gt;：安全地引用凭证。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[/myEnvironment/server_ip]&lt;/code&gt;：从环境模型中获取属性。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. 编排的力量：从部署到发布
&lt;/h2&gt;

&lt;p&gt;CloudBees CD/RO 的 “RO” (Release Orchestration) 是它的真正亮点。一个发布（Release）不仅仅是部署一个应用，而是协调多个应用、多个团队、自动化测试、手动审批和业务决策的复杂过程。&lt;/p&gt;

&lt;p&gt;利用发布流水线（Release Pipeline）来建模你的价值流：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;阶段 (Stages): 将发布过程分解为逻辑阶段，如 &lt;code&gt;SI&lt;/code&gt;, &lt;code&gt;QA&lt;/code&gt;, &lt;code&gt;PROD&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;闸 (Gates): 在阶段之间设置自动或手动的审批门。例如，只有当自动化测试通过率 &amp;gt; 95% 并且 &lt;code&gt;SI&lt;/code&gt; 经理手动批准后，才能进入 &lt;code&gt;QA&lt;/code&gt; 阶段。&lt;/li&gt;
&lt;li&gt;任务 (Tasks): 在每个阶段内定义具体任务，这些任务可以是并行的，也可以是串行的。

&lt;ul&gt;
&lt;li&gt;部署 backend-service。&lt;/li&gt;
&lt;li&gt;部署 frontend-ui。&lt;/li&gt;
&lt;li&gt;Parallel Process（并行执行）运行集成测试。&lt;/li&gt;
&lt;li&gt;通知 Jira 更新工单状态。&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;通过这种方式，你可以将从代码提交到生产上线的整个路径可视化、自动化和可审计。&lt;/p&gt;

&lt;h2&gt;
  
  
  5. 集成与插件：打造你的 DevOps 工具链
&lt;/h2&gt;

&lt;p&gt;CloudBees CD/RO 不是要取代你所有现有的工具，而是要将它们“粘合”在一起。它拥有一个庞大的插件库，可以轻松与你的 DevOps 生态系统集成：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI 服务器: 用 Jenkins/GitLab CI 做好构建和单元测试，然后触发 CloudBees CD/RO 进行部署和发布。&lt;/li&gt;
&lt;li&gt;源码管理: 与 Git 集成，自动触发流程。&lt;/li&gt;
&lt;li&gt;构件库: 从 Artifactory/Nexus 拉取构件。&lt;/li&gt;
&lt;li&gt;配置管理: 调用 Ansible Playbook 或 Chef Recipe 来配置环境。&lt;/li&gt;
&lt;li&gt;测试工具: 集成 Selenium, JMeter 等进行自动化测试，并根据结果驱动流水线。&lt;/li&gt;
&lt;li&gt;工单系统: 与 Jira/ServiceNow 集成，实现工单状态的自动更新和关联。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  总结
&lt;/h2&gt;

&lt;p&gt;高效使用 CloudBees CD/RO 的核心思想是：把它当作一个开发平台，而不是一个运维工具。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;建模优于脚本: 用其对象模型（应用、环境）来组织你的交付物。&lt;/li&gt;
&lt;li&gt;代码优于点击: 全面拥抱 DSL，将你的交付流程纳入版本控制和代码审查。&lt;/li&gt;
&lt;li&gt;抽象优于具体: 构建可重用的、模块化的 Procedure，而不是在每个应用中重复造轮子。&lt;/li&gt;
&lt;li&gt;编排优于执行: 利用发布流水线来管理端到端的价值流，而不仅仅是单个部署任务。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;将这些原则付诸实践，你的交付流程将不仅仅是自动化，更是变得可靠、可扩展且易于管理。你将从救火队员的角色，转变为交付流程的架构师。&lt;/p&gt;

&lt;p&gt;希望这些技巧对你有用！欢迎在评论区分享你的经验和问题。&lt;/p&gt;

</description>
      <category>devops</category>
    </item>
    <item>
      <title>[每次突破0.1] JavaScript 如何判断属性是否存在</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Thu, 09 Jan 2025 11:01:16 +0000</pubDate>
      <link>https://forem.com/andylow/mei-ci-tu-po-01-javascript-ru-he-pan-duan-shu-xing-shi-fou-chun-zai-190b</link>
      <guid>https://forem.com/andylow/mei-ci-tu-po-01-javascript-ru-he-pan-duan-shu-xing-shi-fou-chun-zai-190b</guid>
      <description>&lt;h2&gt;
  
  
  前言
&lt;/h2&gt;

&lt;p&gt;在 JavaScript 开发中，我们常常需要判断在于一个对象中一个属性是否存在。&lt;br&gt;
由于 JavaScript 是一个比较松散的语言，导致我们很难去做一些比较严格的事。就比如这个问题，“属性是否存在”在 JavaScript 里的定义出现了偏差，到底什么时候是存在，什么是算不存在。这没有对错之分，只是在不同的语境下，不同的开发需求下，“存在”的含义是不一样的。&lt;br&gt;
这里我就说一说比较常用的5种判断方式，和它们存在的问题。&lt;/p&gt;
&lt;h2&gt;
  
  
  方法 1：布尔（Boolean）判定
&lt;/h2&gt;

&lt;p&gt;这里举个例子：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 不存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;先说说这种方式的缺陷吧&lt;br&gt;
如果：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Baby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 不存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这种情况下，&lt;code&gt;age&lt;/code&gt;应是 “存在”，但是会被判断成“不存在”。&lt;/p&gt;

&lt;p&gt;那么这种方式是不是就不能用呢？&lt;br&gt;
这就要根据业务的开发需求了。&lt;br&gt;
如果你知道在你的业务开发需求里，这个属性是不可能为&lt;code&gt;0&lt;/code&gt;，空字符串啊，&lt;code&gt;NaN&lt;/code&gt;啊，&lt;code&gt;undefined&lt;/code&gt;之类的，那么这个判定还是可行的。&lt;br&gt;
如果你放在更加严格的环境，那么这个方式就有缺陷的。&lt;/p&gt;
&lt;h2&gt;
  
  
  方法 2: 可选链 &lt;code&gt;(?.)&lt;/code&gt; 和 &lt;code&gt;undefined&lt;/code&gt; 检查
&lt;/h2&gt;

&lt;p&gt;还是先举例：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 不存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这个对比的逻辑就是，在JS语言里，一个不存在的值就是&lt;code&gt;undefined&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;但是在一个对象里，也可能出现的这种情况：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;像这种情况，那么&lt;code&gt;age&lt;/code&gt;这个属性应该是“存在”呢，还是“不存在”？&lt;/p&gt;

&lt;p&gt;这也就不好说了，还是要看你的具体的需求环境。&lt;/p&gt;

&lt;h2&gt;
  
  
  方法 3: 查找&lt;code&gt;Object.keys()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;如果说，我就要知道一个对象里有没有一个属性&lt;code&gt;age&lt;/code&gt;，我不管它的值是什么。&lt;/p&gt;

&lt;p&gt;我们就可以用这个方式：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;使用&lt;code&gt;Object.keys()&lt;/code&gt;可以得到自身的可枚举属性名来进行判断。&lt;/p&gt;

&lt;p&gt;这里有两个关键词，一个是“自身的”（own），一个是“可枚举”（enumerable）。&lt;/p&gt;

&lt;h3&gt;
  
  
  首先说，什么是“自身的”
&lt;/h3&gt;

&lt;p&gt;比方说这里有一个对象，给对象加一个属性&lt;code&gt;name&lt;/code&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// `name` 就是 obj 自身的属性&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [ 'name' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;那么什么不是自身的属性呢？这里就要扯到“原型”了。一个对象是有原型，在原型上加的属性就不是“自身的”属性了。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;human&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Andy&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// human&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [ 'name' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这个例子，你怎么判断&lt;code&gt;type&lt;/code&gt;是不是&lt;code&gt;obj&lt;/code&gt;的属性呢？这就不好说了对吧，你可以说是，也可以说不是。这就是语言宽松环境带来的问题。&lt;/p&gt;

&lt;p&gt;但你需要知道的是，在这种情况下，&lt;code&gt;Object.keys()&lt;/code&gt;是拿不到原型上的属性。因为它只能读取“自身的”属性。&lt;/p&gt;

&lt;h3&gt;
  
  
  第二个是，“可枚举”
&lt;/h3&gt;

&lt;p&gt;这里就要提到属性描述符了，我很多同事都不知道，在JS语言里，在一个对象里，每个属性都有一个描述符的。&lt;br&gt;
怎么读取呢？我们打印看吧：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOwnPropertyDescriptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// { value: 'Andy', writable: true, enumerable: true, configurable: true }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;你会发现，这个描述符其实也是一个对象，它描述了这个属性的一些信息，比如说值（value），可重写（writable），还有这个（&lt;code&gt;enumerable&lt;/code&gt;）&lt;strong&gt;可枚举&lt;/strong&gt; ...&lt;/p&gt;

&lt;p&gt;这个&lt;code&gt;enumerable&lt;/code&gt;定义了那个属性，是否可以被枚举，比如&lt;code&gt;for...in&lt;/code&gt;循环时候可以读取这个属性，&lt;code&gt;Object.keys()&lt;/code&gt;也是如此。&lt;/p&gt;

&lt;p&gt;如果我重新定义一个属性为不可枚举的，那么&lt;code&gt;Object.keys()&lt;/code&gt;就读取不到这个属性了。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enumerable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 21&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [ 'name' ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这里就涉及到了&lt;code&gt;属性描述符&lt;/code&gt;的相关知识了，这个是原生JS语言非常重要的知识，而我发现很多我认识的前端程序员都缺乏这种原生JS的知识。&lt;/p&gt;

&lt;p&gt;那么如果说你要判断的属性要求只要是自身的属性，不管可不可枚举呢？那么就不能用&lt;code&gt;Object.keys()&lt;/code&gt;了。可以用接下来的方法。&lt;/p&gt;

&lt;h2&gt;
  
  
  方法 4：使用 &lt;code&gt;Object.hasOwn()&lt;/code&gt; 或 &lt;code&gt;hasOwnProperty()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Object.hasOwn()&lt;/code&gt; 和 &lt;code&gt;hasOwnProperty()&lt;/code&gt; 有什么区别呢？&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Object.hasOwn()&lt;/code&gt; 是 ES2022 加入的方法，用于检查对象是否自身具有某个属性，用于替代 &lt;code&gt;hasOwnProperty&lt;/code&gt; 的促优处理。由于这是后来加入的方法，兼容性还是个问题，如果只考虑新版本的浏览器还是可以用的。&lt;/p&gt;

&lt;p&gt;这两个方法判断的是 &lt;strong&gt;“自身的”&lt;/strong&gt; 属性名，所以不管是不是可枚举，都能被读取。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enumerable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;// 不可被枚举&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;为什么要用&lt;code&gt;Object.hasOwn()&lt;/code&gt;，由于对象的&lt;code&gt;hasOwnProperty()&lt;/code&gt;有可能被修改：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 不存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;如果你要判断的属性名，不要求是自身的和可枚举，原型也行，那么就要用最后一个方法了。&lt;/p&gt;

&lt;h2&gt;
  
  
  方法 5: &lt;code&gt;in&lt;/code&gt; 运算符
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;in&lt;/code&gt; 运算符用于判断一个属性是否存在于对象或其原型链中。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Andy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 存在&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;不存在&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 不存在&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  总结
&lt;/h2&gt;

&lt;p&gt;这些方法种，没有说那个方法是正确的，那个错误的。并不是每个场景都适合同一种方法，根据情况遵守最佳实践，以增强代码可读性和安全性。&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>[每次突破0.1] Javascript中的==运算和转换</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Mon, 27 Nov 2023 05:25:07 +0000</pubDate>
      <link>https://forem.com/andylow/mei-ci-tu-po-01-javascriptzhong-de-yun-suan-he-zhuan-huan-1800</link>
      <guid>https://forem.com/andylow/mei-ci-tu-po-01-javascriptzhong-de-yun-suan-he-zhuan-huan-1800</guid>
      <description>&lt;p&gt;在工作生涯中，我发现还是有很多很多Frontend Developer（前端程序猿）都不是很清楚Javascript(JS)里有一些基础的知识。这期我们就说说JS里的&lt;code&gt;==&lt;/code&gt;运输和转换规则。&lt;br&gt;
看起来很笨对吧，&lt;code&gt;==&lt;/code&gt;运算符不就是检查其两个操作数是否相等，返回一个布尔值(boolean)结果嘛。&lt;/p&gt;

&lt;p&gt;来我们看看下面这个题例：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;恭喜你突破0.1了。&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;现在我要你把上面的if statement成立，从而打印出&lt;code&gt;恭喜你突破0.1了。&lt;/code&gt;，你能办到吗？&lt;/p&gt;

&lt;p&gt;要解这道题你就要彻底的了解在JS里的&lt;code&gt;==&lt;/code&gt;运输和转换规则。&lt;br&gt;
在&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Equality" rel="noopener noreferrer"&gt;mdn文档&lt;/a&gt;有详细说明了规则，我知道很多程序猿都是很懒惰读文档，这里我就做点简介好让你跟容易理解。&lt;/p&gt;

&lt;p&gt;我大致总结了一下，按以下规则步骤从&lt;code&gt;1.&lt;/code&gt;到&lt;code&gt;5.&lt;/code&gt;依序做比较，直到得到确切的结果为止：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;两边相同的类型做比较，就比较值。&lt;/li&gt;
&lt;li&gt;其中一个是&lt;code&gt;NaN&lt;/code&gt;，直接返回&lt;code&gt;false&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;null&lt;/code&gt;和&lt;code&gt;undefined&lt;/code&gt;只有与自身，或互相比较才会返回&lt;code&gt;true&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;两边不同的类型但都是基础类型，转换成数字重复步骤&lt;code&gt;1.&lt;/code&gt;比较。&lt;/li&gt;
&lt;li&gt;一边是原始类型，一边是对象，把对象转换成基础类型后重复步骤&lt;code&gt;1.比较&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;很简明对吧，现在我们就一步一步看。&lt;/p&gt;

&lt;p&gt;第一步: &lt;strong&gt;两边相同的类型做比较，就比较值。&lt;/strong&gt;&lt;br&gt;
这个很好理解吧，应该不用多解释。&lt;br&gt;
就是&lt;code&gt;1 == 1&lt;/code&gt;是&lt;code&gt;true&lt;/code&gt;，&lt;code&gt;"andy" == "cooker"&lt;/code&gt;是&lt;code&gt;false&lt;/code&gt;。&lt;br&gt;
这里有一点要注意以下，如果两边是对象，比较值是怎样呢？在JS里，变量里存的是对象的地址。这里比较值的意思比较两个变量的地址值是不是一样。&lt;/p&gt;

&lt;p&gt;第二步：&lt;strong&gt;其中一个是&lt;code&gt;NaN&lt;/code&gt;，直接返回&lt;code&gt;false&lt;/code&gt;。&lt;/strong&gt;&lt;br&gt;
这个也很好理解，就一看到&lt;code&gt;NaN&lt;/code&gt;就直接返回&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;第三步：&lt;strong&gt;&lt;code&gt;null&lt;/code&gt;和&lt;code&gt;undefined&lt;/code&gt;只有与自身，或互相比较才会返回&lt;code&gt;true&lt;/code&gt;。&lt;/strong&gt;&lt;br&gt;
这个我就直接举例吧：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;第四步：&lt;strong&gt;两边不同的类型但都是基础类型，转换成数字重复步骤&lt;code&gt;1.&lt;/code&gt;比较。&lt;/strong&gt;&lt;br&gt;
如果两边类型不同又是基础类型，比如&lt;code&gt;1 == true&lt;/code&gt;，&lt;code&gt;1&lt;/code&gt;是&lt;code&gt;Number&lt;/code&gt;，&lt;code&gt;true&lt;/code&gt;是&lt;code&gt;Boolean&lt;/code&gt;就把，true转为&lt;code&gt;Number&lt;/code&gt;进行比较。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// 转为Number, 是1&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// 就是true&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// 转为Number, 是NaN&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="c1"&gt;// 就是false&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// 转为Number, 是2&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c1"&gt;// 就是true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;第五步：&lt;strong&gt;一边是原始类型，一边是对象，把对象转换成基础类型后重复步骤&lt;code&gt;1.比较&lt;/code&gt;。&lt;/strong&gt;&lt;br&gt;
这个的关键在如何把对象转换成基础类型，这里有3个步骤：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;如果对象有&lt;code&gt;@@toPrimitive&lt;/code&gt;方法，就调用做比较。如果方法返回不是基础类型，抛出异常。&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 如果对象有@@toPrimitive方法，就会被调用&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPrimitive&lt;/span&gt;&lt;span class="p"&gt;](){&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;调用&lt;code&gt;valueOf&lt;/code&gt;方法做比较，如果返回值不是基础类型，继续下一步。在JS里，所有对象默认都有&lt;code&gt;valueOf&lt;/code&gt;方法，那么这个方法返回的是什么？默认情况下是返回对象本身。这个&lt;code&gt;valueOf&lt;/code&gt;方法是可以自行更改的：&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 更改成返回1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;调用&lt;code&gt;toString&lt;/code&gt;方法作比较，如果方法返回不是基础类型，抛出异常。&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;知道了第五步的规则逻辑后，我们再来接这个题是不是容易很多了。&lt;br&gt;
我们再看会这个题：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;我们就只要确保&lt;code&gt;a&lt;/code&gt;能再做比较时依序返回&lt;code&gt;1&lt;/code&gt;,&lt;code&gt;2&lt;/code&gt;和&lt;code&gt;3&lt;/code&gt;就可以了，那么我们可以用任何一个&lt;code&gt;@@toPrimitive&lt;/code&gt;，&lt;code&gt;valueOf&lt;/code&gt; 或 &lt;code&gt;toString&lt;/code&gt; 来完成。&lt;br&gt;
这里我就用valueOf来做演示：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;恭喜你突破0.1了。&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;去运行看看吧。&lt;/p&gt;

&lt;p&gt;其实这个题并不是那么重要，关键是你得理解JS的基础，在JS里等号是如何运算的。&lt;br&gt;
Happy Coding.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>[每次突破0.1] ES2023中数组的复制更改方法</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sun, 24 Sep 2023 08:03:32 +0000</pubDate>
      <link>https://forem.com/andylow/mei-ci-jin-bu-01-es2023zhong-shu-zu-de-fu-zhi-geng-gai-fang-fa-476j</link>
      <guid>https://forem.com/andylow/mei-ci-jin-bu-01-es2023zhong-shu-zu-de-fu-zhi-geng-gai-fang-fa-476j</guid>
      <description>&lt;p&gt;过去，JS数组(Array)的方法都是对原数组内容做更改的，其中包过 &lt;code&gt;splice()&lt;/code&gt;, &lt;code&gt;sort()&lt;/code&gt; 和 &lt;code&gt;reverse()&lt;/code&gt;&lt;br&gt;
比如：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [2, 5, 6, 7]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这对一些纯函数编程环境有点不友好，比方说&lt;code&gt;React&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;现在&lt;code&gt;ES2023&lt;/code&gt;加入了几个通过复制来更改数组的方法，分别是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;toSorted(comporeFn)&lt;/code&gt; : 返回一个新的已排序数组&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toReversed()&lt;/code&gt;：返回一个新的逆序数组&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toSplice(start, count, ...items)&lt;/code&gt;：在给定的索引处删除和/或替换了一些元素，返回一个新的数组&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;with(index, value)&lt;/code&gt;：在指定索引处替换上新的值，返回一个新的数组&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上面这4个新的方法都是不会对原数组做更改的，而是先进行复制在给予操作再返回已复制的新数组。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortedArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSorted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [5, 6, 2, 7]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortedArr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// [2, 5, 6, 7]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;这推广函数式编程(Functional Programing)原则并增强代码可预测性。&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>如何用Windows下的Docker Desktop Kubernetes部署ForgeOps 7.2来实现本地开发</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Thu, 25 May 2023 12:32:05 +0000</pubDate>
      <link>https://forem.com/andylow/ru-he-yong-windowsxia-de-docker-desktop-kubernetesbu-shu-forgeops-72lai-shi-xian-ben-di-kai-fa-odc</link>
      <guid>https://forem.com/andylow/ru-he-yong-windowsxia-de-docker-desktop-kubernetesbu-shu-forgeops-72lai-shi-xian-ben-di-kai-fa-odc</guid>
      <description>&lt;h1&gt;
  
  
  前言
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://backstage.forgerock.com/docs/forgeops/7.2/start/start-here.html" rel="noopener noreferrer"&gt;ForgeRock官方&lt;/a&gt;提供了一个DevOps方案(&lt;code&gt;ForgeOps&lt;/code&gt;)用于展示如何部署ForgeRock Identity Platform在Kubernetes里。&lt;/p&gt;

&lt;p&gt;很遗憾的在官方CDK文档并没有教在Windows里的&lt;code&gt;Docker Desktop Kubernetes&lt;/code&gt;或&lt;code&gt;minikube&lt;/code&gt;部署ForgeOps。官方给的方案是运行一个Linux虚拟机，比如使用Hyper-V, VMWare Player 或 VMWare Workstation运行Ubuntu，然后在Linux虚拟机里使用&lt;code&gt;minikube&lt;/code&gt;来部署ForgeOps。&lt;/p&gt;

&lt;p&gt;我个人认为为了实现本地开发而运行一个虚拟机实在是费资源。既然ForgeOps是展示在Kurbenetes上运行的，原理上无论在什么操作系统，只要我能部署一个Kubernetes cluster，我就应该能部署ForgeOps给的配置。&lt;/p&gt;

&lt;p&gt;这里我们就尝试在Windows下的Docker Desktop Kubernetes部署ForgeOps。&lt;/p&gt;

&lt;h1&gt;
  
  
  安装需要的软件
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/get-started/#" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kustomize/releases" rel="noopener noreferrer"&gt;kustomize 5.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skaffold.dev/docs/install/#standalone-binary" rel="noopener noreferrer"&gt;skaffold 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/helm/helm/releases" rel="noopener noreferrer"&gt;helm 3.12&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dos2unix.sourceforge.io/" rel="noopener noreferrer"&gt;dos2unix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果你比较熟悉Kubernetes，其他一些小工具比如&lt;code&gt;kubectx&lt;/code&gt;和&lt;code&gt;kubens&lt;/code&gt;可以选择性安装。这些小工具可以提高工作效率，在这个部署中不是必要工具。&lt;/p&gt;

&lt;h1&gt;
  
  
  安装Docker Desktop并开启Kubernetes功能
&lt;/h1&gt;

&lt;p&gt;安装我想应该非常简单，就不必我一步步指吧。在安装过程中会有一个选项询问是否要开启Kubernetes功能，只需打勾就好了。&lt;br&gt;
如何你在安装中错过了，或早已安装了Docker Desktop的，就去设置目录开启Kubernetes功能就好了。&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu77abf7ihnput0xvp6a3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu77abf7ihnput0xvp6a3.jpg" alt=" " width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  下载ForgeOps 7.2 Github源码
&lt;/h1&gt;

&lt;p&gt;这里要注意每个版本的部署方式都有些许不同，这里我使用的是&lt;a href="https://github.com/ForgeRock/forgeops/tree/release/7.2.0" rel="noopener noreferrer"&gt;&lt;code&gt;release/7.2.0&lt;/code&gt;&lt;/a&gt;版本。但部署原理都是一样的，只要你掌握的原理，你就可以跟着不同版本的需要做些改动来完成部署。&lt;/p&gt;

&lt;p&gt;如果你有用Github Desktop，只需在UI上点几个button就可以下载了。&lt;br&gt;
这里我用git来下载源码：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/ForgeRock/forgeops.git
cd forgeops
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  处理sh文件EOL问题
&lt;/h1&gt;

&lt;p&gt;我在创建docker image后发现所有的docker image都运行不了，原因是forgerock的base image是使用Linux核的，而&lt;code&gt;forgeops&lt;/code&gt;的&lt;code&gt;.sh&lt;/code&gt;源文件是使用&lt;code&gt;CRLF&lt;/code&gt;的，我有点搞不明白为什么。&lt;/p&gt;

&lt;p&gt;所以我们必须先吧所有的&lt;code&gt;.sh&lt;/code&gt;源文件从&lt;code&gt;CRLF&lt;/code&gt;转去Linux能解读的&lt;code&gt;LF&lt;/code&gt;。当然一个一个文件去修改实在太耗时了，这里我们就需要用到&lt;code&gt;dos2unix&lt;/code&gt;这个小工具来帮我们批量处理了。&lt;/p&gt;

&lt;p&gt;我个人对&lt;code&gt;bash&lt;/code&gt;比较熟悉，就使用&lt;code&gt;git-bash&lt;/code&gt;来完成，如果你比较熟悉&lt;code&gt;PowerShell&lt;/code&gt;，也可以用&lt;code&gt;PowerShell&lt;/code&gt;来完成：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find . -name "*.sh" -type f -exec dos2unix {} \;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  更改imagePullPolicy
&lt;/h1&gt;

&lt;p&gt;我们将使用&lt;code&gt;forgeops&lt;/code&gt;提供的skaffold yaml来进行部署，这个skaffold包括了创建custom docker image，并用custom docker image进行部署。&lt;/p&gt;

&lt;p&gt;然而，&lt;code&gt;forgeops&lt;/code&gt;提供的kubernetes部署yaml都是用&lt;code&gt;imagePullPolicy: Always&lt;/code&gt;，如果你部署在本地的Kubernetes，它会一直尝试从互联网下载image，而导致&lt;code&gt;ErrImgPull&lt;/code&gt; image不能被下载。&lt;/p&gt;

&lt;p&gt;这里我们就需要把所有的&lt;code&gt;imagePullPolicy&lt;/code&gt;从&lt;code&gt;Always&lt;/code&gt;改去&lt;code&gt;IfNotPresent&lt;/code&gt;或&lt;code&gt;Never&lt;/code&gt;，这样本地Kubernetes就会优先从本地查找image。&lt;/p&gt;

&lt;p&gt;批量更改的方法很多，你就用你最适应的方法去改吧。我的方法是使用&lt;code&gt;VS Code&lt;/code&gt;打开&lt;code&gt;forgeops&lt;/code&gt;文件夹，然后使用Search &amp;amp; Replace功能，把&lt;code&gt;imagePullPolicy: Always&lt;/code&gt;批量replace成&lt;code&gt;imagePullPolicy: IfNotPresent&lt;/code&gt;。&lt;/p&gt;

&lt;h1&gt;
  
  
  检查Kubernetes
&lt;/h1&gt;

&lt;p&gt;源文件的准备工作到这里就好了，现在要检查你的Kubernetes和安装的CLI能否运行。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;运行以上这个command你应该会得到&lt;code&gt;docker-desktop&lt;/code&gt;，然后status应该要是&lt;code&gt;Ready&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;现在就可以创建新的namespace了，这个namespace主要是用来分开ForgeRock的应用以方便我们查看。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create ns forgerock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;如果你有用&lt;code&gt;kubens&lt;/code&gt;，也可以把&lt;code&gt;forgerock&lt;/code&gt;设置成默认namespace：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubens forgerock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;然后检查所有所需的工具能正常运行&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm
skaffold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  部署secret agent和cert manager
&lt;/h1&gt;

&lt;p&gt;根据&lt;a href="https://backstage.forgerock.com/docs/forgeops/7.2/cdk/architecture.html" rel="noopener noreferrer"&gt;官方CDK Architecture文档&lt;/a&gt;，ForgeRock Identity Platform还需要&lt;code&gt;secret agent&lt;/code&gt;，&lt;code&gt;cert manager&lt;/code&gt; 和 &lt;code&gt;DS operator&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DS Operator&lt;/code&gt;我就不部署了，应该这个主要是用于backup和restore DS的资料，本地开发应该没用。如果你有需要也可以跟着&lt;code&gt;secret agent&lt;/code&gt;或&lt;code&gt;cert manager&lt;/code&gt;的部署方法。&lt;/p&gt;

&lt;h2&gt;
  
  
  部署secret agent
&lt;/h2&gt;

&lt;p&gt;ForgeRock官方提供了secret agent的Kubernetes yaml部署文件，所以这一步非常简单。只需运行以下command就可以了：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://github.com/ForgeRock/secret-agent/releases/download/v1.1.8/secret-agent.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;运行后就可以检查用&lt;code&gt;kubectl get ns&lt;/code&gt; command检查&lt;code&gt;secret-agent-system&lt;/code&gt; namespace是否已经创建。并检查&lt;code&gt;secret-agent-controller-manager&lt;/code&gt;是 READY &lt;code&gt;1/1&lt;/code&gt; 的状体:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployment -n secret-agent-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  部署cert manager
&lt;/h1&gt;

&lt;p&gt;ForgeOps是用开源的&lt;a href="https://github.com/cert-manager/cert-manager" rel="noopener noreferrer"&gt;&lt;code&gt;cert-manager.io&lt;/code&gt;&lt;/a&gt;来管理证书。&lt;code&gt;forgeops&lt;/code&gt;也提供一个bash script方便使用helm来部署&lt;code&gt;cert-manager&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;这里我们可以利用&lt;code&gt;git-bash&lt;/code&gt;来运行这个bash script：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./bin/certmanager-deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;运行完成后也是检查下&lt;code&gt;cert-manager&lt;/code&gt;的status：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployment -n cert-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  创建secrets
&lt;/h1&gt;

&lt;p&gt;ForgeRock Identity Platform里用到大量的secrets，如果要一个一个创建不但麻烦费时也很复杂。这里&lt;code&gt;forgeops&lt;/code&gt;以提供的Kustomize部署文件利用secret agent来创建需要的secrets：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -k .\kustomize\base\secrets -n forgerock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;部署完成后，用以下command检查是不是又一堆&lt;code&gt;ds-&lt;/code&gt;，&lt;code&gt;am-&lt;/code&gt;，&lt;code&gt;idm-&lt;/code&gt;的secrets以创建。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get secrets -n forgerock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  部署ForgeRock
&lt;/h1&gt;

&lt;p&gt;现在我们可以开始部署ForgeRock Identity Platform了，这一步非常简单，只需运行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;skaffold dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  部署Ingress Controller
&lt;/h1&gt;

&lt;p&gt;完成以上的部署，接下来就是要浏览&lt;code&gt;https://default.iam.example.com/am&lt;/code&gt;了。但是应该怎样浏览呢？&lt;/p&gt;

&lt;p&gt;这里我们就需要Ingress Controller了，我选择了Ngix的Ingress Controller，你可以根据自己需求选择。&lt;/p&gt;

&lt;p&gt;这里我们就用官方的部署文件吧：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.1/deploy/static/provider/cloud/deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;部署完成后就只需port-forward去Ingress Controller就可以了&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 80:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  最后一步，设置host文件
&lt;/h1&gt;

&lt;p&gt;想必程序员们对host文件不陌生吧，我们就只需把&lt;code&gt;default.iam.example.com&lt;/code&gt;设成本地解析就可以了。&lt;br&gt;
简单的在&lt;code&gt;C:\Windows\System32\drivers\etc\hosts&lt;/code&gt;文件加一行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1 default.iam.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;现在你就可以浏览 &lt;a href="https://default.iam.example.com/am" rel="noopener noreferrer"&gt;https://default.iam.example.com/am&lt;/a&gt; 了。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn97l5i3sc3ystdaged4j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn97l5i3sc3ystdaged4j.jpg" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;还差最后一样都东西就是登录用户和密码，哈哈。这里我就不明示怎样创建用户了，你们就琢磨琢磨，如果真的不行就在评论区留言，我会在评论区教你。&lt;/p&gt;

&lt;h1&gt;
  
  
  总结
&lt;/h1&gt;

&lt;p&gt;经过我不断的尝试，终于找到一个可以部署ForgeOps让在Windows也能实现本地开发。这里就分享给大家，最后ForgeRock需要的内存挺多的，建议大家预留最少9GB的内存来运行。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>JDK 8 -&gt; 20 最重用的新增特性</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sun, 09 Apr 2023 07:06:11 +0000</pubDate>
      <link>https://forem.com/andylow/jdk-8-20-zui-zhong-yong-de-xin-zeng-te-xing-36jc</link>
      <guid>https://forem.com/andylow/jdk-8-20-zui-zhong-yong-de-xin-zeng-te-xing-36jc</guid>
      <description>&lt;h2&gt;
  
  
  序
&lt;/h2&gt;

&lt;p&gt;Java 8 早已经在 2014 年发布，毫无疑问 Java 8 对 Java 来说绝对算得上是一次重大版本更新，它包含了十多项语言、库、工具、JVM 等方面的十多项新特性。比如提供了语言级的匿名函数，也就是被官方称为 &lt;a href="https://dev.to/andylow/java-8-lambda-5214"&gt;Lambda 的表达式语法&lt;/a&gt;，比如函数式接口，方法引用，重复注解。再比如 Optional 预防空指针，Stearm 流式作，LocalDateTime 时间操作等等。&lt;/p&gt;

&lt;p&gt;如今，在2023年3月21日，Java 20已正式发布，但不是一个长期支持版本（LTS)。目前的长期支持版是Java 17。在这篇章LTS不是重点，我们把中重点放在从Java 8发展到现在的Java 20到底新增什么重要的特性。这里，我只总结了&lt;strong&gt;11个&lt;/strong&gt;我个人认为重要的标准新特性（不是预览的），只要你是用Java 17，这些新特性你都能用得上。&lt;/p&gt;

&lt;h3&gt;
  
  
  Table Of Contents &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
JDK 9

&lt;ul&gt;
&lt;li&gt;集合工厂方法&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 10

&lt;ul&gt;
&lt;li&gt;局部类型推断&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 14

&lt;ul&gt;
&lt;li&gt;Switch 表达式&lt;/li&gt;
&lt;li&gt;更清晰的NPE&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 15

&lt;ul&gt;
&lt;li&gt;文本块&lt;/li&gt;
&lt;li&gt;ZGC: 可扩展低延迟垃圾收集器&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 16

&lt;ul&gt;
&lt;li&gt;instanceof 模式匹配&lt;/li&gt;
&lt;li&gt;Record 类&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 17

&lt;ul&gt;
&lt;li&gt;密封类&lt;/li&gt;
&lt;li&gt;Switch 模式匹配 (预览)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

JDK 18

&lt;ul&gt;
&lt;li&gt;默认 UTF-8 字符编码&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;总结&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  JDK 9 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  集合工厂方法 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/269" rel="noopener noreferrer"&gt;JEPS-269 : Convenience Factory Methods for Collections&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 JDK 9 中为集合的创建增加了静态工厂创建方式（Collection Factories）。这个集合工厂可以只用一行代码来创建一些较小的集合，目前支持&lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;和&lt;code&gt;Map&lt;/code&gt;。这个方法只适合用于创建只读集合（Immutable Collection），里面的对象不可改变。&lt;/p&gt;

&lt;p&gt;在 JDK 8 中:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mySet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;mySet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"yun"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mySet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"yyx"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mySet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"andy"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mySet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unmodifiableSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mySet&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;而在 JDK 9 中只需：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set&amp;lt;String&amp;gt; mySet = Set.of("yun", "yyx", "andy");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 10 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  局部类型推断 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/286" rel="noopener noreferrer"&gt;JEPS-286 : Local-Variable Type Inference&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如何你是 Javascript 程序员，你一定熟悉&lt;code&gt;var&lt;/code&gt;这个syntax。在 JDK 10 也加入&lt;code&gt;var&lt;/code&gt;来实现自动推断数据类型。但这个还是和 Javascript 的&lt;code&gt;var&lt;/code&gt;很不一样的。在 Java 里只是一个新的语法，它在编译时就把&lt;code&gt;var&lt;/code&gt;根据转化成具体的数据类型了。&lt;/p&gt;

&lt;p&gt;传统写法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://dev.to/"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="no"&gt;URL&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;URLConnection&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openConnection&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JDK 10简化版：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://dev.to/"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openConnection&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;虽然&lt;code&gt;var&lt;/code&gt;简化了 Java 代码，但也必须知道&lt;code&gt;var&lt;/code&gt;的使用场景和避免危险使用。比如以下的写法是有后患的：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 这里默认是int，而不是short或byte&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 这里默认是ArrayList&amp;lt;Object&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenJDK官方也给出了&lt;a href="https://openjdk.org/projects/amber/guides/lvti-style-guide" rel="noopener noreferrer"&gt;LVTI的使用指南&lt;/a&gt;，往后我再整理一篇简介的文章。&lt;/p&gt;

&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 14 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Switch 表达式 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/361" rel="noopener noreferrer"&gt;JEPS-361: Switch Expression&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Switch 表达式早在 JDK 12 就推出了，而正式标准化是在 JDK 14。主要是加入了&lt;code&gt;-&amp;gt;&lt;/code&gt;和&lt;code&gt;yeild&lt;/code&gt;语法在&lt;code&gt;switch&lt;/code&gt;语法里。&lt;/p&gt;

&lt;p&gt;传统写法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;season&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;MAR:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;APR:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;MAY:&lt;/span&gt;
        &lt;span class="n"&gt;season&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"spring"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;JUN:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;JUL:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;AUG:&lt;/span&gt;
        &lt;span class="n"&gt;season&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"summer"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;SEP:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;OCT:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;NOV:&lt;/span&gt;
        &lt;span class="n"&gt;season&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"autumn"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;DEC:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;JAN:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;FEB:&lt;/span&gt;
        &lt;span class="n"&gt;season&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"winter"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Not a month: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;season&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switch 表达式简化后：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;MAR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;APR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MAY&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"spring"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;JUN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JUL&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AUG&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"summer"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;SEP&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;OCT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NOV&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"autumn"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;DEC&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JAN&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FEB&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"winter"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;

&lt;h4&gt;
  
  
  更清晰的NPE &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/358" rel="noopener noreferrer"&gt;JEPS-358: Helpful NPE&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 JDK 14 之前，&lt;code&gt;NullPointerException&lt;/code&gt;(NPE)只汇报哪一行代码导致空指针，在有多个表达式的代码里是很难知道那个对象为&lt;code&gt;null&lt;/code&gt;。在 JDK 14，这个 exception 已加入清晰的 message 告诉你哪个对象是&lt;code&gt;null&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;比方这行代码，如果&lt;code&gt;b&lt;/code&gt;是&lt;code&gt;null&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;j&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在 JDK 14 之前的报错是这样的：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main" java.lang.NullPointerException
    at App.main(App.java:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;而 JDK 14 清晰的表明：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main" java.lang.NullPointerException: 
    Cannot read field "j" because "b" is null
    at App.main(App.java:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 15 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  文本块 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/378" rel="noopener noreferrer"&gt;JEPS-378: Text Blocks&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 Java 里长文本字符串连接一直以来都是一个恶梦，因为不仅写起来麻烦，读起来也很恶心。终于在 JDK 15 加入了文本块。直接来看看对比把。&lt;/p&gt;

&lt;p&gt;之前的字符串连接：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"\"name\": \""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\",\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="s"&gt;"\"nickname\": \""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nickName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\"\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
    &lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JDK 15 的文本块：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""
        {
            "name": "%s",
            "nickname": "%s"
        }
        """&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nickName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;

&lt;h4&gt;
  
  
  ZGC: 可扩展低延迟垃圾收集器 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/377" rel="noopener noreferrer"&gt;JEPS-377: A Scalable Low-Latency Garbage Collector&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 JDK 15，ZGC 垃圾收集器正式发布。根据 SPEC (Standard Performance Evaluation Corporation) 的测试，ZGC 拥有着不俗的性能：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3idn5pqet1ypfroyjg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3idn5pqet1ypfroyjg1.png" alt=" " width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;而且还在 JDK 版本更新中不断优化：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j6quf2n978fh98aks35.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j6quf2n978fh98aks35.jpg" alt=" " width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那么 ZGC 那么好，为什么没有取代 G1GC 作为默认的 GC 呢？我个人认为有几个原因。GC 在 Java 里是一个很深学问，目前没有一个方案可以解决全部的使用场景。而 G1GC 已被广泛使用，表现也比较稳定，如果突然默认改了去用 ZGC 可能会出现不可预算的问题而导致大量不太了解 GC 的 Java 用户陷入困境。也有很多 Java 用户做 GC 调试只在默认 GC 上做调试，如果冒昧的升级用了不同的 GC，不读升级文档的 Java 用户酱不懂发生了什么事导致调试失效。&lt;/p&gt;

&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 16 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  instanceof 模式匹配 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/394" rel="noopener noreferrer"&gt;JEPS-394: Pattern Matching for instanceof&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这个 Pattern Matching 的升级略为直接，就是简化了&lt;code&gt;instanceof&lt;/code&gt;使用场景。这里直接举例：&lt;/p&gt;

&lt;p&gt;传统写法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; &lt;span class="c1"&gt;// 1) 检查 obj 的类&lt;/span&gt;
    &lt;span class="c1"&gt;// 2) declare 新的 String 变量 str，3) 并 cast obj 去 String 类&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 

    &lt;span class="c1"&gt;// 使用 str &lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;上面的 3 步现在可以简化成 1 步了：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// 直接可以使用 str &lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;

&lt;h4&gt;
  
  
  Record 类 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/395" rel="noopener noreferrer"&gt;JEPS-395: Records&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;JDK 16 加入了&lt;code&gt;record&lt;/code&gt;类。我相信大部分 Java 用户都用过&lt;code&gt;Lombok&lt;/code&gt;工具库吧，这个&lt;code&gt;record&lt;/code&gt;类和&lt;code&gt;Lombok&lt;/code&gt;的&lt;code&gt;@Data&lt;/code&gt;类似，它会自动编译出&lt;code&gt;hashcode&lt;/code&gt;、&lt;code&gt;equals&lt;/code&gt;、&lt;code&gt;toString&lt;/code&gt; 等方法。但&lt;code&gt;record&lt;/code&gt;是一个&lt;code&gt;final class&lt;/code&gt;，同时所有的属性都是&lt;code&gt;final&lt;/code&gt;修饰，所以&lt;code&gt;record&lt;/code&gt;只有&lt;code&gt;getter&lt;/code&gt;而已。更符合 Record 这么名词，就是不可更改（Immutable）的。&lt;/p&gt;

&lt;p&gt;JDK 16 之前：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;y&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Point[x=%d, y=%d]"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Lombok&lt;/code&gt;写法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Getter&lt;/span&gt;
&lt;span class="nd"&gt;@ToString&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JDK 16 &lt;code&gt;record&lt;/code&gt;写法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 17 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Java 17 是一个长期支持（LTS）版本，有较多的更新，这里我只列出两个我认为比较值得一提的特性。&lt;/p&gt;

&lt;h4&gt;
  
  
  密封类 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/409" rel="noopener noreferrer"&gt;JEPS-409: Sealed Classes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;sealed&lt;/code&gt; 密封类用来限制&lt;code&gt;class&lt;/code&gt;和&lt;code&gt;interface&lt;/code&gt;的继承的机制，可以说是灵活版的&lt;code&gt;final&lt;/code&gt;。被&lt;code&gt;sealed&lt;/code&gt;修饰的类可以指定子类，而且&lt;code&gt;sealed&lt;/code&gt;修饰的类的机制具有传递性，而它的子类必须使用&lt;code&gt;final&lt;/code&gt;、&lt;code&gt;sealed&lt;/code&gt;、&lt;code&gt;non-sealed&lt;/code&gt;来修饰。&lt;/p&gt;

&lt;p&gt;打个比方：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt;
    &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;WeirdShape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; 
    &lt;span class="n"&gt;permits&lt;/span&gt; &lt;span class="nc"&gt;TransparentRectangle&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FilledRectangle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransparentRectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FilledRectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Rectangle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WeirdShape&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;

&lt;h4&gt;
  
  
  Switch 模式匹配 (预览) &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/406" rel="noopener noreferrer"&gt;JEPS-406: Pattern Matching for switch (Preview)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;虽然在 JDK 16 加入了&lt;code&gt;instanceof&lt;/code&gt;模式匹配，但有些使用场景，写起代码来还是比较麻烦的。在 JDK 17 把模式匹配引入到&lt;code&gt;switch&lt;/code&gt;里。虽然这个是预览，但我觉得这个特性挺有用的，就说说这个用在&lt;code&gt;switch&lt;/code&gt;里的模式匹配。&lt;/p&gt;

&lt;p&gt;使用&lt;code&gt;instanceof&lt;/code&gt;模式匹配：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;formatter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"unknown"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"int %d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long %d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"double %f"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"String %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;formatted&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;新的&lt;code&gt;switch&lt;/code&gt;写法简洁很多：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;formatterPatternSwitch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"int %d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long %d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"double %f"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"String %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;回顶部&lt;/p&gt;




&lt;h3&gt;
  
  
  JDK 18 &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  默认 UTF-8 字符编码 &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://openjdk.org/jeps/400" rel="noopener noreferrer"&gt;JEPS-400: UTF-8 by Default&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;最后提一提用纯英文写代码的不太关心的改进，而用中文写代码需要知道的，就是默认字符编码。在 JDK 18 把默认字符编码设置成了 UTF-8。这样有用字符编码的 APIs 都能在开发，操作系统和配置上保持一致性。 &lt;/p&gt;

&lt;p&gt;回顶部&lt;/p&gt;

&lt;h2&gt;
  
  
  总结 &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;JDK 17 已改进与新增了挺多很有用的特性，以上是我个人认为帮助到我平日写代码的，不仅能写出更清晰的代码（readability），在性能上也有大幅的提升。&lt;br&gt;
如果你还用着 JDK 8，强力建议尽快升级到 JDK 17，一般上是不会有太多的问题，必须注意的是 GC，也许默认的 GC 是使用 Serial GC，而新版是使用 G1GC。&lt;/p&gt;

&lt;p&gt;回顶部&lt;/p&gt;

&lt;p&gt;官方视频介绍：&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=NA-sB3zvluE" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=NA-sB3zvluE&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>如何修正npm/yarn的security问题</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sat, 22 Jan 2022 07:20:19 +0000</pubDate>
      <link>https://forem.com/andylow/ru-he-xiu-zheng-npmyarnde-securitywen-ti-2nb7</link>
      <guid>https://forem.com/andylow/ru-he-xiu-zheng-npmyarnde-securitywen-ti-2nb7</guid>
      <description>&lt;h1&gt;
  
  
  审核程序包相关性是否存在安全漏洞
&lt;/h1&gt;

&lt;h2&gt;
  
  
  关于安全审核
&lt;/h2&gt;

&lt;p&gt;根据npm官方&lt;a href="https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities" rel="noopener noreferrer"&gt;docs&lt;/a&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A security audit is an assessment of package dependencies for security vulnerabilities. Security audits help you protect your package's users by enabling you to find and fix known vulnerabilities in dependencies that could cause data loss, service outages, unauthorized access to sensitive information, or other issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单来说就是对package dependencies进行安全漏洞评估以确保已知安全漏洞得到修复。&lt;/p&gt;

&lt;h2&gt;
  
  
  安全漏洞能否自动修复？
&lt;/h2&gt;

&lt;p&gt;在一定程度上是能的。npm提供了&lt;code&gt;npm audit fix&lt;/code&gt;自动修复程序，能自动将有安全漏洞问题的dependencies更新到目前安全的兼容版本。杯具的是，yarn目前只提供了安全审核&lt;code&gt;yarn audit&lt;/code&gt;，并没有可用的自动修复程序。所以yarn用户需要一些特殊的步骤来实现自动修复。&lt;/p&gt;

&lt;h2&gt;
  
  
  使用npm修复安全漏洞
&lt;/h2&gt;

&lt;p&gt;使用npm审核修复略为简单，只需运行&lt;code&gt;npm audit fix&lt;/code&gt;就能自动更新有安全漏洞的dependencies。但是，在某些情况下可能需要手动检查与更新。在这种情况下，npm通常会显示如何解决该特定dependency。&lt;/p&gt;

&lt;h2&gt;
  
  
  使用yarn修复安全漏洞
&lt;/h2&gt;

&lt;p&gt;如前所述，yarn没有类似&lt;code&gt;yarn audit fix&lt;/code&gt;的自动指令。因此，我们必须依靠两种方法：&lt;/p&gt;

&lt;h3&gt;
  
  
  1. 使用npm来解决
&lt;/h3&gt;

&lt;p&gt;如果您使用的是yarn项目，则运行&lt;code&gt;npm audit fix&lt;/code&gt;将得到以下的error：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm ERR! code ENOLOCK
npm ERR! audit This command requires an existing lockfile.
npm ERR! audit Try creating one first with: npm i --package-lock-only
npm ERR! audit Original error: loadVirtual requires existing shrinkwrap file

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/andylow/.npm/_logs/2021-04-30T06_22_16_004Z-debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;我们可以跟着指示运行&lt;code&gt;npm i --package-lock-only&lt;/code&gt;，这个指令将创建一个&lt;code&gt;package-lock.json&lt;/code&gt;文件。&lt;/p&gt;

&lt;p&gt;然后我们可以再次运行&lt;code&gt;npm audit fix&lt;/code&gt;来达成自动修复。&lt;/p&gt;

&lt;p&gt;最后，别忘了删除&lt;code&gt;package-lock.json&lt;/code&gt;，因为它与&lt;code&gt;yarn.lock&lt;/code&gt;会发生冲突。&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 更新使用&lt;code&gt;yarn audit&lt;/code&gt;发现的dependencies
&lt;/h3&gt;

&lt;p&gt;在运行&lt;code&gt;yarn audit&lt;/code&gt;之后，会显示哪些dependencies拥有安全漏洞以及哪个版本已经修复了漏洞。&lt;/p&gt;

&lt;p&gt;现在来了棘手的问题。在Project中可能有多个依赖项使用相同的dependency，但是它们可能使用的版本不同。值得庆幸的是，yarn提供了&lt;a href="https://classic.yarnpkg.com/en/docs/selective-version-resolutions" rel="noopener noreferrer"&gt;选择性的dependency解决方案&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我们可以用以下的格式在&lt;code&gt;package.json&lt;/code&gt;中定义resolutions：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* package.json */&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolutions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;package&amp;gt;/**/&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;假设我们有一个dependency A和dependency B，并且它们都依赖于另一个dependency C。它们的关系由以下结构定义：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── A
|   ├── C (3.1.3)
|   └── D
├── B
|   └── C (1.0.2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在&lt;code&gt;resolutions&lt;/code&gt;里可以这么写：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* package.json */&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolutions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A/**/C&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3.1.3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B/**/C&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Javascript的5个小技巧</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sat, 04 Dec 2021 19:23:59 +0000</pubDate>
      <link>https://forem.com/andylow/javascriptde-4ge-xiao-ji-qiao-4bjf</link>
      <guid>https://forem.com/andylow/javascriptde-4ge-xiao-ji-qiao-4bjf</guid>
      <description>&lt;h2&gt;
  
  
  删除Array中重复的值
&lt;/h2&gt;

&lt;p&gt;利用&lt;code&gt;Set&lt;/code&gt;特性。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  模板字符串
&lt;/h2&gt;

&lt;p&gt;使用反引号 (&lt;code&gt;` `&lt;/code&gt;) 来代替普通字符串中的用双引号和单引号。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num1&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Template_literals" rel="noopener noreferrer"&gt;更多资讯&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  类转换
&lt;/h2&gt;

&lt;p&gt;使用&lt;code&gt;!!&lt;/code&gt;转换成Boolean。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;使用&lt;code&gt;+&lt;/code&gt;转换成Number&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;num1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;num2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  空值合并运算符
&lt;/h2&gt;

&lt;p&gt;当需要给空值一个默认值，可以使用&lt;code&gt;??&lt;/code&gt;。&lt;br&gt;
那么为何不是&lt;code&gt;||&lt;/code&gt;呢？因为&lt;code&gt;||&lt;/code&gt;无法区分 false、0、空字符串 "" 和 null/undefined。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;field2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;field3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;field4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// value&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field2&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field3&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field4&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// value&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;fiedl2&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field3&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;field4&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;高级用法可以参阅&lt;a href="https://zh.javascript.info/nullish-coalescing-operator" rel="noopener noreferrer"&gt;这里&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  可选链 &lt;code&gt;?.&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;使用&lt;code&gt;?.&lt;/code&gt;简去使用&lt;code&gt;if else&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;；&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nullValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Hi&lt;/span&gt;
&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "'empty' undefined error"&lt;/span&gt;
&lt;span class="nx"&gt;nullValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "'nullValue' undefined error"&lt;/span&gt;

&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "no error"&lt;/span&gt;
&lt;span class="c1"&gt;// equal to &lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sayHi&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;nullValue&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "no error"&lt;/span&gt;
&lt;span class="c1"&gt;// equal to &lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;nullValue&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;nullValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sayHi&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;nullValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Java UUID 之路</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sun, 11 Apr 2021 15:02:05 +0000</pubDate>
      <link>https://forem.com/andylow/java-uuid-3onm</link>
      <guid>https://forem.com/andylow/java-uuid-3onm</guid>
      <description>&lt;h2&gt;
  
  
  什么是UUID?
&lt;/h2&gt;

&lt;p&gt;UUID (Universally Unique Identifier) 是给于所有用途一个128位长的唯一值。&lt;/p&gt;

&lt;p&gt;一般 UUID 标准使用Hex octets（十六位，八位字节）进度数字。&lt;br&gt;
是由4个字符和4个“ - ”符号组成，综合长度是36个字符。&lt;br&gt;
而所有位都设为0就是Nil UUID。 &lt;/p&gt;

&lt;p&gt;这里拿个栗子：&lt;br&gt;
 &lt;code&gt;123e4567-e89b-42d3-a456-556642440000&lt;/code&gt;&lt;br&gt;
 &lt;code&gt;xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A 表示确定 UUID 布局的变量。 UUID 中的所有其他位取决于变量字段中位的设置。变体由A的3个最重要位确定：&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MSB1&lt;/th&gt;
&lt;th&gt;MSB2&lt;/th&gt;
&lt;th&gt;MSB3&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;reserved (0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;current variant (2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;reserved for Microsoft (6)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;reserved for future (7)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;举例的 UUID 中的 A 值是'a'。 二进制等价物'a'（= 10xx）将变量显示为2。&lt;br&gt;
 B 代表版本。 举例的 UUID 中的版本（B的值）是4。 &lt;/p&gt;
&lt;h2&gt;
  
  
  Java 提供的 UUID
&lt;/h2&gt;

&lt;p&gt;UUID 布局变量为2 分别有5个版本：&lt;br&gt;
 v1: 基于时间 (Time Based)，&lt;br&gt;
 v2: DCE安全性&lt;br&gt;
 v3，v5: 基于名称 (Name Based)&lt;br&gt;
 v4: 随机 &lt;/p&gt;

&lt;p&gt;Java 只提供了v3和v4 的 UUID implementation，但也提供了用于生成任何类型的UUID的构造函数：&lt;br&gt;
 &lt;code&gt;UUID uuid = new UUID(long mostSigBits, long leastSigBits);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Java 也提供了获取 UUID 的变体和版本的方法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接下来我们来看看不同版本的 UUID 生成。&lt;/p&gt;

&lt;h2&gt;
  
  
  版本 3 &amp;amp; 5
&lt;/h2&gt;

&lt;p&gt;v3 &amp;amp; 5 的 UUID  使用 namespace 和 name 的 hash 来进行生成。 namespace标识符可以是域名系统（DNS），对象标识符（OID），URL等。 &lt;br&gt;
  &lt;code&gt;UUID = hash(NAMESPACE_IDENTIFIER + NAME)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;那么问题来了，v3和v5有什么区别呢？那就是 hash 算法，v3 使用得是 MD5  (128位)  而 v5 使用得是 SHA-1 (160位)。&lt;/p&gt;

&lt;p&gt;那么问题又来了，UUID 不是128位而已吗？SHA1 有160位怎么办？ &lt;br&gt;
 简而言之，我们将生成值散列截断为128位，然后将4位替换为版本，将2位替换为变量。 &lt;/p&gt;

&lt;p&gt;Java 只提供了 UUID v3 的生成，这里我们看看 Java 生成 UUID v3 的方法：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
 &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nameUUIDFromBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  版本 4
&lt;/h2&gt;

&lt;p&gt;UUID v4 的生成是使用随机数作为源。 Java 是用 SecureRandom （使用不可预测的值作为种子来生成随机数以减少冲突的可能性） 来实现。&lt;br&gt;
 Java 生成 UUID v4 非常简单：&lt;br&gt;&lt;br&gt;
 &lt;code&gt;UUID uuid = UUID.randomUUID();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;我们也可以使用 SHA-256 加上随机的 UUID 来使用：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;MessageDigest&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MessageDigest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SHA-256"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
 &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytesToHex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;digest&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  总结
&lt;/h2&gt;

&lt;p&gt;v3 和 v5 都具有不错的属性，不同的系统可以使用相同的 namespace 和 name 可以生成相同的UUID。 用于创建分层 UUID 是不错的选择。&lt;/p&gt;

&lt;p&gt;如果只需要简单的UUID生成，那么使用 v4 就可以了。 &lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Java 8 Lambda 表达式简介</title>
      <dc:creator>[yun]</dc:creator>
      <pubDate>Sun, 11 Apr 2021 14:41:09 +0000</pubDate>
      <link>https://forem.com/andylow/java-8-lambda-5214</link>
      <guid>https://forem.com/andylow/java-8-lambda-5214</guid>
      <description>&lt;p&gt;Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确，但现在姑且这么认为)，简单地说，它是没有声明的方法，也即没有访问修饰符、返回值声明和名字。它是 Java 8 中最重要新特性。&lt;/p&gt;

&lt;p&gt;Java 中的 Lambda 表达式通常使用 (arguments) -&amp;gt; (expression) 语法书写。以下是lambda表达式的重要特征:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;可选参数&lt;/strong&gt;：Lambda 表达式可以有零个或多个参数。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;可选类型声明&lt;/strong&gt;：不需要声明参数类型，编译器可以统一识别参数值。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;可选的参数圆括号&lt;/strong&gt;：一个参数无需定义圆括号，但多个参数需要定义圆括号。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;可选的大括号&lt;/strong&gt;：如果主体包含了一个语句，就不需要使用大括号。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;可选的返回关键字&lt;/strong&gt;：如果主体只有一个表达式返回值则编译器会自动返回值，大括号需要指定明表达式返回了一个数值。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以下是一些 Lambda 表达式的例子：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="c1"&gt;// 无argument，直接return值&lt;/span&gt;
 &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Andy"&lt;/span&gt;

 &lt;span class="c1"&gt;// 接收一个argurment, return一个计算值&lt;/span&gt;
 &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;  

 &lt;span class="c1"&gt;// 接收2个arguments, return一个计算值  &lt;/span&gt;
 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;  

 &lt;span class="c1"&gt;// 接受一个string, 并println, 不return任何值  &lt;/span&gt;
 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lambda 表达式举例
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="c1"&gt;// 旧方法:&lt;/span&gt;
 &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="nd"&gt;@Override&lt;/span&gt;
     &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from thread"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;
 &lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

 &lt;span class="c1"&gt;// Lambda方法:&lt;/span&gt;
 &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from thread"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;以下代码的作用是打印出给定数组中的所有元素。注意，使用 Lambda 的方法不止一种。在下面的例子中，我们先是用常用的箭头语法创建 Lambda，之后，使用 Java 8 全新的双冒号(::)操作符将一个常规方法转化为 Lambda：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="c1"&gt;// 旧方法:&lt;/span&gt;
 &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nl"&gt;n:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;

 &lt;span class="c1"&gt;// Lambda方法:&lt;/span&gt;
 &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;


 &lt;span class="c1"&gt;// ::操作&lt;/span&gt;
 &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  变量作用域
&lt;/h3&gt;

&lt;p&gt;Lambda 只能引用标记了 final 的外层局部变量，这就是说不能在 lambda 内部修改定义在域外的局部变量，否则会编译错误。&lt;/p&gt;

&lt;p&gt;在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
