Как называется функция, которая не принимает аргументов и ничего не возвращает? [закрыто]

80

В java.util.functionпакете Java 8 мы имеем:

  • Функция : принимает один аргумент, выдает один результат.
  • Потребитель : принимает один аргумент, ничего не производит.
  • Поставщик : не принимает аргументов, дает один результат.
  • ... : другие случаи обработки примитивов, двух аргументов и т. Д.

Но мне нужно разобраться с делом «не принимает аргументов, ничего не производит ».

Там нет ничего для этого в java.util.functionnal.

Итак, вопрос в следующем:

Как называется « функция, которая не принимает аргументов и ничего не возвращает »?

В Java 8 его определение будет следующим:

@FunctionalInterface
public interface InsertANameHere {
    void execute();
}

Исполнитель уже существует и имеет другое назначение: « Объект, выполняющий отправленные выполняемые задачи ». Подпись не соответствует ( execute(Runnable):void) и даже не является функциональным интерфейсом .

Runnable существует, но он тесно связан с контекстом потоков:

  • Пакет есть java.lang, нет java.util.function.
  • Javadoc заявляет: « Интерфейс Runnable должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком ».
  • Название «Runnable» указывает на некоторый работающий код внутри потока.
SuperBob
источник
28
«Но нет ничего для« Не принимает аргументов, ничего не производит ».» - Runnable ?
user11153
11
Я думаю, что javadoc для Runnableявляется устаревшим в этой точке, потому что Runnable также используется другими классами, чем Thread( Executorнапример).
SpaceTrucker
13
@superbob Это не значит, что Runnables может быть .run()только Threads. На самом деле они очень часто используются именно для цели, описанной в вопросе
blgt
5
@superbob Это было его первоначальное назначение, но начиная с Java 8 он был «модифицирован» как функциональный интерфейс. Вот почему вы ничего не нашли в java.util.function упаковке.
user11153
5
Semi-Snark: ImpureFuntion, потому что он, безусловно, опирается только на побочные эффекты, в противном случае это неоперация. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Более серьезно: императив (сделать что-то), который по крайней мере соответствует семантике void execute ();
Кристиан Х

Ответы:

71

Выбор Java сделать это таким образом с отдельным именем для каждой арности был глупым. Это не стоит подражать. Тем не менее, если вам нужно для согласованности или если вы пишете очень общий библиотечный код, предложения Конрада хороши. Я мог бы бросить Procedureв ринг.

Использование псевдо-функциональной парадигмы не означает, что нормальные принципы именования должны выходить за рамки. Интерфейсы почти всегда должны называться в соответствии с тем, что они делают , а не с какой-то общей синтаксической идеей. Если функции помещены в стек отмены, они должны быть названы UndoFunction. Если они вызываются из событий GUI, они должны быть названы GUIEventHandler. Друзья не позволяют друзьям увековечивать плохие соглашения об именах.

Карл Билефельдт
источник
Procedureтоже хорошо. Для контекста я разрабатываю универсальную библиотеку, которая должна обрабатывать такого рода «структуру».
Супербоб
18
Мне нравятся Procedureмои паскальные дни. А Procedureимеет побочные эффекты, а Functionнет. Поскольку вы не возвращаете значение, единственное, что он может сделать, - это побочный эффект.
Спенсер Рэтбун
Я мог бы быть склонен использовать ProcedureRIR<T1,T2>для void proc(T1, int, T2), а также для других типов - вероятно, создавая большинство из них по требованию, а не пытаться втиснуть в каждую возможную комбинацию типов.
суперкат
1
Действительно, настоящее функциональное программирование обычно не поощряет именования в венгерском стиле. Это скорее менталитет парадигмы, а не функциональность.
slebetman
3
If the functions are placed into an undo stack, they should be named UndoFunction.Существует разница между именованием функции и присвоением ей другого типа. В функциональном стиле вы бы не создать UndoFunctonтип , потому что теперь вы не можете передать его flip, curry, compose, filter, mapи т.д. На мой взгляд , что является истинной причиной решения Java, чтобы дать функции с различными арностей разные имена глупа. Конечно, если вы собираетесь использовать побочные эффекты, называйте это как угодно; Вы уже выбросили композицию из окна, и вы, вероятно, тоже не используете функции.
Довал
33

В мире Java это называется Runnable. В мире C # это называется Action.

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

Более широкий взгляд на вещи наступит позже, когда вы решите, что помимо вашего функционального интерфейса void без параметров вам также необходимо иметь аналогичные функциональные интерфейсы, которые принимают один, два или более аргументов или которые возвращают значение. Когда это произойдет, вы захотите, чтобы имена всех этих сущностей были изоморфными и соответствовали друг другу.

Итак, в Java у меня есть собственный набор функциональных интерфейсов, который я называю Procedures, который определяется следующим образом:

public interface Procedure
{
    void invoke();
}

public interface Procedure1<T1>
{
    void invoke( T1 argument1 );
}

... (вы получите картину.)

