Предоставляют ли библиотеки JDK служебный класс лямбда-вызывателя?

Я хочу заменить потребность в отдельных автономных статических функциях инициализации лямбда-выражениями. например Я бы хотел заменить что-то подобное...

class Foo {
    private static final Set<String> keywords = keywords();

    private static Set<String> keywords() {
        HashSet<String> s = new HashSet<>();
        s.add("AND");
        s.add("NOT");
        s.add("OR");
        return Collections.unmodifiableSet(s);
    }
}

С чем-то, что вызывает лямбду, определенную на месте во время загрузки класса. Обратите внимание, я не ставлю перед собой цель вызывать это лениво.

На данный момент я создал простой класс Initializer со статическим методом, который принимает Supplier, вызывает его и возвращает значение.

Initializer класс

public class Initializer {
    public static <T> T init(Supplier<T> initializer) {
        return initializer.get();
    }    
}

Затем в другом классе:

import static com.whatever.Initializer.init;

class Foo {
    private static final Set<String> keywords = init(() -> {
        HashSet<String> s = new HashSet<>();
        s.add("AND");
        s.add("NOT");
        s.add("OR");
        return Collections.unmodifiableSet(s);
    });
}

Есть ли что-то, что уже существует в стандартных библиотеках Java, так что мне не нужно предоставлять свой собственный класс Initializer, или есть какой-то способ просто определить, а затем выполнить лямбду на месте?


person Bill    schedule 31.10.2015    source источник
comment
Вам не нужен метод для инициализации keywords. В чем смысл вашей лямбда-версии?   -  person a better oliver    schedule 31.10.2015
comment
Зачем именно здесь нужны лямбды? Похоже, вам просто нужен статический блок инициализатора ( static { } ) и вызывать там свои инициализации?   -  person Zhedar    schedule 31.10.2015
comment
Связано: Как инициализировать карту с помощью лямбда-выражения?   -  person Didier L    schedule 02.11.2015


Ответы (3)


Вы можете просто привести лямбду и вызвать ее:

private static final Set<String> KEYWORDS = ((Supplier<Set<String>>) () -> {
    Set<String> result = new HashSet<>();
    ...
    return Collections.unmodifiableSet(result);
}).get();

Или вы можете использовать существующие ярлыки:

private static final Set<String> KEYWORDS = 
    Collections.unmodifiableSet(new HashSet<>(Arrays.asList("AND", "NOT", "OR")));

Но ваш исходный код, вызывающий метод, очень удобочитаем. Я бы не изменил его.

person JB Nizet    schedule 31.10.2015
comment
В этом конкретном случае, среди прочего, я люблю коллекции Guava: KEYWORDS = ImmutableSet.of("AND", "NOT", "OR") - person JB Nizet; 31.10.2015
comment
Я до сих пор не получаю преимуществ от использования этого лямбда-выражения по сравнению с обычным статическим инициализатором. По сути, это даже не отличается от первоначального подхода к вопросу, поскольку код по-прежнему находится внутри статического метода, теперь уже синтетического. Только то, как он вызывается, имеет здесь больше накладных расходов. - person Holger; 02.11.2015
comment
@ Хольгер, я согласен на 100%. Я просто хотел показать, что это возможно. Но, как говорится в моем ответе, я нахожу исходный код более читаемым и не стал бы его менять. - person JB Nizet; 02.11.2015
comment
Верно, я это понял и не к вам обращался. Я поместил комментарий под вашим ответом вместо вопроса, потому что ваш ответ был принят, поэтому ОП сказал, что решил его настоящую проблему, но все еще неясно, каким образом (или в чем заключалась реальная проблема)… - person Holger; 02.11.2015
comment
@JBNizet Вас может заинтересовать JEP 269 — удобные фабричные методы для коллекций для Java 9! - person mkobit; 02.11.2015

Я бы написал просто специальный служебный метод, который делает всю цепочку:

public class Sets {
    public static <T> Set<T> of(T... elements) {
        return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(elements)));
    }
}

И используйте его там, где это необходимо:

private static final Set<String> KEYWORDS = Sets.of("AND", "NOT", "OR");

Если вы используете Guava, у вас уже есть множество таких методов. Надеюсь, такая функция появится в Java-9. Существует JEP 269, который позволяет писать Set.of("AND", "NOT", "OR").

person Tagir Valeev    schedule 31.10.2015
comment
Хотя это полезно для коллекций, это не для других видов инициализации. - person Bill; 01.11.2015
comment
@Bill, если другой вид инициализации (каким бы он ни был) не может быть выполнен в одном выражении, возможно, вместо этого его следует реорганизовать. Рассмотрите возможность создания новых конструкторов, фабричных методов или реализации шаблона построителя. Я считаю, что гораздо лучше решить эту проблему для каждого случая, чем создавать обобщенное решение, которое в любом случае уродливо. - person Tagir Valeev; 01.11.2015

Как уже упоминал @zeroflagL, вам не нужно использовать лямбда-выражения в этом месте. Вы можете инициализировать keywords в одной строке, используя:

Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("AND", "NOT", "OR")));

Но это не так красиво. В противном случае, что не так с использованием блока static? Он создан для таких вещей.

Но если вы не хотите его использовать, я думаю, что стандартного метода нет. Вы должны использовать свой Initializer.

person Fabian Damken    schedule 31.10.2015