Поддерживает ли 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 такой синтаксис? Есть ли причины, почему этот двухэтапный синтаксис предпочтительнее?
19 ответов:
нет, структура, которую вы нашли, - это то, как Java обрабатывает ее (то есть с перегрузкой вместо параметров по умолчанию).
строителей, см. эффективный Java: руководство по языку программирования пункт 1 совет (рассмотрим статические методы фабрики вместо конструкторов), если перегрузка становится сложной. Для других методов может помочь переименование некоторых случаев или использование объекта параметра. Это когда у вас есть достаточно сложности, что дифференциация является трудный. Определенный случай, когда вы должны дифференцировать, используя порядок параметров, а не только число и тип.
нет, но вы можете использовать Шаблона, как описано в этот ответ переполнения стека.
как описано в связанном ответе, шаблон 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");
одним из ограничений этого подхода является то, что он не работает, если у вас есть два необязательных параметра того же типа, и любой из них может быть опущен.
С varargs.
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");
основным недостатком этого подхода является то, что если необязательные параметры имеют разные типы, вы теряете статическую проверку типа. Кроме того, если каждый параметр имеет разное значение, вам нужно каким-то образом их различать.
Nulls. чтобы устранить ограничения предыдущих подходов, вы можете разрешить нулевые значения, а затем проанализировать каждый параметр в теле метода:
void foo(String a, Integer b, Integer c) { b = b != null ? b : 0; c = c != null ? c : 0; //... } foo("a", null, 2);
теперь все значения аргументов должны быть предоставлены, но значения по умолчанию могут быть null.
дополнительный класс. этот подход похож на null, но использует 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());
Optional делает контракт метода явным для вызывающего абонента, однако, можно найти такую подпись слишком многословной.
шаблон строителя. шаблон строителя используется для конструкторы и реализуется путем введения отдельного класса 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) {}
Я мог бы заявить очевидное здесь, но почему бы просто не реализовать параметр "по умолчанию" самостоятельно?
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 не имеет большого (любого) синтаксического сахара, так как они пытались сделать простой язык.
нет.
вы можете добиться такого же поведения, передавая объект, который имеет смарт-значения по умолчанию. Но опять же это зависит от того, что ваше дело под рукой.
нет, а самый простой способ реализовать это - это:
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); }
Как упоминалось Скала,Котлин также стоит упомянуть. В функции Kotlin параметры могут иметь значения по умолчанию, а также они могут даже ссылаться на другие параметры:
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { ... }
Как и Scala, Kotlin работает на JVM и может быть легко интегрирован в существующие проекты Java.
Он не поддерживается, но есть несколько вариантов, таких как Использование шаблона объекта параметра с некоторым синтаксическим сахаром:
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; }
есть полдюжины или лучше вопросов, таких как это, в конечном итоге вы приходите к статической заводской модели ... см. крипто API для этого. Сортировка трудно объяснить, но подумайте об этом так: Если у вас есть конструктор, по умолчанию или иначе, единственный способ распространить состояние за фигурные скобки - либо иметь логический isValid; (вместе с нулевым значением по умолчанию V failed constructor ), либо выбросить исключение, которое никогда не информативно при его возврате из поля пользователи.
код правильный будь проклят, я пишу тысячи строчных конструкторов и делаю то, что мне нужно. Я нахожу использование isValid при построении объекта-другими словами, двух линейных конструкторов - но по какой-то причине я перехожу к статическому заводскому шаблону. Я просто кажется, что вы можете сделать много, если вы в вызове метода, есть еще вопросы синхронизации (), но по умолчанию могут быть "заменены" лучше ( безопаснее)
Я думаю, что нам нужно здесь решить проблему null как значения по умолчанию vis-a-vis что-то String one=new String(""); как переменная-член, затем выполняет проверку на null перед назначением строки, переданной конструктору.
очень примечательно количество сырых, стратосферных компьютерных наук, выполненных на Java.
C++ и так далее имеет поставщик libs, да. Java может обогнать их на крупномасштабных серверах из-за его массивного набора инструментов. Изучайте статические блоки инициализатора, оставайтесь с нами.
вот как я это сделал ... возможно, это не так удобно, как иметь "необязательный аргумент" против вашего определенного параметра, но он выполняет работу:
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, создавая новый метод с тем же именем только с добавленным логическим значением.
Я на самом деле думаю, что это немного чище, чем если бы Java предоставил "необязательный аргумент" для наших параметров, так как нам нужно было бы затем кодировать значения по умолчанию и т. д. В этом примере мне не нужно беспокоиться ни о чем из этого. Да, Я я добавил еще один метод к моему классу, но его легче читать в долгосрочной перспективе, по моему скромному мнению.
аналогичный подход к https://stackoverflow.com/a/13864910/2323964 что работает в 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; } }); } }
вы можете использовать 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);
или set любое из значений по умолчанию для чего-то другого.
CarService instance = new CarService(); String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()// .withColor(Color.YELLOW)// .invoke(instance);