JAVA 8 Извлечь предикаты как поля или методы?
Что является более чистым способом извлечения предикатов, которые будут иметь многократное использование. Методы или классовые поля?
Два примера:
1. Класс Поле
void someMethod() {
IntStream.range(1, 100)
.filter(isOverFifty)
.forEach(System.out::println);
}
private IntPredicate isOverFifty = number -> number > 50;
2.Method
void someMethod() {
IntStream.range(1, 100)
.filter(isOverFifty())
.forEach(System.out::println);
}
private IntPredicate isOverFifty() {
return number -> number > 50;
}
Для меня полевой путь выглядит немного лучше, но так ли это? У меня есть сомнения.
3 ответа
Обычно вы кэшируете вещи, которые дорого создавать, а эти лямбды без сохранения состояния - нет. Лямбда без сохранения состояния будет иметь один экземпляр, созданный для всего конвейера (в соответствии с текущей реализацией). Первый вызов самый дорогой - основной Predicate
класс реализации будет создан и связан; но это происходит только один раз для лямбд без гражданства и с состоянием.
Лямбда с состоянием будет использовать разные экземпляры для каждого элемента, и, возможно, имеет смысл их кэшировать, но ваш пример не содержит состояний, поэтому я бы не стал.
Если вы все еще хотите это (для целей чтения я предполагаю), я бы сделал это в классе Predicates
давайте предположим. Он также может быть повторно использован для разных классов, примерно так:
public final class Predicates {
private Predicates(){
}
public static IntPredicate isOverFifty() {
return number -> number > 50;
}
}
Вы также должны заметить, что использование Predicates.isOverFifty
внутри потока и x -> x > 50
хотя семантически то же самое, будет иметь различное использование памяти.
В первом случае только один экземпляр (и класс) будет создан и обслужен всем клиентам; пока второе (x -> x > 50
) создаст не только разные экземпляры, но и разные классы для каждого из своих клиентов (представьте, что одно и то же выражение используется в разных местах вашего приложения). Это происходит потому, что связь происходит за CallSite
- а во втором случае CallSite
всегда отличается.
Но это то, на что вы не должны полагаться (и, возможно, даже учитывать) - эти Объекты и классы быстро создаются и быстро удаляются GC - независимо от того, что соответствует вашим потребностям - используйте это.
Чтобы ответить, лучше, если вы расширите те лямбда-выражения для старомодной Java. Теперь вы можете видеть, что это два способа, которые мы использовали в наших кодах. Итак, ответ таков: все зависит от того, как вы пишете определенный сегмент кода.
private IntPredicate isOverFifty = new IntPredicate<Integer>(){
public void test(number){
return number > 50;
}
};
private IntPredicate isOverFifty() {
return new IntPredicate<Integer>(){
public void test(number){
return number > 50;
}
};
}
1) Для полевого случая вы всегда будете выделять предикат для каждого нового вашего объекта. Ничего страшного, если у вас есть несколько экземпляров, лайки, сервис. Но если это объект значения, который может быть N, это не хорошее решение. Также имейте в виду, что someMethod()
не может быть вызван вообще. Одним из возможных решений является сделать предикат как static
поле.
2) Для случая метода вы создадите предикат один раз каждый раз для someMethod()
вызов. После GC откажется от него.