Подтвердить что ты не робот

Именованные блоки для ограничения области видимости: хорошая идея?

В течение многих лет я использовал именованные блоки, чтобы ограничить область временных переменных. Я никогда не видел, чтобы это делалось в другом месте, и это заставляет меня задаться вопросом, является ли это плохая идея. Тем более, что Eclipse IDE помечает их как предупреждения по умолчанию.

Я использовал это для хорошего эффекта, я думаю, в своем собственном коде. Но поскольку это неидиоматично до такой степени, что хорошие программисты будут недоверчивы, когда они это видят, у меня действительно есть два пути отсюда:

  • избегайте этого, или
  • продвигать его, надеясь, что он станет идиомой.

Пример (в рамках более крупного метода):

final Date nextTuesday;
initNextTuesday: {
    GregorianCalendar cal = new GregorianCalendar();
    ... // About 5-10 lines of setting the calendar fields
    nextTuesday = cal.getTime();
}

Здесь я использую GregorianCalendar только для инициализации даты, и я хочу убедиться, что я не случайно его повторно использую.

Некоторые люди прокомментировали, что на самом деле вам не нужно называть блок. Хотя это правда, необработанный блок выглядит еще больше как ошибка, поскольку намерение неясно. Более того, называя что-то побуждает вас думать о намерении блока. Цель здесь состоит в том, чтобы идентифицировать отдельные разделы кода, а не предоставлять каждой временной переменной свою собственную область.

Многие люди прокомментировали, что лучше всего перейти к малым методам. Я согласен, что это должен быть ваш первый инстинкт. Однако могут быть несколько смягчающих факторов:

  • Чтобы даже рассмотреть именованный блок, код должен быть коротким, одноразовым кодом, который никогда не будет вызываться в другом месте.
  • Именованный блок - это быстрый способ организации негабаритного метода без создания одноразового метода с десятком параметров. Это особенно актуально, когда класс находится в потоке, и входы, вероятно, будут меняться от версии к версии.
  • Создание нового метода поощряет его повторное использование, которое может быть необоснованным, если варианты использования не установлены. Именованный блок проще (психологически, по крайней мере) выбросить.
  • Специально для модульных тестов вам может потребоваться определить дюжину различных объектов для одноразовых утверждений, и они достаточно различны, что вы не можете (пока) найти способ объединить их в небольшое количество методов, и вы не можете придумать способ отличить их от имен, которые не длинны в миле.

Преимущества использования именованной области:

  • Невозможно случайно использовать временные переменные
  • Ограниченная область предоставляет сборщику мусора и компилятору JIT дополнительную информацию о намерении программиста.
  • Имя блока предоставляет комментарий к блоку кода, который я считаю более читаемым, чем открытые комментарии
  • Легче реорганизовать код из большого метода на небольшие методы или наоборот, так как именованный блок легче отделить, чем неструктурированный код.

Недостатки:

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

Он может использоваться как предлог для плохих привычек программирования, таких как:

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

Примечание. Я подробно отредактировал этот вопрос, основываясь на некоторых продуманных ответах. Спасибо!

4b9b3361

Ответ 1

Я бы просто пошел рефакторинг на более мелкие методы. Если метод достаточно велик, что ему нужно так разбиться, ему действительно нужно разбиться на несколько методов, если это вообще возможно.

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

Ответ 2

Если это было плохо, то почему это особенность на этом языке! У него есть цель, и вы ее нашли.

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

Мини-области - это простой способ разбить код на "абзацы". Если вы разделитесь на методы, вы можете сделать код более сложным для навигации, когда эти методы не будут вызываться из другого места и иметь порядковый порядок, в котором они должны быть выполнены.

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

Нет жестких и быстрых правил. Мне иногда немного надоели сотрудники, которые чрезмерно вкладывали все в свой собственный метод или класс или файл, и это становится кошмаром для навигации. Там есть хороший баланс!

Ответ 3

Иногда я использую неназванные блоки, чтобы изолировать изменчивые вещи, необходимые для подготовки некоторой непреложной вещи. Вместо того, чтобы иметь метку, я помещаю блок под объявление неизменной переменной.

final String example;
{
   final StringBuilder sb = new StringBuilder();
   for(int i = 0; i < 100; i++)
     sb.append(i);
   example = sb.toString();

}

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

Ответ 4

Использование блоков для ограничения объема - хорошая методика в моей книге.

Но так как вы используете ярлык для работы комментария, почему бы просто не использовать фактический комментарий? Это устранило бы замешательство в отношении метки без ссылки.

Ответ 5

Это первый раз, когда я вижу, как кто-то использует блоки. гмм! Я думал, что я единственный. Я знаю, что я его не изобретал - помнил, что читал его где-то - возможно, из моего предыдущего мира С++.

Я не использую эти метки, и просто комментирую, что я делаю.

Я не согласен со всеми парнями, которые просят вас извлечь его в метод. Большинство вещей, которые мы надеваем в таких блоках, на самом деле не являются многоразовыми блоками. Это имеет смысл при большой инициализации И ДА, я использовал блоки для предотвращения ошибок COPY/PASTE.

BR,
~ А

Ответ 6

Если у вас есть 5-10 строк кода, которые можно безопасно помещать в такой блок, тот же код может быть также извлечен в метод.

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

