Итак, вы хотите упростить Model.getDestination().getDevice().getName()
. Во-первых, я хочу перечислить несколько вещей, которые не следует делать: не используйте исключения. Не пишите метод IsValid
, потому что он просто не работает, потому что все функции (или методы) строги в Java: это означает, что каждый раз, когда вы вызываете функцию, все аргументы оцениваются перед их передачей к функции.
В Swift я бы просто написал let name = Model.getDestination()?.getDevice()?.getName() ?? ""
. В Haskell это будет похоже на name <- (destination >>= getDevice >>= getName) <|> Just ""
(в предположении монады Maybe). И эта семантика отличается от кода Java:
if(Model.getDestination() && Model.getDestination().getDevice() && Model.getDestination().getDevice().getName() {
String name = Model.getDestination().getDevice().getName();
System.out.println("We got a name: "+name);
}
, потому что этот фрагмент вызывает getDestination()
4 раза, getDevice()
3 раза, getName()
2 раза. Это имеет больше, чем просто влияние на производительность: 1) В нем представлены условия гонки. 2) Если какой-либо из методов имеет побочные эффекты, вы не хотите, чтобы они вызывались несколько раз. 3) Это усложняет отладку.
Единственный правильный способ сделать это - что-то вроде этого:
Destination dest = Model.getDestination();
Device device = null;
String name = null;
if(dest != null) {
device = dest.getDevice();
if(device != null) {
name = device.getName();
}
}
if(name == null) {
name = "";
}
Этот код устанавливает имя на Model.getDestination().getDevice().getName()
, или если какой-либо из них вызовы метода возвращают ноль, он устанавливает имя в "". Я думаю, что правильность важнее, чем удобочитаемость, особенно для производственных приложений (и даже, например, кода IMHO). Вышеприведенный код Swift или Haskell эквивалентен этому Java коду.
Если у вас есть производственное приложение, я думаю, что нечто подобное - это то, что вы уже делаете, потому что все, что принципиально отличается от этого, подвержено ошибкам.
Каждое лучшее решение должно предоставлять одну и ту же семантику, и оно НЕ ДОЛЖНО вызывать какие-либо методы (getDestination, getDevice, getName) более одного раза.
Тем не менее, я не думаю, что вы можете значительно упростить код с помощью Java 7.
Что вы можете сделать, конечно, сократить цепочки вызовов: например, вы может создать метод getDeviceName()
на Destination
, если вам часто нужна эта функциональность. Если это сделает код более читабельным, зависит от конкретной ситуации.
У принуждения к кодированию на этом низком уровне также есть свои преимущества: вы можете сделать общее исключение подвыражения, и вы увидите его преимущества, потому что это сделает код короче. Например, если у вас есть:
String name1 = Model.getDevice().getConnection().getContext().getName();
String name2 = Model.getDevice().getConnection().getContext().getLabel();
, вы можете упростить их до
Context ctx = Model.getDevice().getConnection().getContext();
String name1 = ctx.getName();
String name2 = ctx.getLabel();
Второй фрагмент имеет 3 строки, тогда как первый фрагмент имеет только две строки. Но если вы развернете два фрагмента для включения нулевых проверок, вы увидите, что вторая версия на самом деле намного короче. (Я не делаю это сейчас, потому что я ленивый.)
Поэтому (в отношении необязательных цепочек) Java 7 сделает код кодера, учитывающего производительность, лучше, в то время как многие другие языки высокого уровня создают стимулы для создания медленного кода. (Конечно, вы можете также выполнять обычное исключение подвыражений на языках более высокого уровня (и, вероятно, вам следует), но, по моему опыту, большинство разработчиков более неохотно делают это на языках высокого уровня. Тогда как в Ассемблере все оптимизировано, потому что часто повышается производительность означает, что вам нужно писать меньше кода, а код, который вы пишете, легче понять.)
Одним словом, мы все будем использовать языки со встроенной необязательной цепочкой, и мы все будем использовать это ответственно , без проблем с производительностью и условиями гонки.