只需将我的一个项目从 Java-15 升级到 16(使用此处的最新版本)。在编译使用 lombok 的项目时,例如:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
我有点被堆栈跟踪卡住了
Caused by: java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module @0x4e670245) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module @0x4e670245
at lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment (LombokProcessor.java:433)
at lombok.javac.apt.LombokProcessor.init (LombokProcessor.java:92)
at lombok.core.AnnotationProcessor$JavacDescriptor.want (AnnotationProcessor.java:160)
at lombok.core.AnnotationProcessor.init (AnnotationProcessor.java:213)
at lombok.launch.AnnotationProcessorHider$AnnotationProcessor.init (AnnotationProcessor.java:64)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.<init> (JavacProcessingEnvironment.java:702)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next (JavacProcessingEnvironment.java:829)
Run Code Online (Sandbox Code Playgroud)
现在,至少我认为我知道解决这个问题的技巧,但即使在尝试以下配置时 maven-compiler-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>16</source>
<target>16</target>
<!-- <release>16</release>-->
<compilerArgs>
<arg>--enable-preview</arg>
<arg>-Xlint:all</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
</compilerArgs>
<!--for unmappable …Run Code Online (Sandbox Code Playgroud) 当 switch 分支调用具有 void 返回类型的方法时,有没有办法强制对所有枚举值进行彻底检查?仅仅为了诱使编译器要求穷举而对产量进行硬编码是非常丑陋的。
这是我当前的模式(句柄方法具有 void 返回类型)
int unused = switch (event.getEventType()) {
case ORDER -> { handle((OrderEvent) event); yield 0; }
case INVOICE -> { handle((InvoiceEvent) event); yield 0; }
case PAYMENT -> { handle((PaymentEvent) event); yield 0; }
};
Run Code Online (Sandbox Code Playgroud)
我想使用表达式的原因是在添加新枚举值但未处理时出现编译错误。
我们知道可以使用外部类的实例访问非静态内部类,因此静态方法在非静态类中意义不大。但是从 Java 16 开始,允许在非静态内部类中使用静态方法。
为什么首先存在这个限制?为什么在较新的版本中允许这样做?
public class OuterClass {
class InnerClass {
static void printMe() {
System.out.println("Inside inner class");
}
}
public static void main(String[] args) {
InnerClass.printMe();
}
}
Run Code Online (Sandbox Code Playgroud) 我正在检查JDK 16中IndexOutOfBoundsException的实现,我注意到long引入了一个带有索引的新构造函数:
/**
* Constructs a new {@code IndexOutOfBoundsException} class with an
* argument indicating the illegal index.
*
* <p>The index is included in this exception's detail message. The
* exact presentation format of the detail message is unspecified.
*
* @param index the illegal index.
* @since 16
*/
public IndexOutOfBoundsException(long index) {
super("Index out of range: " + index);
}
Run Code Online (Sandbox Code Playgroud)
据我所知,数组索引通常是int值,这在语言规范部分 §10.4 中得到证实:
数组必须按
int值索引;short、byte …
我一直在浏览 Java 16 的新闻和源代码,并且遇到了名为mapMulti. 早期访问的JavaDoc说它类似于flatMap并且已经被批准用于完全相同的 Java 版本。
<R> Stream<R> mapMulti?(BiConsumer<? super T,?? super Consumer<R>> mapper)
Run Code Online (Sandbox Code Playgroud)
flatMap. 什么时候最好?mapper可以调用多少次?我正在流式传输实现接口的类的对象。我想将它们收集为接口的元素列表,而不是实现类。
这对于 Java 16.0.1 的Stream#toList方法似乎是不可能的。例如在下面的代码中,最后一条语句将无法编译。
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WhyDodo {
private interface Dodo { }
private static class FancyDodo implements Dodo { }
public static void main(String[] args) {
final List<Dodo> dodos = Stream.of(new FancyDodo()).collect(Collectors.toList());
final List<FancyDodo> fancyDodos = Stream.of(new FancyDodo()).toList();
final List<Dodo> noFancyDodos = Stream.of(new FancyDodo()).toList();
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以显式地将每个元素从 转换FancyDodo为Dodo。但至少为了简洁起见,我们也可以使用.collect(Collectors.toList()).
为什么我不能使用 Stream#toList 在 Java 16 中收集类的接口列表?
如果有人有比明确投射更好的解决方案,我也很乐意听到:)
假设我有这样的记录(或任何其他记录):
record X(int i, int j) {
X(int i) {
this(i, 0);
}
X() {
this(0, 0);
}
X(String i, String j) {
this(Integer.parseInt(i), Integer.parseInt(j));
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法通过反射找到这条记录的规范构造函数,即在RecordHeader?
Java 记录用于实现浅不可变的数据载体类型。如果构造函数接受可变类型,那么我们应该实现显式防御性复制以强制不变性。例如
record Data(Set<String> set) {
public Data(Set<Thing> set) {
this.set = Set.copyOf(set);
}
}
Run Code Online (Sandbox Code Playgroud)
这有点烦人 - 我们必须
理想情况下,我们想要表达的是以下内容:
record SomeRecord(ImmutableSet<Thing> set) {
}
Run Code Online (Sandbox Code Playgroud)
或者
record SomeRecord(Set<Thing> set) {
public SomeRecord {
if(set.isMutable()) throw new IllegalArgumentException(...);
}
}
Run Code Online (Sandbox Code Playgroud)
这里我们使用一个虚构的ImmutableSet类型和Set::isMutable方法,在任何一种情况下,记录都是使用规范构造函数创建的 - 很好。不幸的是它不存在!
据我所知,内置集合类型(在 Java 10 中引入)是隐藏的,即无法确定集合是否不可变(除了尝试修改它)。
我们可以使用 Guava,但是当 99% 的功能已经在核心库中时,这似乎有点过分了。或者,有 Maven 插件可以测试注释为不可变的类,但这又是一个创可贴而不是解决方案。
是否有任何纯 Java 机制来强制执行不可变集合?
JDK 正在引入一个Stream.toList()带有JDK-8180352的 API 。这是一个基准代码,我试图将其性能与现有的进行比较Collectors.toList:
@BenchmarkMode(Mode.All)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 20, time = 1, batchSize = 10000)
@Measurement(iterations = 20, time = 1, batchSize = 10000)
public class CollectorsVsStreamToList {
@Benchmark
public List<Integer> viaCollectors() {
return IntStream.range(1, 1000).boxed().collect(Collectors.toList());
}
@Benchmark
public List<Integer> viaStream() {
return IntStream.range(1, 1000).boxed().toList();
}
}
Run Code Online (Sandbox Code Playgroud)
结果总结如下:
Benchmark Mode Cnt Score Error Units
CollectorsVsStreamToList.viaCollectors thrpt 20 17.321 ± 0.583 ops/s
CollectorsVsStreamToList.viaStream thrpt 20 23.879 ± 1.682 ops/s
CollectorsVsStreamToList.viaCollectors avgt 20 0.057 ± …Run Code Online (Sandbox Code Playgroud) 想看看如何在 Java 16(和 15 个相同的行为)下使用带有反射的 Records
public record RecordTest2(int id, int something, double total, LocalDateTime createdOn) {
public RecordTest2(int id, int something, double total) {
this(id, something, total, LocalDateTime.now());
}
}
Run Code Online (Sandbox Code Playgroud)
查看规范构造函数,我确实看到了参数名称,但没有看到其他参数名称。
var recordTest2 = new RecordTest2(1, 2, 3.0, LocalDateTime.now());
Class<?> objectClass = recordTest2.getClass();
Constructor<?>[] constructors = objectClass.getConstructors();
for (Constructor<?> con : constructors) {
System.out.println(con.getName());
Parameter[] parameters = con.getParameters();
for (Parameter parameter : parameters) {
System.out.printf("param: %s\n", parameter.getName());
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
net.sf.persism.dao.records.RecordTest2
param: arg0
param: arg1
param: arg2
net.sf.persism.dao.records.RecordTest2
param: …Run Code Online (Sandbox Code Playgroud) java ×10
java-16 ×10
java-record ×3
java-stream ×3
arrays ×1
constructor ×1
flatmap ×1
generics ×1
immutability ×1
jmh ×1
lombok ×1
long-integer ×1
mapmulti ×1
maven ×1
performance ×1
reflection ×1
void ×1