JavaRush /Java блог /Random /Кофе-брейк #88. Сила метаданных: как работать со спагетти...

Кофе-брейк #88. Сила метаданных: как работать со спагетти-кодом. Сборка мусора в Java — как она работает и в чем ее преимущества

Статья из группы Random

Сила метаданных: как работать со спагетти-кодом

Источник: Hackernoon Мы все пытаемся использовать общие подходы и известные шаблоны для создания приложения с минимальными усилиями и максимальной отдачей. У нас есть отличные библиотеки и мощные фреймворки, которые выполняют рутинные операции за нас. Все это мы используем для того, чтобы сосредоточиться только на бизнес-логике. Однако эта погоня довольно часто приводит нас к спагетти-коду, особенно когда речь идет о реализации функции без готового решения для нее. В этой статье я хочу поделиться с вами одним мощным инструментом, который, по моему опыту, ценят не все разработчики. Этот инструмент есть в большинстве языков программирования, и он очень часто используется во многих фреймворках — аннотации. Кофе-брейк #88. Сила метаданных: как работать со спагетти-кодом. Сборка мусора в Java — как она работает и в чем ее преимущества - 1

Вы любите спагетти?

Давайте рассмотрим пример, с которым я столкнулся пару лет назад. Мне нужно было сделать синтаксический анализ электронной таблицы Excel, чтобы поместить проанализированные данные в базу данных. Также я хотел собрать часть данных из базы данных и создать электронную таблицу. Для реализации я использовал известную Java-библиотеку — Apache POI. API библиотеки облегчает работу, поскольку позволяет вручную создавать лист, строку, ячейку и другие элементы. Это очень хорошо, но когда необходимо генерировать различные электронные таблицы Excel, код становится абсолютно нечитаемым и неподдерживаемым. В итоге, как это обычно бывает, первая версия приложения получается просто ужасной. Реализация состояла из класса данных, который представлял строку со всеми полями, необходимыми для синтаксического анализа. Также был парсер, в котором поля Excel анализировались ячейка за ячейкой и помещались во вновь созданный экземпляр класса данных. Поначалу программа работала отлично и делала то, что от нее требовалось. Проблемы начались, когда пришло время вносить какие-то модификации; код не читался. Даже я, написавший этот код, не мог найти подходящего места для размещения новых строк для реализации новой необходимой мне функции.

Спасение в аннотациях

Спасли приложение от этого спагетти-кода аннотации. Чтобы избавиться от неподдерживаемого кода, мне нужно было перенести логику определения того, какой столбец следует анализировать, какой тип данных содержится в ячейке и все остальное в другое место. Для этого я создал аннотацию, в которой указал имя столбца для каждого поля класса. В аннотации я также добавил переменную, с помощью которой можно выбирать цвет и шрифт ячейки. Тем самым код в классе синтаксического анализа был значительно сокращен. Только один обработчик динамически создавал электронную таблицу по параметрам, взятым из аннотаций. Это была победа. Затем, чтобы внести какие-либо изменения в приложение, мне просто нужно было создать класс с аннотациями. Решение напоминало библиотеку Jackson, которая анализирует JSON с помощью аннотаций, и, я думаю, нет необходимости рассказывать, насколько удобна Jackson или аналогичные библиотеки.

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnExcel {

    String name() default "";

    int position();

    ExcelColumnDataFormat cellTypePattern() default ExcelColumnDataFormat.NONE;

    IndexedColors cellColor() default IndexedColors.AUTOMATIC;

    ExcelTotalFormula total() default ExcelTotalFormula.NONE;

}

ColumnExcel columnExcel = field.getAnnotation(ColumnExcel.class);
По мере развития приложение получило новую аннотацию, с помощью которой в электронной таблице можно было создать ячейку с функцией внутри. Различные поля можно умножать, вычитать, использовать любые общие функции Excel. Также я добавил ​​итоговую строку для отображения суммы по столбцу. И все это было я сделал лишь за счет незначительной модификации основного парсера и простого добавления аннотаций к классам.

@ColumnExcel(
            name = "Views",
            position = 4,
            total = ExcelTotalFormula.SUM)
    private BigDecimal variableC;

    @ColumnExcelFormula(
            name = "Conversion",
            position = 5,
            cellTypePattern = CellDataTypeFormatPattern.PERCENTAGE
    )
    public String variableD(int rowNumber) {
        return new CellAddress(rowNumber, 4).formatAsString() + "*" 
		+ new CellAddress(rowNumber, 2).formatAsString();
    }

    @ColumnExcelTotalFormula(position = 4, cellTypePattern = CellDataTypeFormatPattern.RUR)
    public static String getVariableCTotalFormula(int firstRowNum, int lastRowNum) {
        return "SUM( " + new CellAddress(firstRowNum, 4).formatAsString() + ":" 
		+ new CellAddress(lastRowNum, 4).formatAsString() + ")";
    }

Сборка мусора в Java — как она работает и в чем ее преимущества

Источник: Dev.to Сборка мусора означает уничтожение или очистку неиспользуемых объектов в памяти. Java обрабатывает освобождение памяти автоматически, поскольку однажды созданный объект использует некоторый объем памяти в куче. Кофе-брейк #88. Сила метаданных: как работать со спагетти-кодом. Сборка мусора в Java — как она работает и в чем ее преимущества - 2

Как это работает?

