JavaRush /Java Blog /Random-TW /喝咖啡休息#88。元資料的力量:如何使用義大利麵條式程式碼。Java 中的垃圾收集 - 它是如何運作的以及它的優點...

喝咖啡休息#88。元資料的力量:如何使用義大利麵條式程式碼。Java 中的垃圾收集 - 它是如何運作的以及它的優點是什麼

在 Random-TW 群組發布

元資料的力量:如何使用義大利麵條式程式碼

來源: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;
}
在 main 方法中,我建立了一個StringBuffer物件及其參考。此時,StringBuffer物件不符合垃圾回收條件。現在我要將StringBuffer物件設定為「null」。該物件現在符合垃圾回收條件,並成為堆記憶體中不可存取的物件。也就是說,垃圾收集通常在物件變得不可訪問的情況下起作用。這意味著物件通常是在「if 區塊」或方法的上下文中建立的。因此,一旦方法執行完成,物件就會超出範圍,並且可以由垃圾收集器處理。由於從舊物件到新物件的參考數量有限,這意味著應用程式中長期存在的物件通常不是新建立的物件。以下是我們應該熟悉的幾個術語;其中之一是活體物體。它是應用程式中的一個對象,被同一應用程式中的另一個對象引用。還有一個「死」的物體。死對像是在方法呼叫期間建立的不可存取的對象,一旦方法呼叫完成,該對象就會脫離上下文並僅位於堆上。

對象什麼時候適合垃圾回收?

如果物件沒有任何引用變量,則該物件有資格進行垃圾回收。

如何使物件可用於垃圾回收?

下面有幾種方法:
  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");
}
}
結果:
對象垃圾收集 對象垃圾收集
Finalize() 方法在物件被清理之前呼叫。該方法在Object類別中定義:
protected void finalize() throws Throwable
  1. Finalize方法用於關閉與資料庫的連線。

  2. 該方法由垃圾收集器調用,而不是 JVM。

  3. 我們需要重寫finalize()方法。因為它有一個空的實作。

  4. 每個物件僅呼叫一次。

getRuntime().gc()方法存在於運行時類別。它會傳回與目前 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);
}
}
結果:
稱為物件垃圾收集器的垃圾收集器:Demo@2130772 稱為物件垃圾收集器的垃圾收集器:Demo@cd4e940

垃圾收集的好處:

  1. Java 中的垃圾收集是自動發生的,這使我們免於釋放已使用記憶體的額外負擔。這使得Java程式的記憶體更有效率。
  2. 垃圾收集確保程序完整性。
  3. 我們不需要編寫任何額外的程式碼,因為垃圾收集器是 JVM 的一部分。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION