Java编程语言、JDK软件开发
Java综合
新特性有:结构化并发(JEP 453)、外部函数和内存API(JEP 424)等。
JDK23 - 导入模块所有包 import module java.base;
断点续传方案 - Java RandomAccessFile 大文件分片上传及合并。
Java开发工具IDE - IntelliJ IDEA、NetBeans、Eclipse
实用:
var _="Unnamed Variables";
ThreadPoolExecutor已取代ThreadGroup
死记:
日志:
抑制NetBeans和Android Studio警告 ex.printStackTrace(System.err); android.util.Log.e("tag", Log.getStackTraceString(e));
java.util.logging 包和 ex.printStackTrace() 的加锁会影响性能,且不支持异步,故仅用于调试阶段;
System.getLogger("name").log(Level.ERROR, "msg"); // 底层依赖 java.logging 模块?
ClassCastException.getMessage() 等异常会返回null;而 printStackTrace() 和 NullPointerException 则不会;
正式产品应换用支持异步的未加锁日志库,比如logback等。
获取父级异常 - if (e.getCause() instanceof BindException){}
特殊:
URI.create("https://congci.com").toURL(); JDK20+取代了过时的 new URL("https://congci.com");
序列化:
Map.entry(true, 1); 可换用支持序列化且key/value均可为null的 new AbstractMap.SimpleEntry<Boolean, Integer>(false, 0);
版本兼容性:
| Java | ClassVersion | Gradle | 其他 |
|---|---|---|---|
| Java 23 | 67 | 8.10 | ? |
| Java 22 | 66 | 8.8 | ? |
| Java 21 | 65 | 8.5 | LTS |
| Java 20 | 64 | 8.3 | ? |
Java基础
免源文件执行Java代码:
命令行输入: jshell
填入: "x".repeat(3)
退出: /exit
用法: /help
JDK21+(JEP445)新版main函数最简写法:
void main() { System.out.println("Hello, World!"); }
Linux创建Java主函数文件:
dd of=/tmp/hi.java << EOF
void main() { System.out.println(System.getProperty("java.version")); }
EOF
启动单文件源码命令: java --enable-preview --source 21 /tmp/hi.java
Gradle启用预览特性:
application { mainClass = 'App'
applicationDefaultJvmArgs = ['--enable-preview']
}
compileJava { options.compilerArgs += ['--enable-preview'] }
单jar包启动: java -jar ./app.jar com.jpkg.App 或MANIFEST.MF用Class-Path: other.jar指定额外*.jar
多jar包启动: java -cp ./app.jar;./guava-31.1-jre.jar pkg.App
孵化特性还需要添加模块儿 --add-modules jdk.incubator.concurrent
运行时新JIT(Java23+): -XX:+UnlockExperimentalVMOptions -XX:+UseGraalJIT
运行后关闭控制台:
注意 - javaw不能用双引号括住!适用于gradle assembleDist生成的app.bat;%*指所有入参。
@echo off
start javaw -cp "./app.jar;./guava-31.1-jre.jar" pkg.App %*
exit
JDK21以前版本主函数完整写法:
// 若为Linux Shebang脚本(如java.sh)则起行必须写上#!....
#!/usr/bin/java --source 11
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
chmod +x java.sh
./java.sh
[或] java --release 11 java.sh 传参...
标准编译:
javac hi.java
[指定字节码版本/JDK9前用单横杠的-source]:javac --help输出最低支持为Java8(JDK9+为Java6)
javac --release 11 hi.java
java hi
带包名则 java pkg/hi
或 JDK11+支持同时编译加执行:java hi.java
Java反编译工具(请合法使用) - JD-GUI
keytool的storetype默认是pkcs12,取代了老版本的jks私有格式;算法默认为3072 bits的SHA-384。
断言:
用途 - Java默认禁止断言,不会执行assert行代码,也不会报错;生产期间可手动启用java -ea。
语法 - assert result; 或 assert result : "移除失败";
特殊情况:
gradle等工具对JDK新版本很敏感,若报错莫名其妙,可降级至主流JDK重测:
曾遇到此类案例 - io.quarkus插件quarkusRun任务不支持JDK22;NetBeans运行的JDK和其运行的Gradle不兼容报错。
Windows PowerShell执行Java程序:
& (gcm java.exe).Path --version
Java打开命令行控制台并切换至指定目录:
var cmd = {"cmd", "/c", "start", "powershell.exe", "-NoExit", "-Command", "Set-location", "D:\\"};
//说明 - 参数-NoExit指弹出控制台窗口并停住。
//直接执行powershell语句+不显示标头:cmd = {"powershell.exe", "-Command", "Get-NetNeighbor", "-IPAddress", "192.168.3.29", "|", "ForEach-Object", "{$_.LinkLayerAddress}"};
new ProcessBuilder(cmd).start(); // 在PowerShell中执行命令、进入指定目录。
//直接输出执行结果:new String(new ProcessBuilder(cmd).start().getInputStream().readAllBytes()).trim();
// 接收命令输出流较复杂,故优先使用日志方式:
new ProcessBuilder("ping", "localhost")
//.redirectErrorStream(true).redirectOutput(ProcessBuilder.Redirect.appendTo(new File("x.log")))
.start().onExit().thenAccept(p -> System.out.println("PID:" + p.pid() + "; EXIT CODE:" + p.exitValue())).join();
Java参数
查看JVM参数(亲测Open Liberty、Gradle等均可用) - java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments() // [-Dfile.encoding=UTF-8, -Duser.language=zh]
[开发用JVM参数]
-Xmx2048m -XX:+UseZGC --enable-preview
启用预览特性JVM参数 --enable-preview
内存实际占用JVM参数 -XX:NativeMemoryTracking=summary
启用后(性能损失约10%)查看命令(主看Total:committed=值) jcmd [jps所查pid] VM.native_memory scale=MB
GC:
Java23默认垃圾回收器为-XX:+UseG1GC,可改为内存占用折半的-XX:+UseZGC,[废弃的ZGC额外参数]Java21、Java22还应加上-XX:+ZGenerational
Java Agent参数: -javaagent:agent.jar
Java语法、简写
内存不足导致无法创建对象或执行System.gc()时才会触发Full GC,即使是“软引用(SoftReference)”对象也会被回收,而“弱引用(WeakReference)”则不进行Full GC也会被回收。
垃圾回收器属于低优先级线程,故扫描时可能有延迟;System.gc()适用场合 - 在占内存较多的粗粒度操作之前调用。
Java 22实用新特性 -
Unnamed Variables: try { } catch (NumberFormatException _) { }
var arrays = {"a","b"}; // or new String[]{"a","b"};
判断字符串是不是数字 - "123".chars().allMatch(Character::isDigit);
Lambda:
@FunctionalInterface interface Fi{ void x(String x); }
Fi fi = (x) -> { System.out.println(x); }; fi.x("x");
String Templates:
var s = """
{"text": "%s"}
""".formatted("text value");
System.out.println(s); // {"text": "text value"}
遍历枚举:
var e = NetworkInterface.getNetworkInterfaces(); // Guava 👇 入参必须判null。
新迭代 - List.of("A", "B").iterator().forEachRemaining(System.out::println);
传统迭代 - while(it.hasNext()) { System.out.println(it.next()); }
if (e != null) { com.google.common.collect.Iterators.forEnumeration(e).forEachRemaining(System.out::println); }
直接比对static常量会被IDE警告永不为true/false,故改写为:
Objects.equals("com.example", BuildConfig.APPLICATION_ID);
列表去重 - stringList.stream().distinct().toList();
获取系统字体名:GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
VarHandle、MethodHandles反射API用法
Lambda、Stream API
Stream API参考
Arrays转Stream - Stream.ofNullable(request.getCookies()).forEach(System.out::println);
List转Map:Java Stream 转换List至Map写法 Collectors.toMap 或 Guava库方式
list.stream().collect(Collectors.toMap(User::getId, User::getName)); // 值为字段
list.stream().collect(Collectors.toMap(User::getId, obj -> obj)); // 值为对象
...Collectors.toMap(User::Id, obj -> obj.Name != null ? obj.Name : "") // 值为null处理
或 Collectors.toMap(User::Id, obj -> Optional.ofNullable(obj.Name()).orElse(""))
// Key重复则取首个;覆盖式则Lambda返回值改为duplicateId
list.stream().collect(Collectors.toMap(User::Id, User::Name, (firstId, duplicateId) -> firstId));
ByteBuffer写入InputStream并可读:
var bb = ByteBuffer.allocate(inputStream.available());
while (inputStream.available() > 0) {
bb.put((byte) inputStream.read());
} // 该方式似乎是逐字节写入,可再套一层做成多字节缓冲方式。
bb.flip(); // 从InputStream切换至OutputStream模式
特殊备忘
获取Java版本 - System.getProperty("java.version");
获取系统临时目录 - System.getProperty("java.io.tmpdir"); // Windows中默认取自“tmp”环境变量
设置系统临时目录 - java -Djava.io.tmpdir=C:\Users\x\AppData\Local\Temp\ -jar ...
路径不存在的方法 - Files.notExists(dirPath);
Java switch 是通过 String.equals 方法来比较 case 值的,所以应避免 NullPointerException 。
非自定义类的类加载器和getResource("")永远为null:new String().getClass().getClassLoader()
永不null:Thread.currentThread().getContextClassLoader()、CustomClass.class.getResource("");
Open Liberty - App.class.getResource("/x.wasm"); // wsjar:file:/opt/ol/wlp/usr/servers/defaultServer/apps/x.war!/WEB-INF/classes/x.wasm
类型默认值: 等同C#的default(int)或return default;
com.google.common.base.Defaults.defaultValue(Integer.TYPE); //will return 0
或 public static <T> T defaultValue(Class<T> cls) {
return (T) java.lang.reflect.Array.get(Array.newInstance(cls, 1), 0);
}
线程:
每个线程占内存1MiB,每个对象占用50B左右,即对象头16B+int字段占4B...。虚拟线程(Virtual Threads)/协程:
Thread.startVirtualThread(() -> { Thread.currentThread().isVirtual(); });Thread.ofVirtual().name("可传递自定义数据").start(() -> System.out.println());
结构化并发(Structured Concurrency)
多任务并发时,只要其中之一完成,就关闭所有任务线程:
try (var sts = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
sts.fork(() -> findUser()); sts.fork(() -> fetchOrder());
sts.joinUntil(Instant.now().plusSeconds(60)).result();
} catch (InterruptedException | TimeoutException | ExecutionException ex) {
System.err.println(ex);
}
老版本方式:Executors.newCachedThreadPool().invokeAny(List.of(() -> UUID.randomUUID()));
Java兼容性
Apache NetBeans:
IDE v20首选JDK 20,若用JDK 21+则警告“Unsupported Java Runtime”,但不影响使用;
该IDE配置的Gradle,若不支持高版本JDK则报错;
注意 - 版本发布日总会延误20天!
gradle.properties可指定IDE所用JDK之外的版本:netbeans.hint.jdkPlatform=JDK_20
【临时Bug】NB20在compileJava任务启用--enable-preview会飘红,暂注释之。
Gradle 8.1 最高兼容 JDK 20;Gradle 8.0 最高兼容 JDK 19
Android Studio Dolphin 2021.3.1 项目 最高兼容 JDK 11
jpackage - 打包java程序为系统安装包("app-image", "exe", "msi", "rpm", "deb", "pkg", "dmg")
GraalVM Native Image
Java语法
Java语言关键词、保留词列表
方法内抛出异常:throw new Exception("抛出一个异常");
方法体声明异常:void method() throws Exception, ArithmeticException { }
Java Web App | 网站应用
Java Servlet、JAX-RS(RESTful)、Spring、JSF等网页开发专题常用Java Servlet Server - Jetty、Tomcat、Undertow。
Java Web Server | HTTP网站服务监听
java -m jdk.httpserver 默认端口为-p 8000 绑IP用 -b 192.168.3.151或 C:\Progra~1\Java\jdk-21\bin\jwebserver.exe -p 8000
可选参数:默认为当前目录,可指定其他目录 -d D:\
Java 网络
Java HttpClient实例 Java Socket 网络编程详解
Java Swing | 桌面GUI程序、JNI\JNA\FFM
JDBC操作数据库
Java Optional类
参考文章
对象嵌对象判null传统写法:
if (p!= null && p.getLocation() != null && p.getLocation().getCity() != null) {
return p.getLocation().getCity().toLowerCase();
}
简写:
Optional.ofNullable(p).map(Person::getLocation)
.map(Location::getCity).map(String::toLowerCase);
Gradle & Maven
Java构建工具