标签: java-16

Lombok 访问 jdk.compiler 的内部包与 Java-16 不兼容

只需将我的一个项目从 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)

java incompatibility maven lombok java-16

31
推荐指数
5
解决办法
2万
查看次数

返回类型为 void 的 switch 表达式

当 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 void switch-statement switch-expression java-16

30
推荐指数
3
解决办法
1625
查看次数

为什么在 Java 16 中的非静态内部类中允许静态方法?

我们知道可以使用外部类的实例访问非静态内部类,因此静态方法在非静态类中意义不大。但是从 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)

java inner-classes java-16

30
推荐指数
2
解决办法
2737
查看次数

为什么 IndexOutOfBoundsException 现在在 Java 16 中有一个带有长索引作为参数的构造函数?

我正在检查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值索引;shortbyte …

java arrays indexoutofboundsexception long-integer java-16

29
推荐指数
3
解决办法
2260
查看次数

从 Java 16 开始,何时以及如何在 flatMap 上执行从 Stream mapMulti 到 0..n 的映射

我一直在浏览 Java 16 的新闻和源代码,并且遇到了名为mapMulti. 早期访问的JavaDoc说它类似于flatMap并且已经被批准用于完全相同的 Java 版本。

<R> Stream<R> mapMulti?(BiConsumer<? super T,?? super Consumer<R>> mapper)
Run Code Online (Sandbox Code Playgroud)
  • 如何使用此方法执行一对 0..n 映射?
  • 新方法如何工作以及它与flatMap. 什么时候最好?
  • mapper可以调用多少次?

java java-stream flatmap java-16 mapmulti

22
推荐指数
2
解决办法
1147
查看次数

为什么我不能使用 Stream#toList 在 Java 16 中收集类的接口列表?

我正在流式传输实现接口的类的对象。我想将它们收集为接口的元素列表,而不是实现类。

这对于 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)

我们可以显式地将每个元素从 转换FancyDodoDodo。但至少为了简洁起见,我们也可以使用.collect(Collectors.toList()).

为什么我不能使用 Stream#toList 在 Java 16 中收集类的接口列表?

如果有人有比明确投射更好的解决方案,我也很乐意听到:)

java generics type-inference java-stream java-16

21
推荐指数
3
解决办法
1051
查看次数

有没有办法通过反射识别 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 reflection java-record java-16

16
推荐指数
2
解决办法
1100
查看次数

在 Java 记录中强制执行不可变集合?

Java 记录用于实现浅不可变的数据载体类型。如果构造函数接受可变类型,那么我们应该实现显式防御性复制以强制不变性。例如

record Data(Set<String> set) {
    public Data(Set<Thing> set) {
        this.set = Set.copyOf(set);
    }
}
Run Code Online (Sandbox Code Playgroud)

这有点烦人 - 我们必须

  1. 实现一个老式的 POJO 构造函数(复制字段)而不是使用规范的构造函数和
  2. 显式初始化每个字段只是为了处理可变字段的防御性副本。

理想情况下,我们想要表达的是以下内容:

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 机制来强制执行不可变集合?

java immutability java-record java-16

13
推荐指数
1
解决办法
261
查看次数

Stream.toList() 会比 Collectors.toList() 表现得更好吗

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 performance java-stream jmh java-16

12
推荐指数
1
解决办法
749
查看次数

Record 无法从构造函数获取参数名称?

想看看如何在 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 constructor java-record java-16

11
推荐指数
1
解决办法
319
查看次数