Я никогда не работал с псевдонимами типа, но эта концепция, по-видимому, очень полезная функция, добавляющая семантику над теми же типизированными объектами и защитой от общих опечаток.
Скажем, существует void foo(float volume, float weight)
. Это нормально, если он вызывается следующим образом: foo(v, m)
, но foo(m, v)
не является очевидной опечаткой. void process(Iterable<File> javaPath, Iterable<File> classPath)
может быть другим вариантом использования. К сожалению, в Java нет псевдонимов типов, и некоторые обходные пути являются истинным излишеством:
Таким образом, у обоих из них есть недостатки и затраты времени исполнения/производительности.
Насколько я могу судить, в Java время на основе "псевдонимов типа" может быть заменено проверками времени компиляции, например, обрабатываются @NotNull и @Nullable. Существуют ли какие-либо статические проверки типа/псевдонимы/инструменты APT, поддерживающие такие конструкции, как void foo(@Volume float volume, @Weight float weight)
, чтобы контролер мог проверять такую "безопасность типа" во время компиляции и требовать прохождения переменных/констант и литералы, которые должны быть аннотированы (на сайтах с объявлениями и вызовами)?
Этот вопрос также поднят, потому что я в настоящее время работаю над инструментом обработки кода Java-исходного кода, который может использовать несколько back-end (в настоящее время только JDT). Пока я хочу, чтобы это был JDT-агностик, я хотел бы иметь бизнес-объекты для типов, методов и полей. Несмотря на это, я теряю много информации из JDT AST, лучший текущий подход для моего инструмента - использование строк (это позволяет выполнить некоторый анализ, достаточный для сферы применения инструмента). Но такие методы, как void process(String type, String field, String method)
, путают, поэтому я создал Type
, Field
и Method
которые представляют объекты домена и являются JDT-агностиками. Они в порядке, но я не ожидаю, что они будут расширены в будущем (все эти три типа имеют одно private final String name;
поле + мне пришлось переопределить hashCode/equals
и toString
). Это снова привело меня к идее проверки типа APT. До тех пор, пока нормально обрабатывать необработанные данные, достаточно будет иметь что-то вроде void process(@Type String type, @Field String field, @Method String method)
(я все еще могу использовать один объект).
Если ваша проблема выглядит неоднозначно, когда вы вызываете foo(v,m)
что люди могут ошибочно писать foo(m,v)
без каких-либо предупреждений или видимых подсказок об ошибке, вы можете использовать шаблон с быстрым построением:
(Код не проверен, просто написал, чтобы продемонстрировать идею)
public class MyClass {
public class FooStub {
int volume;
int weight;
public FooStub withVolume(int v) {
this.volume = v;
return this;
}
public FooStub withWeight(int w) {
this.weight = w;
return this;
}
public int run() { // or call it getResult() or whatever you want
Assert.notNull(volume);
Assert.notNull(weight);
return foo(volume,weight); // calling method of outer class
}
}
public int foo(int volume, int weight) { // you even hide this if you want
return volume * weight;
}
public FooStub foo() {
return new FooStub();
}
}
Таким образом, вызывающий может сделать
MyClass myObj = ....;
int result = myObj.foo().withVolume(a).withWeight(b).run();
// which is the same as result = myObject.foo(a,b);
myObj.foo().withVolume(b).withWeight(a).run()
- здесь a
и b
меняются местами случайно.
myObj.foo(w,v);
, он по-прежнему «выглядит» хорошо, в то время как myObj.foo().withVolume(w).withWeight(v).run()
не
foo(a,b)
, для которых одновременно и Ьint
, как инструменты предполагается проверить , если мой являетсяa
Volume
? Если вам нужно, чтобыVolume
имел смысловое значение, сделайте его классом.