Поддерживает ли Java значения параметров по умолчанию?
Я наткнулся на некоторый код Java, который имел следующую структуру:
public MyParameterizedFunction(String param1, int param2)
{
this(param1, param2, false);
}
public MyParameterizedFunction(String param1, int param2, boolean param3)
{
//use all three parameters here
}
Я знаю, что в C++ я могу присвоить параметру значение по умолчанию. Например:
void MyParameterizedFunction(String param1, int param2, bool param3=false);
Поддерживает ли Java этот вид синтаксиса? Есть ли причины, по которым этот двухэтапный синтаксис предпочтительнее?
28 ответов
Нет, структура, которую вы нашли, - это то, как Java обрабатывает ее (то есть с перегрузкой вместо параметров по умолчанию).
Конструкторы см. В статье 1 "Эффективная Java: Руководство по языку программирования" (рассмотрим статические фабричные методы вместо конструкторов), если перегрузка усложняется. Для других методов может помочь переименование некоторых случаев или использование объекта параметра. Это когда у вас достаточно сложности, чтобы дифференцировать трудно. Определенный случай, когда вы должны различать, используя порядок параметров, а не только число и тип.
Нет, но вы можете использовать шаблон Builder, как описано в ответе на переполнение стека.
Как описано в связанном ответе, шаблон Builder позволяет писать код
Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
.name("Spicoli")
.age(16)
.motto("Aloha, Mr Hand")
.buildStudent();
в котором некоторые поля могут иметь значения по умолчанию или иным образом быть необязательными.
Есть несколько способов симулировать параметры по умолчанию в Java:
Метод перегрузки.
void foo(String a, Integer b) { //... } void foo(String a) { foo(a, 0); // here, 0 is a default value for b } foo("a", 2); foo("a");
Одним из ограничений этого подхода является то, что он не работает, если у вас есть два необязательных параметра одного типа, и любой из них может быть опущен.
Спеременным числом аргументов.
а) Все необязательные параметры имеют одинаковый тип:
void foo(String a, Integer... b) { Integer b1 = b.length > 0 ? b[0] : 0; Integer b2 = b.length > 1 ? b[1] : 0; //... } foo("a"); foo("a", 1, 2);
б) Типы необязательных параметров могут быть разными:
void foo(String a, Object... b) { Integer b1 = 0; String b2 = ""; if (b.length > 0) { if (!(b[0] instanceof Integer)) { throw new IllegalArgumentException("..."); } b1 = (Integer)b[0]; } if (b.length > 1) { if (!(b[1] instanceof String)) { throw new IllegalArgumentException("..."); } b2 = (String)b[1]; //... } //... } foo("a"); foo("a", 1); foo("a", 1, "b2");
Основным недостатком этого подхода является то, что если дополнительные параметры имеют разные типы, вы теряете статическую проверку типов. Кроме того, если каждый параметр имеет разное значение, вам нужен какой-то способ их различения.
Нулевые. Чтобы устранить ограничения предыдущих подходов, вы можете разрешить нулевые значения, а затем проанализировать каждый параметр в теле метода:
void foo(String a, Integer b, Integer c) { b = b != null ? b : 0; c = c != null ? c : 0; //... } foo("a", null, 2);
Теперь все значения аргументов должны быть предоставлены, но значения по умолчанию могут быть нулевыми.
Необязательный класс. Этот подход аналогичен пустым значениям, но использует необязательный класс Java 8 для параметров со значением по умолчанию:
void foo(String a, Optional<Integer> bOpt) { Integer b = bOpt.isPresent() ? bOpt.get() : 0; //... } foo("a", Optional.of(2)); foo("a", Optional.<Integer>absent());
Необязательно делает контракт метода явным для вызывающей стороны, однако, такая подпись может оказаться слишком многословной.
Образец строителя. Шаблон Builder используется для конструкторов и реализуется путем введения отдельного класса Builder:
class Foo { private final String a; private final Integer b; Foo(String a, Integer b) { this.a = a; this.b = b; } //... } class FooBuilder { private String a = ""; private Integer b = 0; FooBuilder setA(String a) { this.a = a; return this; } FooBuilder setB(Integer b) { this.b = b; return this; } Foo build() { return new Foo(a, b); } } Foo foo = new FooBuilder().setA("a").build();
Карты. Если число параметров слишком велико и для большинства из них обычно используются значения по умолчанию, вы можете передать аргументы метода в виде карты их имен / значений:
void foo(Map<String, Object> parameters) { String a = ""; Integer b = 0; if (parameters.containsKey("a")) { if (!(parameters.get("a") instanceof Integer)) { throw new IllegalArgumentException("..."); } a = (String)parameters.get("a"); } else if (parameters.containsKey("b")) { //... } //... } foo(ImmutableMap.<String, Object>of( "a", "a", "b", 2, "d", "value"));
Обратите внимание, что вы можете комбинировать любой из этих подходов для достижения желаемого результата.
К сожалению, да.
void MyParameterizedFunction(String param1, int param2, bool param3=false) {}
может быть написано в Java 1.5 как:
void MyParameterizedFunction(String param1, int param2, Boolean... params) {
assert params.length <= 1;
bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}
Но стоит ли вам зависеть от того, как вы относитесь к компилятору, генерирующему
new Boolean[]{}
за каждый звонок.
Для нескольких параметров по умолчанию:
void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}
может быть написано в Java 1.5 как:
void MyParameterizedFunction(String param1, int param2, Object... p) {
int l = p.length;
assert l <= 2;
assert l < 1 || Boolean.class.isInstance(p[0]);
assert l < 2 || Integer.class.isInstance(p[1]);
bool param3 = l > 0 && p[0] != null ? ((Boolean)p[0]).booleanValue() : false;
int param4 = l > 1 && p[1] != null ? ((Integer)p[1]).intValue() : 42;
}
Это соответствует синтаксису C++, который допускает параметры по умолчанию только в конце списка параметров.
Помимо синтаксиса, есть различие, когда в нем есть проверка типов во время выполнения для переданных по умолчанию параметров, а тип C++ проверяет их во время компиляции.
Нет, но вы можете очень легко подражать им. Что в C++ было:
public: void myFunction(int a, int b=5, string c="test") { ... }
В Java это будет перегруженная функция:
public void myFunction(int a, int b, string c) { ... }
public void myFunction(int a, int b) {
myFunction(a, b, "test");
}
public void myFunction(int a) {
myFunction(a, 5);
}
Ранее упоминалось, что параметры по умолчанию вызывали неоднозначные случаи перегрузки функций. Это просто не соответствует действительности, мы можем видеть в случае с C++: да, возможно, он может создавать неоднозначные случаи, но эти проблемы могут быть легко решены. Он просто не был разработан в Java, возможно потому, что создатели хотели гораздо более простой язык, чем был C++ - если они имели право, это другой вопрос. Но большинство из нас не думают, что он использует Java из-за его простоты.
Вы можете сделать это в Scala, которая работает на JVM и совместима с Java-программами. http://www.scala-lang.org/
т.е.
class Foo(var prime: Boolean = false, val rib: String) {}
Вместо того, чтобы использовать:
void parameterizedMethod(String param1, int param2) {
this(param1, param2, false);
}
void parameterizedMethod(String param1, int param2, boolean param3) {
//use all three parameters here
}
Вы можете использовать необязательную функциональность java, имея один метод:
void parameterizedMethod(String param1, int param2, @Nullable Boolean param3) {
param3 = Optional.ofNullable(param3).orElse(false);
//use all three parameters here
}
Основное отличие состоит в том, что вам нужно использовать классы-оболочки вместо примитивных типов Java, чтобы разрешить null
ввод.Boolean
вместо того boolean
, Integer
вместо того int
и так далее.
Нет, но самый простой способ реализовать это:
public myParameterizedFunction(String param1, int param2, Boolean param3) {
param3 = param3 == null ? false : param3;
}
public myParameterizedFunction(String param1, int param2) {
this(param1, param2, false);
}
Или вместо троичного оператора вы можете использовать, если:
public myParameterizedFunction(String param1, int param2, Boolean param3) {
if (param3 == null) {
param3 = false;
}
}
public myParameterizedFunction(String param1, int param2) {
this(param1, param2, false);
}
Я мог бы заявить об очевидном здесь, но почему бы просто не реализовать параметр "по умолчанию" самостоятельно?
public class Foo() {
public void func(String s){
func(s, true);
}
public void func(String s, boolean b){
//your code here
}
}
по умолчанию вы бы использовать эфир
func("моя строка");
и если вы не хотите использовать значение по умолчанию, вы бы использовали
func("моя строка", false);
Он не поддерживается в java, например, на другом языке. Котлин.
Как упоминалось в Scala, стоит упомянуть и Котлина. В параметрах функции Kotlin также могут быть значения по умолчанию, и они могут даже ссылаться на другие параметры:
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
...
}
Как и Scala, Kotlin работает на JVM и может быть легко интегрирован в существующие проекты Java.
Нет. В общем, у Java нет большого (любого) синтаксического сахара, так как они пытались создать простой язык.
Нет.
Вы можете добиться того же поведения, передав Объект, который имеет умные значения по умолчанию. Но опять же, это зависит от того, что у вас под рукой.
Если вы действительно хотите, вы можете проверить это вручную, используя
null
:
public MyParameterizedFunction(String param1, int param2, boolean param3)
{
if(param3 == null) {
param 3 = false;
}
}
Однако я настоятельно рекомендую использовать что-то еще, например, перегрузку или статическую фабрику. Возможно, вам это сойдет с рук, но это может привести к неожиданному поведению. Например, у вас может быть ошибка в вашем коде, так что ваше логическое значение никогда не получит значения. В этом случае вы не получите
NullPointerException
. Вместо этого будет выглядеть так, как будто было установлено значение false, что может сильно сбить с толку при отладке.
Вы можете использовать Java Method Invocation Builder для автоматической генерации компоновщика со значениями по умолчанию.
Просто добавьте @GenerateMethodInvocationBuilder к классу или интерфейсу и @Default к параметрам в методах, где вы хотите использовать значения по умолчанию. Конструктор будет создан во время компиляции, используя значения по умолчанию, которые вы указали в своих аннотациях.
@GenerateMethodInvocationBuilder
public class CarService {
public CarService() {
}
public String getCarsByFilter(//
@Default("Color.BLUE") Color color, //
@Default("new ProductionYear(2001)") ProductionYear productionYear,//
@Default("Tomas") String owner//
) {
return "Filtering... " + color + productionYear + owner;
}
}
И тогда вы можете вызывать методы.
CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
.invoke(instance);
Или установите любое другое значение по умолчанию.
CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
.withColor(Color.YELLOW)//
.invoke(instance);
Это не поддерживается, но есть несколько опций, например использование шаблона объекта параметра с некоторым синтаксическим сахаром:
public class Foo() {
private static class ParameterObject {
int param1 = 1;
String param2 = "";
}
public static void main(String[] args) {
new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
}
private void myMethod(ParameterObject po) {
}
}
В этом примере мы строим ParameterObject
со значениями по умолчанию и переопределить их в разделе инициализации экземпляра класса { param1 = 10; param2 = "bar";}
Попробуйте это решение:
public int getScore(int score, Integer... bonus)
{
if(bonus.length > 0)
{
return score + bonus[0];
}
return score;
}
конструктор как для метода
static void popuping() {
popuping("message", "title");
}
static void popuping(String message) {
popuping(message, "title");
}
static void popuping(String message, String title){
JOptionPane.showMessageDialog(null, message,
title, JOptionPane.INFORMATION_MESSAGE);
}
Сейчас я потратил довольно много времени, чтобы выяснить, как использовать это с методами, которые возвращают значения, и я не видел пока никаких примеров, я подумал, что было бы полезно добавить это здесь:
int foo(int a) {
// do something with a
return a;
}
int foo() {
return foo(0); // here, 0 is a default value for a
}
Аналогичный подход к /questions/18838814/podderzhivaet-li-java-znacheniya-parametrov-po-umolchaniyu/18838866#18838866 который работает в Java 8, заключается в использовании интерфейса с получателями по умолчанию. Это будет более детализированный пробел, но это будет насмешливо, и это здорово, когда у вас есть куча примеров, когда вы действительно хотите привлечь внимание к параметрам.
public class Foo() {
public interface Parameters {
String getRequired();
default int getOptionalInt(){ return 23; }
default String getOptionalString(){ return "Skidoo"; }
}
public Foo(Parameters parameters){
//...
}
public static void baz() {
final Foo foo = new Foo(new Person() {
@Override public String getRequired(){ return "blahblahblah"; }
@Override public int getOptionalInt(){ return 43; }
});
}
}
Вот как я это сделал... возможно, это не так удобно, как иметь "необязательный аргумент" против вашего определенного параметра, но он выполняет свою работу:
public void postUserMessage(String s,boolean wipeClean)
{
if(wipeClean)
{
userInformation.setText(s + "\n");
}
else
{
postUserMessage(s);
}
}
public void postUserMessage(String s)
{
userInformation.appendText(s + "\n");
}
Заметьте, что я могу вызвать одно и то же имя метода либо просто строкой, либо я могу вызвать его со строкой и логическим значением. В этом случае установка wipeClean в значение true заменит весь текст в моей TextArea указанной строкой. Если установить для параметра wipeClean значение false или оставить все вместе, просто добавьте предоставленный текст в TextArea.
Также обратите внимание, что я не повторяю код в этих двух методах, я просто добавляю функциональность возможности сброса TextArea путем создания нового метода с тем же именем только с добавленным логическим значением.
Я на самом деле думаю, что это немного чище, чем если бы Java предоставил "необязательный аргумент" для наших параметров, поскольку нам нужно было бы затем кодировать значения по умолчанию и т. Д. В этом примере мне не нужно беспокоиться об этом. Да, я добавил еще один метод в свой класс, но, по моему скромному мнению, в долгосрочной перспективе его легче читать.
Одна идея - использовать String... args
public class Sample {
void demoMethod(String... args) {
for (String arg : args) {
System.out.println(arg);
}
}
public static void main(String args[] ) {
new Sample().demoMethod("ram", "rahim", "robert");
new Sample().demoMethod("krishna", "kasyap");
new Sample().demoMethod();
}
}
Выход
ram
rahim
robert
krishna
kasyap
из https://www.tutorialspoint.com/Does-Java-support-default-parameter-values-for-a-method
Есть полдюжины или даже больше проблем, таких как эта, в конце концов вы получите статический шаблон фабрики... см. Crypto api для этого. Сортировать сложно объяснить, но подумайте об этом так: если у вас есть конструктор, по умолчанию или другой, единственный способ распространить состояние за пределы фигурных скобок - это иметь логическое значение isValid; (вместе со значением NULL в качестве значения по умолчанию v конструктор с ошибкой) или сгенерировать исключение, которое никогда не будет информативным при получении его от полевых пользователей
Будь проклят код, я пишу тысячи конструкторов строк и делаю то, что мне нужно. Я нахожу использование isValid при построении объектов - другими словами, двух строковых конструкторов - но по какой-то причине я перехожу на статический шаблон фабрики. Я просто думаю, что вы можете многое сделать, если вы в вызове метода, все еще есть проблемы с sync(), но значения по умолчанию можно "заменить" лучше (безопаснее)
Я думаю, что здесь нам нужно решить проблему с нулем как значение по умолчанию для чего-то String one=new String(""); в качестве переменной-члена, затем выполняет проверку на нулевое значение, прежде чем присваивать строку, переданную в конструктор.
Весьма примечательно, что на Яве сделано огромное количество необработанных стратосферных компьютерных наук.
C++ и т. Д. Имеет библиотеки поставщика, да. Java может опередить их на крупных серверах благодаря огромному набору инструментов. Изучите статические блоки инициализатора, оставайтесь с нами.
НЕТ, но у нас есть альтернатива в виде перегрузки функций.
вызывается, когда не передан ни один параметр
void operation(){
int a = 0;
int b = 0;
}
вызывается, когда передается параметр "a"
void operation(int a){
int b = 0;
//code
}
вызывается при передаче параметра b
void operation(int a , int b){
//code
}
Вы можете использовать следующее:
public void mop(Integer x) {
// Define default values
x = x == null ? 200 : x;
}
Прямой ответ - нет.
Эти ответы довольно старые и в основном обсуждают альтернативы, которые мы можем иметь, даже если у java нет прямого пути к параметру метода по умолчанию.
мы можем легко справиться с этим сценарием с помощью функционального программирования в java.
мы можем использовать метод каррирования функционального программирования Java, и я думаю, что его лучше всего использовать для таких сценариев, где нам нужны параметры по умолчанию.
нам может понадобиться параметр по умолчанию в следующих ситуациях... Пример: Создайте метод, который работает с двумя разными объектами и возвращает вычисление
int mutiply(int a,int b){
return a*b;
}
если мы хотим иметь метод умножения на 2, нам придется переопределить метод, как показано ниже.
int mutiply(int a){
mutiply(a, 2); // as can not write mutiply(int a,b=2)
}
Выше 2 — это значение по умолчанию для b, но оно будет исправлено. что, если мы хотим умножить на три, теперь мы не можем больше перегружать это, и кажется странным иметь несколько таких методов.
Это когда мы можем использовать технику каррирования метода.
метод Каррирование — это способ преобразования функций с несколькими параметрами в несколько функций, каждая из которых принимает один параметр.
Шаги для создания метода Curried
Напишите функцию, которая принимает один параметр и возвращает другую функцию, как показано ниже.
Function<Integer,Function<Integer,Integer>> mutiply = a->{ return b -> a*b; };
Давайте упростим и поймем вышеуказанный метод.
Вышеупомянутый метод принимает только один целочисленный аргумент и возвращает другую функцию с одним параметром a в качестве значения по умолчанию и b в качестве переменной. Если вы запутались и начинаете думать, как метод может использовать переменную из вызывающей функции и не знаете о замыканиях…
«Закрытие — это функция, которая ссылается на свободную переменную в ее лексическом контексте». Так что здесь, в этом случае, замыкание — это функция, возвращаемая при работе с переменной умножением, и у нее есть свободная переменная a, которая имеет лексический контекст вызывающей функции.
Вернуть метод умножения или исправить значение по умолчанию для одного из параметров.
//multiply is defined in the first step mutiplyByTwo = mutiply.apply(2) mutiplyByThree = mutiply.apply(3); mutiplyByFour = mutiply.apply(4);;
И так далее …
Передайте вторую переменную возвращаемой функции, чтобы получить результат.
mutiplyByTwo.apply(2);//results mutiplyByTwo.apply(3);//results 6 mutiplyByThree.apply(2);//results 6 mutiplyByThree.apply(3);//results 9 mutiplyByFour.apply(2);//results 8 mutiplyByFour.apply(3);//results 124
Вы можете найти мой оригинальный пост здесь... https://www.linkedin.com/pulse/can-we-have-default-method-parameter-java-rajat-singh/?trackingId=yW84I1fzT6WGStrNPAWn4w%3D%3D