Как избежать избыточности кода конструктора в Java?

У меня есть следующий класс:

class Pair
{
    String car;
    Integer cdr;

    public Pair () {}
    public Pair (String car) { this.car = car; }
    public Pair (Integer cdr) { this.cdr = cdr; }

    public Pair (String car, Integer cdr)
    {
        this(car);
        this(cdr);
    }
}

Класс содержит два необязательных значения, и я хотел бы предоставить все возможные перестановки конструктора. Первая версия ничего не инициализирует, вторая инициализирует только первое значение, а третья инициализирует только второе значение.

Последний конструктор является комбинацией второго и третьего. Но это невозможно записать, потому что код не работает с.

constructor.java:13: call to this must be first statement in constructor
        this(cdr);
            ^
1 error

Можно ли написать последний конструктор без какой-либо избыточности кода (также без вызова тех же методов установки)?

 RudolphEst18 июн. 2013 г., 16:41
Вы вызываете конструкторы this (...) дважды, вы можете сделать так, чтобы конструктор вызывал только один другой конструктор, и вызов связанного конструктора должен быть первым оператором в конструкторе.
 bNd18 июн. 2013 г., 16:15
Ваша проблема с this () и super () должна быть [первое утверждение в конструкторе] [1]. [1]:stackoverflow.com/questions/1168345/...

Ответы на вопрос(4)

class Pair
{
    String car;
    Integer cdr;

    public Pair () {}
    public Pair (String car) { 
        this(car, null)
    }
    public Pair (Integer cdr) {
        this(null, cdr);
    }

    public Pair (String car, Integer cdr) {
        this.car = car;
        this.cdr = cdr;
    }
}

с наиболее конкретным из них, чтобы установить все поля:

public Pair() {
    this(null, null); // For consistency
}

public Pair(String car) {
    this(car, null);
}

public Pair(Integer cdr) {
    this(null, cdr);
}

public Pair (String car, Integer cdr)  {
    this.car = car;
    this.cdr = cdr;
}

Сюда:

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

В сторону, яНастоятельно рекомендую сделать поля приватными (и, вероятно, окончательными) и дать им более значимые имена.

Обратите внимание, что таким образом, если у вас есть, скажем, 5 параметров и один конструктор с 3, один с 4 и один с 5, выможет быть выбрать цепочку из 3 -> 4 -> 5, или вы можете пойти прямо с 3 -> 5.

Кроме того, вы можете полностью удалить конструкторы с одним параметром - было бы удобнее читать статические методы, где вы можете указать значение в имени:

public static Pair fromCar(String car) {
    return new Pair(car, null);
}

public static Pair fromCdr(Integer cdr) {
    return new Pair(null, cdr);
}

Или в моем предпочтительном названии значений:

public static Pair fromFirst(String first) {
    return new Pair(first, null);
}

public static Pair fromSecond(Integer second) {
    return new Pair(null, second);
}

На данный момент вы можете сделатьPair универсальный класс, не беспокоясь о том, какой конструктор будет вызываться, если два аргумента типа совпадают. Кроме того, любой, кто читает код, может понять, что будет сконструировано, без проверки типа аргумента.

 Nathan Hughes18 июн. 2013 г., 16:36
@ceving: как говорит Джон, было бы лучше переименовать их вfirst а такжеsecond, то, что у вас есть, это 2-кортеж, а не ячейка против.
 ceving18 июн. 2013 г., 16:27
Это всего лишь пример. Я могу изменить это наfoo а такжеbar если вы более знакомы с ними.
 Jon Skeet18 июн. 2013 г., 16:15
@ceving: мне кажется, это довольно туманный смысл в контексте Java ... особенно потому, что онидолжен был бытьоператоры скорее, чемценности, Если это только для того, чтобы бытьпервый" а также "второй» ценности, тогда эти имена будут гораздо более значимыми для большинства людей.
 Lukas Eder18 июн. 2013 г., 16:26
Ребята, я чувствую, что обсуждаю названияcar а такжеcdr действительно не по теме и немного шумно здесь ;-)
 ceving18 июн. 2013 г., 16:12
Они имеют значение:en.wikipedia.org/wiki/CAR_and_CDR

образец строителя Вот.

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

@Immutable // see JSR 305
public final class Pair
{
    private final String car;
    private final integer cdr;

    private Pair(final Builder builder)
    {
        car = builder.car;
        cdr = builder.cdr;
    }

    public static Builder newBuilder()
    {
        return new Builder();
    }

    // whatever other methods in Pair, including accessors for car and cdr, then:

    @NotThreadSafe // see JSR 305
    public final class Builder
    {
        private String car;
        private int cdr;

        private Builder()
        {
        }

        public Builder withCar(final String car)
        {
            this.car = car;
            return this;
        }

        public Builder withCdr(final int cdr)
        {
            this.cdr = cdr;
            return this;
        }

        public Pair build()
        {
            return new Pair(this);
        }
    }
}

Пример использования:

final Pair newPair = Pair.newBuilder.withCar("foo").withCdr(1).build();

Преимущество:Pair теперь неизменна!

 fge18 июн. 2013 г., 16:25
@ Chips_100 Я так привык к тому, что, с другой стороны, я могу упустить некоторые важные моменты ... Например, DI-фреймворки (Dependecy Injection).
 Dennis18 июн. 2013 г., 16:15
хороший и исчерпывающий пример для построения шаблона, но, возможно, немного излишним в этом случае. (также, я думаю, неизменность не является преимуществом автоматически). Но все равно +1 за хорошую альтернативу!
Решение Вопроса

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

public Pair() {}
public Pair(String car) { this(car, null); }
public Pair(Integer cdr) { this(null, cdr); }
public Pair(String car, Integer cdr) { this.car = car; this.cdr = cdr; }
 Michael Shopsin25 июн. 2013 г., 15:38
@josefx вы правы, я никогда не пытался вызывать другие конструкторы только методами.
 Lukas Eder18 июн. 2013 г., 16:08
Вариант будет сделать поляfinal и пусть вызов конструктора по умолчаниюthis(null, null);
 josefx22 июн. 2013 г., 16:21
@MichaelShopsin почему бы быть исключением
 Michael Shopsin24 июн. 2013 г., 20:32
@josefx конечные переменные класса должны быть установлены в конструкторе или когда они объявлены. Вы не можете вызвать другой метод из конструктора, чтобы установить окончательную переменную класса.
 josefx24 июн. 2013 г., 21:44
@MichaelShopsin ctor цепочка с финальными работами для меня, подумал конструктор! = Метод.
 Michael Shopsin18 июн. 2013 г., 17:51
Исключением из правила конструкторов, вызывающих своих родителей, являются конечные переменные. Для версии Pair с конечными переменными код выглядит так:class pair { private final String car; private final Integer cdr; public Pair() { this.car = null; this.cdr = null; } public Pair(String car) { this.car = car; this.cdr = null; } ... }

Ваш ответ на вопрос