JavaRush /Blog Java /Random-PL /Przerwa kawowa #88. Siła metadanych: jak pracować z kodem...

Przerwa kawowa #88. Siła metadanych: jak pracować z kodem spaghetti. Odśmiecanie w Javie – jak to działa i jakie są jego zalety

Opublikowano w grupie Random-PL

Siła metadanych: jak pracować z kodem spaghetti

Źródło: Hackernoon Wszyscy staramy się wykorzystywać wspólne podejścia i znane wzorce, aby stworzyć aplikację przy minimalnym wysiłku i maksymalnym wpływie. Mamy doskonałe biblioteki i potężne frameworki, które wykonują za nas rutynowe operacje. Wykorzystujemy to wszystko, aby skupić się wyłącznie na logice biznesowej. Jednak to dążenie często prowadzi nas do kodu spaghetti, zwłaszcza jeśli chodzi o implementację funkcji bez gotowego rozwiązania. W tym artykule chcę podzielić się z Wami jednym potężnym narzędziem, które z mojego doświadczenia wynika, że ​​nie wszyscy programiści doceniają. Narzędzie to występuje w większości języków programowania i bardzo często wykorzystywane jest w wielu frameworkach - adnotacjach. Przerwa kawowa #88.  Siła metadanych: jak pracować z kodem spaghetti.  Zbiórka śmieci w Javie – jak to działa i jakie są jego zalety – 1

Lubisz spaghetti?

Spójrzmy na przykład, na który natknąłem się kilka lat temu. Musiałem przeanalizować arkusz kalkulacyjny Excel, aby umieścić przeanalizowane dane w bazie danych. Chciałem także zebrać część danych z bazy danych i stworzyć arkusz kalkulacyjny. Do wdrożenia wykorzystałem dobrze znaną bibliotekę Java - Apache POI. API biblioteki ułatwia pracę, ponieważ umożliwia ręczne utworzenie arkusza, wiersza, komórki i innych elementów. To bardzo dobrze, ale gdy konieczne jest wygenerowanie różnych arkuszy kalkulacyjnych Excel, kod staje się całkowicie nieczytelny i nieobsługiwany. W rezultacie, jak to zwykle bywa, pierwsza wersja aplikacji okazuje się po prostu fatalna. Implementacja składała się z klasy danych, która reprezentowała ciąg znaków ze wszystkimi polami potrzebnymi do analizy. Dostępny był także parser, w którym pola Excela były analizowane komórka po komórce i umieszczane w nowo utworzonej instancji klasy danych. Na początku program działał świetnie i robił to, co było od niego wymagane. Problemy zaczęły się, gdy przyszedł czas na wprowadzenie pewnych modyfikacji; kod nie został odczytany. Nawet ja, który napisałem ten kod, nie mogłem znaleźć odpowiedniego miejsca na umieszczenie nowych linii w celu zaimplementowania nowej funkcji, której potrzebowałem.

Ratunek w adnotacjach

Zapisano aplikację z tego kodu spaghetti adnotacji. Aby pozbyć się nieobsługiwanego kodu, musiałem przenieść logikę określania, którą kolumnę należy przeanalizować, jaki typ danych zawiera komórka i wszystko inne, w inne miejsce. W tym celu utworzyłem adnotację, w której podałem nazwę kolumny dla każdego pola klasy. W adnotacji dodałem także zmienną pozwalającą wybrać kolor i czcionkę komórki. Tym samym kod w klasie parsującej został znacząco zredukowany. Tylko jeden procesor dynamicznie tworzył arkusz kalkulacyjny na podstawie parametrów pobranych z adnotacji. To było zwycięstwo. Następnie, aby dokonać jakichkolwiek zmian w aplikacji, wystarczyło utworzyć klasę z adnotacjami. Rozwiązanie przypominało bibliotekę Jacksona, która analizuje JSON za pomocą adnotacji i myślę, że nie trzeba mówić, jak wygodne są biblioteki Jacksona lub podobne.
@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);
Wraz z ewolucją aplikacji otrzymała nową adnotację, za pomocą której można było utworzyć w arkuszu kalkulacyjnym komórkę zawierającą funkcję. Różne pola można mnożyć, odejmować i używać dowolnych popularnych funkcji programu Excel. Dodałem także wiersz sumy, aby pokazać sumę według kolumn. A wszystko to zrobiłem po prostu nieznacznie modyfikując główny parser i po prostu dodając adnotacje do klas.
@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() + ")";
    }

Odśmiecanie w Javie – jak to działa i jakie są jego zalety

Źródło: Dev.to Garbage zbieranie oznacza niszczenie lub czyszczenie nieużywanych obiektów w pamięci. Java automatycznie obsługuje zwalnianie pamięci, ponieważ po utworzeniu obiektu zużywa część pamięci na stercie. Przerwa kawowa #88.  Siła metadanych: jak pracować z kodem spaghetti.  Odśmiecanie w Javie – jak to działa i jakie są jego zalety – 2

Jak to działa?

