JavaRush /Java Blog /Random EN /Coffee break #88. The power of metadata: how to work with...

Coffee break #88. The power of metadata: how to work with spaghetti code. Garbage collection in Java - how it works and what are its advantages

Published in the Random EN group

The power of metadata: how to work with spaghetti code

Source: Hackernoon We all try to use common approaches and known patterns to create an application with minimal effort and maximum impact. We have excellent libraries and powerful frameworks that perform routine operations for us. We use all this to focus only on business logic. However, this pursuit often leads us to spaghetti code, especially when it comes to implementing a function without a ready-made solution for it. In this article, I want to share with you one powerful tool that, in my experience, not all developers appreciate. This tool is present in most programming languages, and it is very often used in many frameworks - annotations. Coffee break #88.  The power of metadata: how to work with spaghetti code.  Garbage collection in Java - how it works and what are its advantages - 1

Do you like spaghetti?

Let's look at an example I came across a couple of years ago. I needed to parse an Excel spreadsheet to put the parsed data into a database. I also wanted to collect some of the data from the database and create a spreadsheet. For implementation, I used the well-known Java library - Apache POI. The library's API makes your work easier because it allows you to manually create a sheet, row, cell, and other elements. This is very good, but when it is necessary to generate various Excel spreadsheets, the code becomes completely unreadable and unsupportable. As a result, as usually happens, the first version of the application turns out to be simply terrible. The implementation consisted of a data class that represented a string with all the fields needed for parsing. There was also a parser where Excel fields were parsed cell by cell and placed into a newly created data class instance. At first the program worked great and did what was required of it. The problems started when it came time to make some modifications; the code was not read. Even I, who wrote this code, could not find a suitable place to place new lines to implement the new function I needed.

Rescue in annotations

Saved the application from this annotation spaghetti code. To get rid of unsupported code, I needed to move the logic for determining which column to parse, what type of data a cell contained, and everything else to a different location. To do this, I created an annotation in which I specified the column name for each class field. In the annotation, I also added a variable that allows you to select the color and font of the cell. Thus, the code in the parsing class has been significantly reduced. Only one processor dynamically created the spreadsheet based on the parameters taken from the annotations. It was a victory. Then, to make any changes to the application, I just had to create a class with annotations. The solution was reminiscent of the Jackson library, which parses JSON using annotations, and I think there is no need to tell how convenient Jackson or similar libraries are.
@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);
As the application evolved, it received a new annotation that could be used to create a cell in a spreadsheet with a function inside. Various fields can be multiplied, subtracted, and any common Excel functions can be used. I also added a total row to show the sum by column. And I did all this just by slightly modifying the main parser and simply adding annotations to the classes.
@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() + ")";
    }

Garbage collection in Java - how it works and what are its advantages

Source: Dev.to Garbage collection means destroying or cleaning up unused objects in memory. Java handles memory deallocation automatically because once an object is created, it uses some memory on the heap. Coffee break #88.  The power of metadata: how to work with spaghetti code.  Garbage collection in Java - how it works and what are its advantages - 2

How it works?

Before Java, the most popular programming language was C or C++. If you speak these languages, then you should know that they manage their own memory manually. For example, C has methods such as calloc() , malloc() and realloc() that will allow you to use buffer memory. You must determine how much memory you need for your program and specify what is called by this API. You can then get a memory buffer to create a linked list node or something else. When your program terminates, at some point, you are also responsible for cleaning up that memory. So a large application written in C keeps allocating buffer memory and sometimes forgets to flush it. This ultimately causes memory leaks and a lot of problems in the application. Unlike C and C++, the Java language comes with automatic memory management through a thread called a garbage collector. Its main purpose is to free heap memory by destroying inaccessible objects. The garbage collector always runs in the background.

What are inaccessible objects in Java?

When does an object get a chance to start garbage collection? If there are inaccessible objects - those for which there are no active links. Let's see an example:
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;
}
In the main method I created a StringBuffer object and a reference to it. At this point, the StringBuffer object is not eligible for garbage collection. Now I'm going to set the StringBuffer object to "null". The object is now eligible for garbage collection and becomes an inaccessible object in heap memory. That is, garbage collection generally works in cases where objects become inaccessible. This means that objects are usually created in the context of an “if block” or method. Thus, objects go out of scope once the method execution completes and can be disposed of by the garbage collector. Because references from old objects to new ones exist in limited numbers, this means that objects that have been present in your application for a long time are usually not newly created objects. Here are a couple of terms that we should be familiar with; one of them is a live object. It is an object in an application that is referenced by another object in the same application. There is also a “dead” object. A dead object is an inaccessible object that is created during a method call, and once the method call completes, the object goes out of context and just sits on the heap.

When is an object eligible for garbage collection?

If an object does not have any reference variable, then the object is eligible for garbage collection.

How to make an object available for garbage collection?

Below are several ways:
  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();

    Once an object is made available to the garbage collector, it is not immediately destroyed.

When the Java Virtual Machine runs the garbage collector, only the object is destroyed. NOTE: The garbage collector only collects objects created using the “new” keyword, for objects without the “new” keyword, use the finalize() method . There are several methods to run the garbage collector in the Java Virtual Machine:
  1. System.gc() method

  2. finalize() method

  3. Runtime.getRuntime().gc() method

The static gc() method is located in the System class . This method asks the JVM to call the garbage collector. Let's see how a Java application calls the garbage collector using the gc() method.
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");
}
}
Result:
object garbage collected object garbage collected
The finalize() method is called just before the object is cleaned up. This method is defined in the Object class :
protected void finalize() throws Throwable
  1. The Finalize method is used to close the connection to the database.

  2. This method is called by the garbage collector, not the JVM.

  3. We need to override the finalize() method . Because it has an empty implementation.

  4. It is called only once per object.

The getRuntime().gc() method is present in the runtime class. It returns the Runtime object associated with the current Java application. Let's look at this method in a Java program.
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);
}
}
Result:
Garbage collector called Object garbage collector: Demo@2130772 Garbage collector called Object garbage collector: Demo@cd4e940

Benefits of garbage collection:

  1. Garbage collection in Java occurs automatically, which saves us from the additional burden of freeing used memory. This makes the Java program's memory more efficient.
  2. Garbage collection ensures program integrity.
  3. We don't need to write any additional code since the garbage collector is part of the JVM.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION