'Boolean value remains false after the value of the static field involved changes

In my assignment I have to use an enum to make an EnumSet of elements that fit the criteria given. So, the code needs to be as flexible as possible and allow any criteria that could be applied to the object declared in the enum.

I've been testing things out, my code involves taking the finals of the enum into the static context, so that a boolean can be applied to them, and then looping through each declared object in the enum to see if they fit the criteria. For some reason though, the state of the boolean doesn't change to true, when the value of the static fields fit the criteria.

Here is my code:

public class test {
// enumeration of persons by age and sex
    enum Name {
        
        Adam("Male", 17),
        Amy("Female", 24),
        Boris("Male", 12),
        Bella("Female", 16);
        
        final String _sex;
        final int _age;
// static variants to "turn" values to the static context
        volatile static String sex = "";
        volatile static int age = 0;
        
        Name(String sex, int age) {
            _sex = sex;
            _age = age;
        }
    }
    public static void main(String[] args) {
// creating a set of people older than 17
        EnumSet<Name> set = makeSet(Name.age >= 17);
        System.out.print(set.toString());
    }
    static EnumSet<Name> makeSet(boolean query) {
        EnumSet<Name> set = EnumSet.noneOf(Name.class);
        for (Name element : Name.values()) {
// this is the "turning" of the values to the static context
            Name.sex = element._sex;
            Name.age = element._age;
// PROBLEM LIES HERE
// the query remains false, even when age is above 17
            if (query) {
                set.addAll(EnumSet.of(element));
            }
        }
        return set;
    }
}

Changing the static fields to volatile doesn't fix the problem either, so I don't think it's a caching issue.

So, why does the boolean not update? Is there a work-around?



Solution 1:[1]

Answered in comments by @Turing85

The problem occurred because the boolean is being passed by value. Using a Predicate instead of just a boolean fixed the problem, because the object reference would be passed on instead, allowing the value to change after the makeSet() method was invoked.

Furthermore, this eliminates the need to take the finals of the enum into the static context.

Here is my code now:

public class test {
// enumeration of persons by age and sex
    enum Name {
        
        Adam("Male", 17),
        Amy("Female", 24),
        Boris("Male", 12),
        Bella("Female", 16);
        
        final String sex;
        final int age;
        
        Name(String sex, int age) {
            this.sex = sex;
            this.age = age;
        }
    }
    public static void main(String[] args) {
// creating a set of people older than 17
        EnumSet<Name> set = makeSet(query -> query.age >= 17);
        System.out.print(set.toString());
    }
    static EnumSet<Name> makeSet(Predicate<Name> query) {
        EnumSet<Name> set = EnumSet.noneOf(Name.class);
        for (Name element : Name.values()) {
// PROBLEM FIXED
            if (query.test(element)) {
                set.addAll(EnumSet.of(element));
            }
        }
        return set;
    }
}

Solution 2:[2]

The problem you are facing is that the predicate (Name.age >= 17) is checked at the moment of the function call:

When you are calling makeSet(Name.age >= 17), what actually happens is, the predicate returns a boolean, which at the time of checking returns false, and false is therefore parsed into the function.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Daan Sneep