И у меня также есть подобный набор интерфейсов, называемых Functions, определенных подобным образом, с первым универсальным параметром, являющимся типом возврата:

public interface Function<R>
{
    R invoke();
}

public interface Function1<R,T1>
{
    R invoke( T1 argument1 );
}

Итак, моя точка зрения в том, что Procedureэто очень хорошее имя, потому что оно хорошо вписывается в более широкий взгляд на вещи. Если позже вы решите использовать аналогичные функциональные интерфейсы с методами, которые принимают аргументы или возвращают значение, вы столкнетесь с этим.

ПРИМЕЧАНИЕ: я в основном согласен с утверждением Карла Билефельдта о том, что «нормальные принципы именования не должны выходить за рамки» и что «интерфейсы почти всегда должны называться в соответствии с тем, что они делают, а не с какой-то общей синтаксической идеей». Но учтите, что даже он учитывает «почти всегда». Иногда нужны (по сути, анонимные) процедуры и функции, и это то, о чем спрашивает ОП, и именно на это я отвечаю.

Поправка 2017-11-10:

Вы можете спросить, почему Function1<R,T1>вместо Function1<T1,R>? Это может произойти в любом случае, но у меня есть предпочтение для возвращаемых значений слева, потому что я предпочитаю следовать соглашению об именах 'convert-from' (destination-from-source), а не 'convert-to' (source-to) конвенция. (На самом деле это скорее случайность, чем соглашение, в том смысле, что, скорее всего, никто никогда не задумывался об этом, потому что, если бы они вообще об этом думали, они бы пришли к соглашению «новообращенных»). )

Я читал об этом в статье Джоэла Сполкси - «Как неправильный код выглядит неправильно» , это очень длинная статья, которую я рекомендую прочитать полностью, но если вы хотите перейти непосредственно к конкретному случаю, найдите «TypeFromType», но чтобы дать вам TL; DR, идея в том, что myint = intFromStr( mystr )это намного лучше, чем myint = strToInt( mystr ), потому что в первом случае имена типов близки к связанным значениям, так что вы можете легко увидеть, что 'int' совпадает с 'int' и «str» совпадает с «str».

Поэтому, как правило, я упорядочиваю вещи так, как они будут выглядеть в коде.

Майк Накис
источник
1
Это решение действительно хорошо, оно кажется даже более пуленепробиваемым, чем собственный поставщик Java, Consumer, BiFunction, ..., потому что оно сводит все только к двум концепциям. Это напоминает мне ответ @Karl Bielefeldt о «желании Java сделать это таким образом с отдельным именем для каждой арности [которая] была глупой ». Единственным недостатком является то, что он не обрабатывает примитивные типы и их комбинации (такие забавные вещи, как DoubleToLongFunction, ToLongBiFunction, ...). Но примитивы - это еще одна проблема ...
супербоб
Да. По сути, как только вы начинаете заменять универсальные элементы примитивами, это означает, что вы действительно заботитесь о производительности, так что все будет в порядке, если вы отклоняетесь от соглашения, представленного здесь, и используете сильно настроенные имена для улучшения пользовательской производительности.
Майк Накис
1
Если бы я мог принять 2 - й ответа, я бы выбрал Yours благодаря процессуальному N , функция N предложения. Я все еще проголосовал за это.
супербоб
Почему это не так Function1<T1, R>?
ErikE
@ErikE это очень хороший вопрос, и я исправил свой пост, чтобы ответить на него.
Майк Накис
18

Почему нет Command? Учитывая, что он не принимает никаких данных и не возвращает никаких данных, но при условии, что его вызов вызывает некоторый эффект (в противном случае это было бы довольно бессмысленно), я представляю, что это примерно единственное, что он может сделать - запустить действие, заставить что-то произойти.

Кстати, Actionв .NET также есть общий делегат. В отличие от Java, Consumerон может принимать от 0 до 16 аргументов; другими словами, самая простая версия этого не берет - см. MSDN .

И поскольку имя не подразумевает, что есть что-то, что можно «потреблять», оно также кажется хорошим выбором имени.

Конрад Моравский
источник
1
Commandэто хорошо. Его можно спутать с шаблоном Command, но это может быть решением.
Супербоб
7
Мне нравится Actionбольше, чем Command. Команда звучит больше как что-то, что принимается и оценивается, в то время как действие выполняется для ее побочных эффектов.
Берги
7
Хм ... как это не может быть шаблон командования? Вы создали именно командную сущность! У него даже есть традиционно названный execute()метод. 0_o '
хиджарский
1
Не нравится предложение Action, поскольку это обычный (и хороший) интерфейс Swing. Командование разумно.
user949300
@ user949300, но это зависит от контекста - вы видите, Java - это большой мир, я - разработчик для Android (сейчас), и у меня нет особенностей, связанных с J2EE;) Я согласен, конечно, что выбранное соглашение об именах не должно конфликтовать с тем, который использует ваш фреймворк.
Конрад Моравский