До Java самым популярным языком программирования был C или C ++. Если вы владеете этими языками, то вам должно быть известно, что управление собственной памятью в них происходит вручную. Например, в C есть такие методы, как calloc(), malloc() и realloc(), которые позволят вам использовать буферную память. Вы должны определить, сколько памяти вам нужно для вашей программы, и указать, что вызывается этим API. Затем вы можете получить буфер памяти для создания узла связанного списка или чего-то другого. При завершении работы вашей программы, в какой-то определенный момент, вы также отвечаете за очистку этой памяти. Таким образом, большое приложение, написанное на языке C, продолжает выделять буферную память и иногда забывает ее очищать. В конечном итоге это вызывает утечки памяти и множество проблем в приложении. В отличие от C и C ++, язык Java поставляется с автоматическим управлением памятью через поток, называемый сборщиком мусора. Его основная цель — освободить память кучи путем уничтожения недоступных объектов. Сборщик мусора всегда работает в фоновом режиме.

Что такое недоступные объекты в Java?

Когда объект получает возможность начать сборку мусора? При наличии недоступных объектов — тех, на которые нет активных ссылок. Давайте посмотрим пример:

public static void main(String[] args)
{
// StringBuffer object sb is not eligible for garbage collection
StringBuffer sb = new StringBuffer("Flower Brackets");
System.out.println(sb);
// StringBuffer object sb is eligible for garbage collection
sb = null;
}
В основном методе я создал объект StringBuffer и ссылку на него. На данном этапе объект StringBuffer не подходит для сборки мусора. Теперь я собираюсь присвоить объекту StringBuffer значение “null”. Теперь объект имеет право на сборку мусора и становится недоступным объектом в памяти кучи. То есть, сборка мусора, как правило, работает в тех случаях, когда объекты становятся недоступными. Это означает, что объекты обычно создаются в контексте “if block” или метода. Таким образом, объекты выходят за пределы области видимости, как только выполнение метода завершается, их может удалить сборщик мусора. Поскольку ссылки из старых объектов на новые существуют в ограниченном количестве, это означает, что объекты, которые долгое время присутствуют в вашем приложении, обычно не относятся к вновь созданным объектам. Вот пара терминов, с которыми мы должны быть знакомы; один из них — live-объект. Это объект в приложении, на который ссылается другой объект в том же приложении. Также есть “dead” (мертвый) объект. Dead-объект — это недоступный объект, который создается во время вызова метода, и как только вызов метода завершается, объект выходит из контекста и просто лежит в куче.

Когда объект имеет право на сборку мусора?

Если объект не имеет какой-либо ссылочной переменной, то объект имеет право на сборку мусора.

Как сделать объект доступным для сборки мусора?

Ниже приведены несколько способов:
  1. 
    null reference variable
    Student obj = new Student();
    obj = null;
    

  2. 
    re-assign reference variable
    Student obj1 = new Student();
    Student obj2 = new Student();
    obj1 = obj2;
    

  3. 
    reate anonymous object
    new Student();
    

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

Когда виртуальная машина Java запускает сборщик мусора, уничтожается только объект. ПРИМЕЧАНИЕ: сборщик мусора собирает только объекты, созданные с использованием ключевого слова “new”, для объектов без ключевого слова “new” используйте метод finalize(). Существует несколько методов для запуска сборщика мусора в виртуальной машине Java:
  1. Метод System.gc()

  2. Метод finalize()

  3. Метод Runtime.getRuntime().gc()

Статический метод gc() расположен в классе System. Этот метод запрашивает у JVM вызов сборщика мусора. Давайте посмотрим, как Java-приложение с помощью метода gc() вызывает сборщик мусора.

public class GarbageCollector
{
public static void main(String[] args)
{
Employee obj1 = new Employee();
Employee obj2 = new Employee();
obj1 = null;
obj2 = null;
System.gc();
}
public void finalize()
{
System.out.println("object garbage collected");
}
}
Результат:
object garbage collected object garbage collected
Метод finalize() вызывается непосредственно перед очисткой объекта. Этот метод определен в классе Object:

protected void finalize() throws Throwable
  1. Метод Finalize используется для закрытия соединения с базой данных.

  2. Этот метод вызывается сборщиком мусора, а не JVM.

  3. Нам нужно переопределить метод finalize(). Потому что у него пустая реализация.

  4. Он вызывается только один раз для каждого объекта.

Метод getRuntime().gc() присутствует в классе времени выполнения. Он возвращает объект Runtime, связанный с текущим приложением Java. Давайте посмотрим на этот метод в Java-программе.

public class Demo
{
public static void main(String[] args)
{
Demo obj1 = new Demo();
Demo obj2 = new Demo();
// nullifying reference variable
obj1 = null;
// nullifying reference variable
obj2 = null;
// running Garbage Collector
Runtime.getRuntime().gc();
}
@Override
protected void finalize() throws Throwable
{
System.out.println("Garbage collector called");
System.out.println("Object garbage collector: " + this);
}
}
Результат:
Garbage collector called Object garbage collector: Demo@2130772 Garbage collector called Object garbage collector: Demo@cd4e940

Преимущества сборки мусора:

  1. Сборка мусора в Java происходит автоматически, что избавляет нас от дополнительной нагрузки по освобождению используемой памяти. Это делает память Java-программы более эффективной.
  2. Сборка мусора обеспечивает целостность программы.
  3. Нам не нужно писать дополнительный код, поскольку сборщик мусора является частью JVM.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
fog Уровень 18
19 августа 2021
finalize() Deprecated. Используйте интерфейс AutoCloseable в сочетании с try-with-resouces, или java.lang.ref.Clearner.