Метод Java 8 requireNonNull с производительностью параметра поставщика

Метод Objects.requireNonNull с добавлением Supplier в Java 8, но я не уверен, в чем заявлено улучшение производительности:

Хотя это может дать преимущество в производительности в случае, отличном от null, при принятии решения о вызове этого метода следует позаботиться о том, чтобы затраты на создание поставщика сообщений были меньше, чем затраты на просто создание строковое сообщение напрямую.

Метод со строкой игнорирует параметр, если он не нулевой:

public static <T> T requireNonNull(T obj, String message) {
    if (obj == null)
        throw new NullPointerException(message);
    return obj;
}

Я нашел JDK-8011800: добавить java.util.Objects.requireNonNull(T, поставщик )

В JDK 7 java.util.Objects включал несколько методов для проверки на нуль, в том числе один, который принимал сообщение для возврата, если был найден нуль. С лямбда-выражениями в JDK 8 другим вариантом, который следует включить, является метод requireNonNull, который принимает поставщика строки вместо строки. Вот почему можно избежать затрат на создание строкового сообщения для ненулевого случая. Обратите внимание, что сбор лямбда-выражений может иметь ненулевую стоимость.

Комментарий указывает на отсутствие влияния на производительность:

Меня беспокоит ненулевая стоимость захвата. Я обеспокоен тем, что это часто сводит на нет все преимущества использования Поставщика. 04-09-2013

Я нашел другие вопросы, но не ссылался на (почему) отправка параметра String имеет затраты на производительность.

Это специфично для использования лямбда-выражений/потока?


person user7294900    schedule 16.01.2019    source источник
comment
вероятно предназначено для случая, когда создание String не является тривиальным (связанным с производительностью), например, вызовом дорогого метода - на основе последней части ... поставщик сообщений меньше, чем стоимость простого создания строкового сообщения напрямую   -  person user85421    schedule 16.01.2019
comment
@CarlosHeuberger, вы имеете в виду, что строку нужно построить, например, с помощью StringBuilder? Вы можете расширить ответ?   -  person user7294900    schedule 16.01.2019
comment
Подумайте о сложном сообщении об ошибке, включая информацию о состоянии программы.   -  person Marco    schedule 16.01.2019
comment
StringBuilder (или + конкатенация), String.format и, как я добавил к моему комментарию, вызов некоторых других методов (этот метод позволяет отложить создание сообщения до тех пор, пока не будет выполнена проверка на null) - если проверено объект не нулевой, нет необходимости создавать сообщение, но если метод получает сообщение в виде строки, это уже сделано   -  person user85421    schedule 16.01.2019
comment
Именно та часть документации, которая намекает на то же самое: В отличие от метода requireNonNull(Object, String), этот метод позволяет отложить создание сообщения до тех пор, пока не будет выполнена проверка null   -  person Naman    schedule 16.01.2019
comment
@user7294900 user7294900 можешь попытаться объяснить, что тебе непонятно? Создание Supplier требует определенных затрат производительности, как и создание String. Создание простой строки может быть дешевле, чем создание файла Supplier. Но если создание String по какой-то причине требует дорогостоящих операций и предполагается, что null встречается редко, может быть лучше создать поставщика и вызывать эти дорогостоящие операции только тогда, когда они действительно необходимы.   -  person Hulk    schedule 16.01.2019
comment
Тем не менее, до сих пор я никогда не сталкивался с необходимостью использовать перегрузку Supplier. Типичным вариантом использования является выполнение проверки параметров вещей, которые никогда не должны быть нулевыми, и для таких случаев обычно достаточно очень краткого постоянного сообщения.   -  person Hulk    schedule 16.01.2019
comment
@Hulk да, кажется, очень специфические случаи, вероятно, встречаются при разработке Java 8.   -  person user7294900    schedule 16.01.2019
comment
Если примеры с конкатенацией строк или использованием средства форматирования вас не убеждают, подумайте о загрузке сообщений из пакета ресурсов.   -  person Holger    schedule 16.01.2019


Ответы (1)


Рассмотрим это, где generateString делает много вещей, чтобы сгенерировать строку из someParam:

Objects.requireNonNull(obj, generateString(someParam));

В Java аргументы обрабатываются с готовностью, а это означает, что generateString будет оцениваться до вызова requireNonNull. Поэтому он вычисляется независимо от того, является ли obj нулевым или нет.

Вы можете решить эту проблему, изменив ее на это:

Objects.requireNonNull(obj, () -> generateString(someParam));

В этом случае generateString будет вызываться только в том случае, если obj на самом деле было нулевым. Это более эффективно, когда generateString обходится дороже, чем создание объекта Supplier.

Вы должны просто использовать обычный метод, отличный от лямбда, если ваш параметр String является просто литералом, например:

Objects.requireNonNull(obj, "obj was null!");
person marstran    schedule 16.01.2019
comment
Есть ли способ определить баланс между расходами на создание строки и расходами на создание поставщика? - person Mukund Jalan; 15.06.2020