如果 class 是通过 Lombok 初始化的,则 class 的谓词不能使用实例变量
Predicates of a class are not able to use the instance variable if the class is initialised via Lombok
我正在通过 Lombok Builder 初始化 class。通过它我正在初始化一个变量。但是当我在谓词定义中使用它时,它的变量值不可用。
我的代码如下所示:
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
class NumCheck {
int maxCount;
Predicate<Integer> isLessThanMax = num -> maxCount < num;
}
public class PredicateInstance {
public static void main(String[] args) {
int a = 5, b=11;
NumCheck numCheck = new NumCheck().toBuilder().maxCount(10).build();
Stream.of(2,5,6,7,10,11,20,32).filter(numCheck.isLessThanMax).forEach(System.out::println);
}
}
调试时,maxCount 的值没有初始化为 10。它保持为 0。
如果我删除 Lombok 构建器并以正常方式执行,则工作正常:
class NumCheck {
int maxCount;
Predicate<Integer> isLessThanMax = num -> maxCount < num;
}
public class PredicateInstance {
public static void main(String[] args) {
int a = 5, b=11;
NumCheck numCheck = new NumCheck();
numCheck.maxCount = 10;
Stream.of(2,5,6,7,10,11,20,32).filter(numCheck.isLessThanMax).forEach(System.out::println);
}
}
这是 Lombok 的已知限制还是我做错了什么?
可行但不适用于我的情况的解决方法:
- 将 maxCount 声明为静态。
- 声明 BiPredicate 并发送 maxCount 和 num 参数。
问题在于您调用 Lombok 生成器的方式。
而不是
NumCheck numCheck = new NumCheck().toBuilder().maxCount(10).build()
;
你应该使用:
NumCheck numCheck = NumCheck.builder().maxCount(10).build();
前者使用 no-arg 构造函数创建一个实例,然后从中创建一个构建器,并使用构建器创建第二个实例,该实例被丢弃(未分配给变量)。
后者只是通过构建器创建一个实例,并将其分配给变量。
您应该问问自己 isLessThanMax
是否真的可以通过构建器设置。在我看来更像是一个不变的定义。如果是这样的话,你应该做到 final
。 Lombok 在生成构建器时忽略带有初始值设定项的 final
字段。
(在这种情况下,您也不需要 @Builder.Default
。但是,@Builder.Default
在字段上没有任何问题。性能或内存影响完全为零。)
如果您对为什么您的代码表现如此奇怪感兴趣,请查看此处的解释。
当使用 no-args 构造函数实例化时,isLessThanMax
使用对此实例的字段 maxCount
的引用进行初始化。 maxCount
默认为 0
。然后调用 toBuilder()
,它只是将实例的所有值复制到构建器。最后,您对该构建器调用 maxCount(10).build()
。生成的第二个实例将具有 maxCount = 10
,但与第一个实例的 isLessThanMax
值完全相同。这意味着第二个实例的谓词仍然引用第一个实例的字段,即0
。因此,即使您为第二个实例设置 maxCount = 10
,Predicate
仍会使用第一个实例中的 maxCount = 0
值进行比较。
tl;dr:不要将引用实例字段的方法引用与 toBuilder()
.
结合使用
我正在通过 Lombok Builder 初始化 class。通过它我正在初始化一个变量。但是当我在谓词定义中使用它时,它的变量值不可用。
我的代码如下所示:
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
class NumCheck {
int maxCount;
Predicate<Integer> isLessThanMax = num -> maxCount < num;
}
public class PredicateInstance {
public static void main(String[] args) {
int a = 5, b=11;
NumCheck numCheck = new NumCheck().toBuilder().maxCount(10).build();
Stream.of(2,5,6,7,10,11,20,32).filter(numCheck.isLessThanMax).forEach(System.out::println);
}
}
调试时,maxCount 的值没有初始化为 10。它保持为 0。
如果我删除 Lombok 构建器并以正常方式执行,则工作正常:
class NumCheck {
int maxCount;
Predicate<Integer> isLessThanMax = num -> maxCount < num;
}
public class PredicateInstance {
public static void main(String[] args) {
int a = 5, b=11;
NumCheck numCheck = new NumCheck();
numCheck.maxCount = 10;
Stream.of(2,5,6,7,10,11,20,32).filter(numCheck.isLessThanMax).forEach(System.out::println);
}
}
这是 Lombok 的已知限制还是我做错了什么?
可行但不适用于我的情况的解决方法:
- 将 maxCount 声明为静态。
- 声明 BiPredicate 并发送 maxCount 和 num 参数。
问题在于您调用 Lombok 生成器的方式。
而不是
NumCheck numCheck = new NumCheck().toBuilder().maxCount(10).build()
;
你应该使用:
NumCheck numCheck = NumCheck.builder().maxCount(10).build();
前者使用 no-arg 构造函数创建一个实例,然后从中创建一个构建器,并使用构建器创建第二个实例,该实例被丢弃(未分配给变量)。
后者只是通过构建器创建一个实例,并将其分配给变量。
您应该问问自己 isLessThanMax
是否真的可以通过构建器设置。在我看来更像是一个不变的定义。如果是这样的话,你应该做到 final
。 Lombok 在生成构建器时忽略带有初始值设定项的 final
字段。
(在这种情况下,您也不需要 @Builder.Default
。但是,@Builder.Default
在字段上没有任何问题。性能或内存影响完全为零。)
如果您对为什么您的代码表现如此奇怪感兴趣,请查看此处的解释。
当使用 no-args 构造函数实例化时,isLessThanMax
使用对此实例的字段 maxCount
的引用进行初始化。 maxCount
默认为 0
。然后调用 toBuilder()
,它只是将实例的所有值复制到构建器。最后,您对该构建器调用 maxCount(10).build()
。生成的第二个实例将具有 maxCount = 10
,但与第一个实例的 isLessThanMax
值完全相同。这意味着第二个实例的谓词仍然引用第一个实例的字段,即0
。因此,即使您为第二个实例设置 maxCount = 10
,Predicate
仍会使用第一个实例中的 maxCount = 0
值进行比较。
tl;dr:不要将引用实例字段的方法引用与 toBuilder()
.