从此
📄文章 #️⃣专题 🌐酷站 👨‍💻技术 📺 📱

Java编程语言、JDK新特性语法、集成开发环境IDE、Gradle | Guava、Hutool、Netty

综合/最新

Java编程专题Nginx Jetty HTTP C/SJava WebAndroid应用开发JDK源码Gradle构建
原则 - 主用JDK版本选择安装版,备用JDK则用压缩版。 Java/JDK下载地址 Linux安装:apt install default-jre (Debian默认为JDK21) 或用解压缩方式: wget https://download.oracle.com/java/24/latest/jdk-24_linux-aarch64_bin.tar.gz 或 jdk-24_linux-x64_bin.tar.gz tar -xf jdk-24_linux-*64_bin.tar.gz Java程序打包: 完整JDK/JRE方式: JRE自定义镜像方式: cd "C:\Program Files\Java\jdk-24\bin" ./jlink --help 只含 java.base 则生成后约 30-47MiB。 [可选] 查看依赖的modules: jdeps HelloWorld.class 不含应用: ./jlink --output $HOME/Desktop/my-jre/ --add-modules java.base ./jlink --output $HOME/Desktop/my-jre/ --add-modules java.base,jdk.localedata --include-locales en,zh-Hans-CN --strip-debug --compress=zip-9 说明 - 不指定 --module-path 则默认取 JDK 目录 jmods/;可指定 jar(不指定模块名则取文件名) 和通过 jar 或 *.class 生成的 jmod 文件。 其中 --strip-debug --compress=zip-9 参数均为可选,但建议加上,压缩似乎只针对 my-jre/lib/modules 文件。 包含应用: ./jlink --output $HOME/Desktop/my-jre/ --module-path ../jmods/:path/to/your-modular.jar:your-modular.jmod --add-modules java.base 说明 - 运行命令 java --module your.modular/HelloWorld.class 其他参数:如果想重用参数,可通过配置文件指定 ./jlink @my.conf --add-modules java.base,javafx.base,javafx.graphics,javafx.controls --launcher start=java.base/java 指定本地化语言(默认en_US) ./jlink --add-modules java.base,jdk.localedata --include-locales en,ja,zh-Hans-CN 清理输出目录: rm -r $HOME/Desktop/my-jre/ [可选] 创建jmod文件: jmod create --class-path mods/com.example.mymodule --output mymods/com.example.mymodule.jmod --module-version 1.0.0 --main-class com.example.mymodule.MyClass --resource-path resources 新: Oracle GraalVM 仅支持 CycloneDX 生成 SBOM,暂不支持 SPDX 格式。 JDK 24+: 支持 ASM 能力 java.lang.classfile.ClassFile.of().parse(byte[] bytes) 通过预缓存加快启动速度 java -XX:AOTCache=app.aot -jar app.jar 通过--enable-linkable-runtime减少JDK镜像尺寸,从JDK_HOME\jmods\抽取所用classes。 Stream.of(1, 2, 3).gather(Gatherers.mapConcurrent(3, (item) -> { return item * item; // Thread.currentThread().isVirtual() })).toList(); // map 未使用 VirtualThread;JDK 24+ 首选 mapConcurrent Java/JDK版本重大变化: Java 18+ 默认编码统一为 StandardCharsets.UTF_8 Java 9+ 引入了JPMS(Java Platform Module System) 死记、偏门: 常量 - 编码方式 StandardCharsets.UTF_8、换行符 System.linSeparator()、本机地址 InetAddress.getLocalHost().getHostAddress() 目录 - 当前目录 System.getProperty("user.dir") 在MAC DOCK上启动则总为“/”,Windows正常; Path对象不含结尾的斜杠。 File.createTempFile("x".repeat(3), ".txt") 返回 File,而 Files.createTempFile(...) 则返回 Path。 其他 - Gradle判断>=Java版本:org.gradle.api.JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17); 也可用Guava库com.google.common.base.JavaVersion 国名代码 - Locale.getISOCountries(); // 输出2字母大写,等同域名后缀,3字母则更清晰;全名用 locale.getDisplayCountry(Locale.ENGLISH) 时区 - PRC or CTT 即 China Standard Time 上海时区,简短易记。 TimeZone.getTimeZone("PRC").toZoneId(); ZoneId.SHORT_IDS.get("CTT"); // 输出 Asia/Shanghai ZoneId.of("Asia/Shanghai"); // 完整写法 ZoneOffset.UTC.normalized() // 规范化 无法跳读,直接获取最后一个元素,仍然会接收之前所有元素文件流 - request.getParts().stream().findLast().getInputStream(); 时间 - 周年份(Week Year)指跨年周的天数低于4天就归属到新年份了,1月1日永远属于新年份第一周。Java中用YYYY表示周年份,常规年份使用yyyy。 错误响应标准(RFC 9457) - org.springframework.http.ProblemDetail NetBeans控制台中文乱码解决(macOS无此问题):计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage 将 ACP 值改为 65001。 IDE: NetBeans - 离线模式 NetBeans -> Tools -> Options -> Java -> Gradle -> ✔Offline macOS安装包为Apache-NetBeans-25.pkg。 v25 Bug - 时间久了,外部复制后粘贴到编辑器里失效。

