JavaRush /Java блог /Random /Глобальные переменные в Java: когда их использовать?
Анзор Кармов
31 уровень
Санкт-Петербург

Глобальные переменные в Java: когда их использовать?

Статья из группы Random
Привет! В этой статье мы поговорим о глобальных переменных, об их объявлении и примерах уместного использования. Небольшое примечание: мы не будем рассматривать глобальные переменные класса, то есть те, доступ к которым есть в рамках какого-либо одного класса. Будем говорить о глобальных переменных всего приложения — тех, доступ к которым есть в рамках целого приложения. Глобальные переменные в Java: когда их использовать? - 1

Как создавать глобальные переменные

Глобальные переменные — это переменные, которые доступны отовсюду в приложении. Иначе говоря их область видимости — все приложение. Чтобы создать такую переменную в Java, необходимо в публичном классе создать публичную статическую переменную:

public class Example {
    public static int a;
    public static int b;
    public static String str;
}
Переменные a, b и str — стали глобальными. Мы можем получить к ним прямой доступ из других классов внутри приложения:

public class GlobalVarsDemo {
    public static void main(String[] args) {
        Example.a = 4;
        Example.b = 5;
        Example.str = "Global String variable value";

        System.out.println(Example.a);
        System.out.println(Example.b);
        System.out.println(Example.str);
    }
}
Если мы запустим метод main, то увидим следующий вывод:

4
5
Global String variable value
Глобальные переменные можно разделить на 2 типа:
  • переменные которые можно редактировать;
  • переменные, которые можно только считывать.
Последние называют глобальными константами. Для того, чтобы создать глобальную константу, необходимо сделать переменную final и присвоить ей значение при определении переменной:

public class Constants {
    
    public static final double PI = 3.1415926535897932384626433832795;
    public static final String HELLO_WORLD_STR = "Hello, World!";
    
}
По соглашению об именовании в ЯП Java, все константы нужно именовать в верхнем регистре, разделяя слова символом нижнего подчеркивания. Итак, мы создали константы, и теперь мы не сможем изменять их значения:Глобальные переменные в Java: когда их использовать? - 2Однако, мы можем считывать их значения:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println(Constants.HELLO_WORLD_STR);
    }
}
Вывод:

Hello, World!

public class ConstantsDemo {
    public static void main(String[] args) {
        double r = 10;
        String message = String.format("Площадь круга с радиусом %f=%f", r, getCircleSquare(r));
        System.out.println(message);

    }

    static double getCircleSquare(double r) {
        return Constants.PI * r * r;
    }
}
Вывод:

Площадь круга с радиусом 10,000000=314,159265

Стоит ли использовать глобальные переменные

В интернете много статей, основной посыл которых такой: глобальные переменные — это зло, плохо и ужасно. Так ли это на самом деле? Попробуем привести плюсы и минусы глобальных переменных, чтобы каждый мог сделать вывод самостоятельно.Глобальные переменные в Java: когда их использовать? - 3Начнем с минусов. Представим себе приложение, в котором есть класс с глобальными переменными, доступными для чтения и редактирования. Со временем в проекте растет количество классов, количество глобальных переменных и методов, которые используют глобальные переменные, а иными словами — зависят от них. Со временем каждая глобальная переменная считывается в разных частях системы для разных целей. В разных частях системы значение переменной может обновляться. Общая картина мира данного приложения существенно усложняется, и отсюда вытекают такие минусы:
  1. Снижение читабельности и увеличение сложности понимания кода.
  2. Увеличение сложности сопровождения кода.
  3. Для изменения одной глобальной переменной, необходимо проанализировать весь код, чтобы не задать переменной невалидное для других частей системы значение.
  4. Увеличение ошибок, которые очень сложно отлаживать.

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

  5. Имена переменных могут совпасть, если вы используете в своем коде глобальные переменные, а также некоторые библиотеки, в которых в свою очередь также используются глобальные переменные. Это может привести к ошибкам как на стороне вашего приложения, так и на стороне используемой вами библиотеки.
  6. Увеличивается связность между различными частями системы, которые используют глобальные переменные. Стремиться нужно наоборот к слабой связанности кода. Лучше иметь много маленьких подсистем, слабо связанных друг с другом, чем одну здоровенную фиговину. Потому что мозгу легче разбираться с несколькими простыми вещами, чем с одной слишком сложной и запутанной штукой.
  7. Написание юнит-тестов усложняется, поскольку тесту не известно, какие глобальные переменные нужны и каким образом их необходимо проинициализировать.
  8. В многопоточных приложениях использование глобальных переменных разными потоками приводит к росту ошибок, которые сложно отлаживать, и к росту сложности проекта. Из-за этого необходимо настраивать доступ к таким переменным более правильно, обвешивая их синхронизациями и блокировками. В будущем это может привести к замкнутым блокировкам. Например, поток А заблокировал для своей работы переменную X, а поток B заблокировал для своей работы переменную Y, а потоку А теперь нужна переменная Y, а потоку B переменная X. В итоге, программа зависнет.
Но это все неточно. Это описание рисков, вероятность которых увеличивается с ростом проекта и ростом числа глобальных переменных в нем. Перейдем к плюсам:
  1. В маленьких проектах глобальные переменные — наиболее простая вещь для достижения работоспособности проекта.
  2. Иногда страх использования глобальных переменных приводит к еще большему усложнению проекта. Тогда программисты начинают создавать синглтоны и прибегать к прочим шаблонам проектирования.
  3. В программировании часто бывает нужно опираться на некоторые неизменные значения.

    Самое разумное — записать такие значения в виде константы, потому что только константы дают гарантию, что значение переменной не изменится со временем. Такие константы можно встретить сплошь и рядом (Integer.MAX_VALUE, Integer.MIN_VALUE, Boolean.TRUE, Collections.EMPTY_LIST и пр.). Но программирование не ограничивается использованием стандартных библиотек. Часто бывает нужно писать какую то уникальную логику, в которой необходимо будет опираться на свои, уникальные константы. Поэтому порой использование констант (глобальных переменных, доступных только для чтения) действительно упрощает жизнь.

В целом, не стоит злоупотреблять глобальными переменными, по возможности использовать только константы. Ранее было сказано, что использовать глобальные переменные в маленьких проектах — это не плохо. Но начинающему разработчику лучше вообще их не использовать. По двум причинам:
  1. Все, что пишет начинающий разработчик — по сути небольшой проект. И использование в его проектах глобальных переменных приучит его к использованию глобальных переменных везде.
  2. Лучше научиться сначала обходиться без «запретных приемчиков». А с опытом понимание, когда такие приемчики уместно применять, придет само.
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