Reputation: 526
I am initializing a class via Lombok Builder. Through which I am initializing a variable. But that's variable's value is not available when I use that in a Predicate definition.
My code looks this:
@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);
}
}
While debugging, the value of maxCount was not getting initialized to 10. It remained 0.
If I remove the Lombok builders and do it in normal way, this is working fine:
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);
}
}
Is it a known limitation of Lombok or am I doing anything wrong here?
Workarounds that worked but not applicable for my scenario:
Upvotes: 1
Views: 478
Reputation: 8142
You should ask yourself whether the isLessThanMax
should really be settable via the builder. It seems to me more like a constant definition. If that is the case, you should make it final
. Lombok ignores final
fields with an initializer when generating the builder.
(You also don't need @Builder.Default
in this case. However, there is nothing wrong with @Builder.Default
on fields. There is exactly zero performance or memory impact.)
If you are interested why your code behaves so strange, here's the explanation.
When instantiating using the no-args constructor, isLessThanMax
is initialized using a reference to the field maxCount
of this instance. maxCount
is defaulted to 0
. Then you call toBuilder()
, which simply copies all values of the instance to the builder. Finally you call maxCount(10).build()
on that builder. The resulting second instance will have maxCount = 10
, but exactly the same isLessThanMax
value than the first instance. That means that the predicate of the second instance still references the field of the first instance, which is 0
. So even though you set maxCount = 10
for the second instance, the Predicate
still compares using the maxCount = 0
value from the first instance.
tl;dr: Don't use method references that reference instance fields in combination with toBuilder()
.
Upvotes: 1
Reputation: 30088
The problem is the way that you're invoking the Lombok builder.
Instead of
NumCheck numCheck = new NumCheck().toBuilder().maxCount(10).build()
;
you should use:
NumCheck numCheck = NumCheck.builder().maxCount(10).build();
The former creates an instance using the no-arg constructor, then creates a builder from that, and uses the builder to create a second instance, which is thrown away (not assigned to a variable).
The latter just creates one instance via the builder, and assigns it to the variable.
Upvotes: 0