Przed Javą najpopularniejszym językiem programowania był C lub C++. Jeśli znasz te języki, powinieneś wiedzieć, że ręcznie zarządzają one swoją pamięcią. Na przykład C ma metody takie jak calloc() , malloc() i realloc() , które pozwalają na użycie pamięci buforowej. Musisz określić, ile pamięci potrzebujesz dla swojego programu i określić, co jest wywoływane przez to API. Następnie możesz uzyskać bufor pamięci, aby utworzyć połączony węzeł listy lub coś innego. Kiedy program się kończy, w pewnym momencie jesteś także odpowiedzialny za oczyszczenie tej pamięci. Zatem duża aplikacja napisana w C stale przydziela pamięć buforową i czasami zapomina ją opróżnić. To ostatecznie powoduje wycieki pamięci i wiele problemów w aplikacji. W przeciwieństwie do C i C++, język Java jest wyposażony w automatyczne zarządzanie pamięcią poprzez wątek zwany modułem zbierającym elementy bezużyteczne. Jego głównym celem jest zwolnienie pamięci sterty poprzez niszczenie niedostępnych obiektów. Moduł zbierający elementy bezużyteczne zawsze działa w tle.

Jakie są niedostępne obiekty w Javie?

Kiedy obiekt ma szansę rozpocząć zbieranie elementów bezużytecznych? Jeśli są niedostępne obiekty - takie, dla których nie ma aktywnych linków. Zobaczmy przykład:
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;
}
W metodzie głównej utworzyłem obiekt StringBuffer i referencję do niego. W tym momencie obiekt StringBuffer nie kwalifikuje się do usuwania elementów bezużytecznych. Teraz ustawię obiekt StringBuffer na „null”. Obiekt kwalifikuje się teraz do usuwania elementów bezużytecznych i staje się obiektem niedostępnym w pamięci sterty. Oznacza to, że zbieranie elementów bezużytecznych na ogół działa w przypadkach, gdy obiekty stają się niedostępne. Oznacza to, że obiekty są zwykle tworzone w kontekście bloku lub metody „if”. W ten sposób obiekty wychodzą poza zakres po zakończeniu wykonywania metody i mogą zostać usunięte przez moduł wyrzucający elementy bezużyteczne. Ponieważ odniesienia ze starych obiektów do nowych istnieją w ograniczonej liczbie, oznacza to, że obiekty, które są obecne w Twojej aplikacji od dłuższego czasu, zwykle nie są obiektami nowo utworzonymi. Oto kilka terminów, które powinniśmy znać; jeden z nich jest obiektem żywym. Jest to obiekt w aplikacji, do którego odwołuje się inny obiekt w tej samej aplikacji. Jest też obiekt „martwy”. Martwy obiekt to niedostępny obiekt, który jest tworzony podczas wywołania metody, a po zakończeniu wywołania metody obiekt wychodzi z kontekstu i po prostu znajduje się na stercie.

Kiedy obiekt kwalifikuje się do wyrzucenia śmieci?

Jeśli obiekt nie ma żadnej zmiennej referencyjnej, wówczas kwalifikuje się do odśmiecania.

Jak udostępnić obiekt do zbierania śmieci?

Poniżej kilka sposobów:
  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();

    Gdy obiekt zostanie udostępniony modułowi wyrzucania elementów bezużytecznych, nie jest on natychmiast niszczony.

Kiedy wirtualna maszyna Java uruchamia moduł zbierający elementy bezużyteczne, niszczony jest tylko obiekt. UWAGA: Moduł zbierający elementy bezużyteczne zbiera tylko obiekty utworzone przy użyciu słowa kluczowego „new”, w przypadku obiektów bez słowa kluczowego „new” należy użyć metody finalize() . Istnieje kilka metod uruchamiania modułu zbierającego elementy bezużyteczne w wirtualnej maszynie Java:
  1. Metoda System.gc().

  2. metoda finalizacji().

  3. Metoda Runtime.getRuntime().gc().

Statyczna metoda gc() znajduje się w klasie System . Ta metoda prosi maszynę JVM o wywołanie modułu zbierającego elementy bezużyteczne. Zobaczmy, jak aplikacja Java wywołuje moduł zbierający elementy bezużyteczne za pomocą metody 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");
}
}
Wynik:
Zebrane śmieci obiektowe. Zebrane śmieci obiektowe
Metoda finalize() jest wywoływana tuż przed oczyszczeniem obiektu. Metoda ta jest zdefiniowana w klasie Object :
protected void finalize() throws Throwable
  1. Metoda Finalize służy do zamykania połączenia z bazą danych.

  2. Ta metoda jest wywoływana przez moduł zbierający elementy bezużyteczne, a nie maszynę JVM.

  3. Musimy zastąpić metodę finalize() . Ponieważ ma pustą implementację.

  4. Jest wywoływana tylko raz na obiekt.

Metoda getRuntime().gc() jest obecna w klasie wykonawczej. Zwraca obiekt Runtime powiązany z bieżącą aplikacją Java. Przyjrzyjmy się tej metodzie w programie 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);
}
}
Wynik:
Odśmiecacz o nazwie Odśmiecacz obiektów: Demo@2130772 Odśmiecacz o nazwie Odśmiecacz obiektów: Demo@cd4e940

Korzyści ze zbiórki śmieci:

  1. Odśmiecanie w Javie odbywa się automatycznie, co oszczędza nam dodatkowego ciężaru zwalniania używanej pamięci. Dzięki temu pamięć programu Java jest bardziej wydajna.
  2. Wyrzucanie śmieci zapewnia integralność programu.
  3. Nie musimy pisać żadnego dodatkowego kodu, ponieważ moduł zbierający elementy bezużyteczne jest częścią maszyny JVM.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION