Это слишком дорого, чтобы сделать (Runnable & Serializable), когда вы хотите отправить анонимную функцию?
Я делаю sht, как:
executor.execute((Runnable & Serializable)func);
Где func является анонимной функцией, я должен активно использовать это в проекте, иначе мне пришлось бы создавать класс для каждой другой функции, которую я хочу вызвать, и реализовывать Runnable и Serializable в каждом из этих классов, преимуществом было бы то, что у меня был бы тип во время компиляции, а не приведение его во время выполнения, я хотел бы знать, является ли выполнение этого приведения слишком дорогостоящим или тривиальным и не представляет большого разрыва в производительности.
Если у вас есть реальный жизненный опыт по этому вопросу, и вы готовы поделиться им, это было бы потрясающе.Заранее благодарю.
3 ответа:
Кастинг "почти тривиален" в том смысле, что он только проверяет, что данный объект расширяет некоторый класс или реализует интерфейс - он не изменяет сам объект.
В вашем случае, если
func
обозначает лямбда-выражение или ссылку на методexecutor.execute((Runnable & Serializable) () -> System.out.println("5")); executor.execute((Runnable & Serializable) System.out::println);
LambdaMetafactory гарантирует, что сгенерированный лямбда-объект действительно реализует
Runnable
иSerializable
, и приведение может даже быть оптимизировано.Если, однако,
func
является параметром для вашего метод:public void execute(Runnable func) { executor.execute((Runnable & Serializable)func); }
Ни компилятор java, ни среда выполнения java каким-то волшебным образом не сделают
func
Сериализуемым.В этом случае вы можете переписать свой метод как
public <T extends Runnable & Serializable> void execute(T func) { executor.execute(func); }
Который требует, чтобы вызывающий объект предоставил запускаемый и сериализуемый объект - либо автоматически созданный (через лямбда-выражение или ссылку на метод), либо "вручную" закодированный класс.
В большинстве случаев выполнение любой операции во время выполнения оказывается более дорогостоящим, чем ее альтернатива времени компиляции. Есть случаи, когда это не так, но в основном JVM делает лучшую работу. В большинстве случаев, когда я видел такие реализации,это было более дорогостоящим. В конце концов, это действительно будет зависеть от количества задач, которые вы будете выполнять. Если их много, я бы рекомендовал использовать интерфейс или абстракцию здесь. Что-то вроде этого ....
public interface RunnableSerializable extends Runnable, Serializable { // override and add as necessary } public class MyRunnableClass implementes RunnableSerializable { // your runnable code } MyRunnableClass clazz = ... executor.execute(clazz);
Если его просто очень мало из запускаемые каждые несколько минут (или больше), приведение типов должно быть в порядке.
Приведение само по себе очень тривиально: это просто if-else, который будет оптимизирован JIT и предсказателем ветвей, потому что вы все время передаете допустимые классы (Вы не видите никаких ClassCastException).
Я думаю, что реальный вопрос здесь, Если есть какая-либо разница между выполнением (путем создания виртуального вызова через интерфейс через Runnable.run ()) анонимный лямбда-код или объявленный класс. Поэтому я установил тестовый тест JMH для тестирования 3 следующих случаев с использованием лямбд и объявил классы:
- выполнить материал
- выполнять произвольно разные вещи (чтобы предотвратить предсказание ветвей, если таковые имеются)
- выполнять произвольно разные вещи, но некоторые вещи будут происходить чаще (чтобы позволить предсказание ветвей, если таковые имеются)
Результат показывает, что лямбды медленнее на несколько наносекунд, поэтому на самом деле нет никакой разницы между labmda или объявленным классом вообще:
Benchmark Mode Cnt Score Error Units MyBenchmark.testAnonymousLambda sample 7272891 16.150 ± 1.646 ns/op MyBenchmark.testDeclared sample 7401499 15.349 ± 3.648 ns/op MyBenchmark.testRandomAnonymousLambda sample 6851255 3314.151 ± 11.655 ns/op MyBenchmark.testRandomBranchingDeclared sample 6887926 3293.818 ± 9.180 ns/op MyBenchmark.testPredictableAnonymousLambda sample 3990711 6091.766 ± 25.912 ns/op MyBenchmark.testPredictableBranchingDeclared sample 3993885 6055.421 ± 21.535 ns/op
Так что в ответ на ваш вопрос не имеет значения, будете ли вы бросать, или если вы бы использовали лямбду вместо того, чтобы создавать набор объявленных классов.
С. П. контрольный код доступен через суть