Ответ 7

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

  • Вы не сможете использовать временные переменные, объявленные в новом методе
  • Компилятор GC и JIT собирает одну и ту же информацию с помощью нового метода
  • Использование описательного имени для нового метода (с использованием "private Date initNextTuesday()" в вашем случае) позволит использовать преимущества комментирующего кода
  • Не нужно реорганизовывать код, если вы уже "предварительно факторизировали" его

В дополнение к этим преимуществам вы также получаете преимущества повторного использования кода, и это сократит ваши длинные методы.

Ответ 8

Я бы использовал блок с комментарием, добавив там ярлык.

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

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

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

Ответ 9

Это хорошая техника в моей книге. Управление большим количеством методов отбрасывания является злым, и причины, которые вы предоставляете для обозначения блоков, хороши.

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

Ответ 10

Извините за воскрешение этого, но я не видел, чтобы кто-то упоминал, что я считаю очень важным. Посмотрите на свой пример:

final Date nextTuesday;
initNextTuesday: {
    GregorianCalendar cal = new GregorianCalendar();
    ... // About 5-10 lines of setting the calendar fields
    nextTuesday = cal.getTime();
}

Включение этой логики инициализации здесь упрощает понимание, если вы читаете файл сверху донизу и заботитесь о каждой строке. Но подумайте о том, как вы читаете код. Вы начинаете читать из верхней части файла и продолжаете снизу? Конечно нет! Единственный раз, когда вы когда-либо делаете это, - во время проверки кода. Вместо этого у вас, вероятно, есть начальная точка, основанная на предыдущих знаниях, трассировке стека и т.д. Затем вы будите дальше вниз/вверх по пути выполнения, пока не найдете то, что ищете. Оптимизация для чтения на основе пути выполнения, а не отзывов об ошибках.
Является ли человек, читающий код, который использует nextTuesday, действительно хочет прочитать, как он инициализируется? Я бы сказал, что единственная информация, которая им нужна, это то, что в следующий вторник будет Date. Вся эта информация содержится в ее заявлении. Это прекрасный пример кода, который должен быть разбит на частный метод, потому что не нужно понимать логику, которую читатель заботится о.

final Date nextTuesday;
initNextTuesday: {
    GregorianCalendar cal = new GregorianCalendar();
    //1
    //2
    //3
    //4
    //5
    nextTuesday = cal.getTime();
}

против

final Date nextTuesday = getNextTuesday();

Что бы вы предпочли прочитать на своем модуле?

Ответ 11

Название Блоки помогают: Использование break как формы Goto

Использование break как цивилизованной формы goto.

class Break {
    public static void main(String args[]) {
        boolean t = true;
        first: {
            second: {
                third: {
                    System.out.println("Before the break.");
                    if (t)
                        break second; // break out of second block
                    System.out.println("This won't execute");
                }
                System.out.println("This won't execute");
            }
            System.out.println("This is after second block.");
        }
    }
}

Использование break для выхода из вложенных циклов

class BreakLoop4 {
    public static void main(String args[]) {
        outer: for (int i = 0; i < 3; i++) {
            System.out.print("Pass " + i + ": ");
            for (int j = 0; j < 100; j++) {
                if (j == 10)
                    break outer; // exit both loops
                System.out.print(j + " ");
            }
            System.out.println("This will not print");
        }
        System.out.println("Loops complete.");
    }
}

Источник Ссылка

Ответ 12

Я сделал это в некоторых из моих С#. Я не знал, что вы могли бы назвать блоки, но мне придется попробовать, чтобы увидеть, работает ли он в С#.

Я думаю, что блок области может быть хорошей идеей, потому что вы можете инкапсулировать код, специфичный для чего-то в блоке кода, где вы, возможно, не захотите разбить его на свою собственную функцию.

Что касается недостатка вложенности в них, я вижу, что, поскольку больше ошибок программиста, а не области блоков, сами блокируются.

Ответ 13

Именованные области технически хороши здесь, это просто они не используются таким образом очень часто. Поэтому, когда кто-то еще хочет сохранить ваш код в будущем, может быть сразу не видно, почему они там. ИМХО - частный помощник - лучший выбор...

Ответ 14

Мне нравится идея использования блока для ограничения области var. Так много раз меня путали недолговечные вары при большом объеме, которые должны уходить сразу после использования. Длинный метод + много нечетных vars затрудняет рассуждение о намерении кодера, особенно когда комментарии редки. Учитывая большую часть логики, которую я вижу в методе, были ниже

Type foo(args..){
    declare ret
    ...
    make temp vars to add information on ret
    ...

    make some more temp vars to add info on ret. not much related to above code. but previously declared vars are still alive
    ...


    return ret
}

если vars может иметь меньший объем, чем весь тело метода, я могу быстро забыть большинство из них (хорошо).

Также я согласен, что слишком много или слишком мало личных вещей приводит к коду спагетти.

Фактически то, что я искал, было чем-то вроде вложенного метода в функциональных языках, и кажется, что его кузен в Java - это { BLOCK} (внутренний класс и выражение labmda не для этого..).

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

Для использования частного метода я рассматриваю его как следующий шаг использования блоков.