内容

常用
Stream API:
  按字段排序 - items.stream().sorted(Comparator.comparing(Item::getName)).toList();
  按多个字段倒序排序 - items.stream().sorted(Comparator.comparing(Item::getName).reversed().thenComparing(Item::getField)).collect(Collectors.toList());

线程:
  阻塞当前线程数秒: LockSupport.parkNanos(Duration.ofSeconds(3).toNanos()); // 或精确时间点 LockSupport.parkUntil(Instant.now().plusSeconds(3).toEpochMilli());
  ThreadPoolExecutor submit(...) 内部封装了其 execute(...) 方法,提供了延迟处理异常的能力 var f = es.submit(...); if (f.isDone()) { f.exceptionNow(); } 或取返回值 f.resultNow() 。

无输出执行终端命令: new ProcessBuilder("killall", "Finder").start();
执行含管道命令:new ProcessBuilder("/bin/sh", "-c", "cat /proc/meminfo | grep MemTotal").start();
执行终端命令并返回退出码: 
  new ProcessBuilder("gio", "launch", "/etc/xdg/autostart/x.desktop").start()
    .onExit().thenAccept(p -> System.out.println(p.pid() + " | " + p.exitValue())).join();
  System.exit(0); // 不会停止上方 ProcessBuilder 已执行命令。

异常错误:
  抛异常:
    数据库连接超时应记录后并向上抛出:
      fetch("/main/api/articles/modify", {
        method: "POST", body: JSON.stringify({}),
        headers: {"Content-Type": "application/json"}
      }).then(r => r.text()).then(data => {
        console.log(data);
        if (data === "ok") { location.href = "./"; } else { alert(data); }
      });

      @Override
      protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try { executeUpdate(sql); } catch (SQLException ex) {
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("text/plain");  //  避免被搜索引擎收录
            response.getWriter().print(ex.getLocalizedMessage());
            return;
        }
      }

      public static void executeUpdate(String sql) throws SQLException {
        try (var conn = DriverManager.getConnection(url, user, password); //
                 var cs = conn.createStatement()) {
            System.out.println(cs.executeUpdate(sql));
        } catch (SQLException ex) {
            ex.printStackTrace(System.err);
            throw ex; // 连接超时等 SQLTimeoutException
        }
      }
跨语言
  可逆Hex(避免URL编码空格问题) - Java 中 java.util.HexFormat.of().parseHex("E6b58be8af95") 可解码JavaScript编码(Array.from方法入参必须为无符号):
    https://tsc.openle.com/.well-known/static/scripts/core.js
    非module脚本 - https://tsc.openle.com/.well-known/static/scripts/core-classic.js
网络
Java支持mDNS主机名查对应IP(需20分钟通讯过): InetAddress.getByName("raspberrypi.local").getHostAddress()

其他

Java运行期和编译期异常

网络Socket - 常规功能用 Java NIO API,较复杂可用 Netty。

Java运行WebAssembly - Instance.builder(com.dylibso.chicory.wasm.Parser.parse(new File("./x.wasm"))).build()

知名类库 - 流行工具库 Guava
验证码库 - Java国产工具库 Hutool
序列化库 - Java国产库 阿里巴巴 Fastjson
工具 - TCP/UDP网络调试助手
MQTT Clients - https://github.com/hivemq/hivemq-mqtt-client 或用不怎么更新的 https://eclipse.dev/paho/ 

UDP:
    try {
        var dp = new DatagramPacket(bytes, bytes.length,
                InetAddress.getByName("192.168.3.193"), 7777);
        socket.send(dp); // DatagramSocket 应提升为成员变量,便于重用。
    } catch (IOException e) { e.printStackTrace(System.err); }

WoL唤醒 - InetAddress.getByName("device.local").isReachable(3000); // 亲测能唤醒未限定幻数据包(Magic Packet)的休眠设备(自动休眠可用/主动关机不行);返回false。
  Windows 命令 Resolve-DnsName device.local 效果等同上行代码。