2012-03-20 28 views
9

Podczas tworzenia aplikacji java-app (z NetBeans jako IDE) tworzyłem program rejestrujący, gdy nagle zobaczyłem ostrzeżenie: "Nieefektywne użycie konkatenacji ciągów w rejestratorze".Nieefektywne wykorzystanie konkatenacji ciągów znaków

Mój kod oringinal jest

srcLogger.getLogger().log(Level.INFO,"UploadBean.doUpload completado [" + file.getName() + "]\n"); 

ale NetBeans zasugerował, aby przekształcić go do szablonu podając ten kod (co to jest "szablon" oznacza tutaj):

srcLogger.getLogger().log(Level.INFO, "UploadBean.doUpload completado [{0}]\n", file.getName()); 

Co się różni między nimi dwa sposoby łączenia się, nigdy jednak nie korzystałem z tego drugiego.

Pozdrawiam.

Odpowiedz

11

Zignorowałbym ostrzeżenie (i jeśli to możliwe, wyłącz, jeśli to możliwe). Konkatenacja nie jest tak nieefektywna, ponieważ nowoczesne kompilatory zastępują ją wydajną implementacją opartą na StringBuilder (zobaczysz ją, jeśli spojrzysz na kod bajtowy pliku klasowego).

Sugerowana zamiana nie łączy łańcuchów, ale wymaga dodatkowego przetwarzania, aby przeanalizować szablon i połączyć go z parametrami.

Netbeans, to zła rada.

Dotyczy to środowiska Java 1.5+. Starsze wersje Java (może) stworzyć wiele niewykorzystanych String przypadkach podczas konkatenacji ..

+3

Aby wyłączyć ostrzeżenie (w NetBeans 7.2.1): Preferencje -> Edytor -> Wskazówki -> Rejestrowanie -> Łączenie ciągów w rejestratorze. Opis mówi: " Nie jest wydajne pod względem wydajności łączenie ciągów w komunikatach rejestratora.Jednak lepiej jest użyć szablonu wiadomości z symbolami zastępczymi, które są zastąpione konkretnymi wartościami tylko wtedy, gdy wiadomość rzeczywiście zostanie zarejestrowana." –

+0

Właściwie przegapiłeś jedną z głównych zalet, dodam teraz odpowiedź, mimo że jest późno :) –

+3

Ale ostrzeżenie jest nieefektywne, ponieważ konkatenacja jest zawsze wykonywana w przeciwieństwie do wykonywania jej tylko w zależności od bieżącego poziomu rejestrowania w przypadku korzystania z parametrów ['log (poziom poziomu, ciąg msg, Object []) (https://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html # log-java.util.logging.Level-java.lang.String-java.lang.Object: A-) method. – Adam

4

Ponieważ ciągi są niezmienne w Javie, podczas łączenia obiektów w rzeczywistości tworzysz zupełnie nowy obiekt. Korzystanie z czegoś takiego jak szablon Netbeans sugeruje, lub StringBuilder uniemożliwia stworzenie wszystkich tych pośrednich obiektów, które wymagają czasu i zasobów.

+0

Poza tym, że współczesne kompilatory Java będą używać StringBuilder dla ciebie, to nie jest powód w tym przypadku. –

11

Prawdziwe zwycięstwo tutaj jest to, że nie trzeba robić żadnych ciąg obsługi w ogóle (albo konkatenacji lub szablonu ekspansji), jeśli rejestrator jest skonfigurowany tak, aby nie logował się na poziomie INFO.

Oznacza to, że logger może zdecydować się na nic nie robić, bez konieczności zbliżania się do jakiejkolwiek manipulacji ciągami.

1

Szablon oznacza dokładnie to, przypuszczalnie jest to szablon dla łańcucha, a nie sam łańcuch. Chodzi o to, że bit {0} zostanie zastąpiony pierwszym argumentem, który pojawi się po nim na liście (file.getName()). Jest to zgodne z metodą String.

Nie widziałem żadnych testów wydajności, aby sprawdzić, czy jest to szybsze, czy nie. Jak wskazywały inne odpowiedzi, pozostawienie go tak, jak jest, nie będzie szczególnie powolne, ponieważ zamiast zwykłego Stringa będzie używane przez kompilator. Jednakże, jak zaznacza @dty, myślę, że powinno być szybciej w przypadku, gdy poziom rejestrowania jest ustawiony tak, że instrukcja nie jest faktycznie rejestrowana, ponieważ nie ma pracy wymaganej do skonstruowania ciągu znaków do wyjścia. Ponadto, ponieważ cały ciąg szablonu jest pojedynczym literałem, zostanie on dodany do puli String przez kompilator. Oznacza to, że wszystkie wystąpienia tego konkretnego String będą wskazywać na to samo rzeczywiste wystąpienie - więc jeśli instrukcja nie jest faktycznie zarejestrowana, to nawet nie musi przydzielić pamięci do przechowywania tego ciągu, po prostu wyszukuje, co powinno być bardziej wydajny.

1

Ostrzeżenie otrzymane od NetBeans daje najkrótsze uzasadnienie uniknięcia konkatenacji w dzienniku.

  1. Wiadomości dziennika, które nie zostaną wysłane do dziennika, nie są tworzone podczas używania stylu szablonu. Możesz nawet zoptymalizować styl, unikając wywoływania metod na liście argumentów.

Istnieje jednak kilka innych powodów, dla których należy wybrać styl szablonu dla wiadomości dziennika.

a. Unika możliwości narzutu concat. Jak zauważyli inni, nie jest to ogromny problem z najnowszymi javac.

b. Twój kod jest lepiej przygotowany do internacjonalizacji/lokalizacji. Chociaż możesz pomyśleć ... ten kod nigdy nie będzie wymagał takiego poziomu zainteresowania ... zadziwiające jest, jak daleko kodu idzie po jego początkowym napisaniu.

16

Wiadomość nie odnosi się do kosztu konkatenacji String sama w sobie. Inne odpowiedzi są absolutnie poprawne, gdy mówią, że zostanie użyty StringBuilder.

Głównym powodem używania szablonu wiadomości jest to, że przetwarzanie odbywa się tylko wtedy, gdy wyświetlany jest poziom rejestrowania!

Użyjmy te dwa przykłady:

srcLogger.getLogger().log(Level.INFO,"UploadBean.doUpload completado [" + file.getName() + "]\n"); 
srcLogger.getLogger().log(Level.INFO, "UploadBean.doUpload completado [{0}]\n", file.getName()); 

Z debugowania Poziom Informacje o: Obie mają dostać nazwę pliku z pliku, oba muszą zaktualizować ciąg, generuje nowy, wyświetlić go.

Z poziomem debugowania INFO off: Druga odpowiedź przechodzi przez nazwę obiektu File (który jest prostym zapytaniem), metoda log() sprawdza poziom INFO i natychmiast zwraca. W ogóle nie jest wykonywane przetwarzanie!

Teraz wyobraźmy sobie, że zamiast zwykłego file.getName() rejestrowaliśmy bardziej złożony obiekt, który sam w sobie wymaga dużej ilości łączenia ciągów w metodzie toString(). Logując te obiekty bezpośrednio, żadne przetwarzanie nie jest w ogóle wykonywane. toString() nigdy nie jest wywoływany, chyba że wyświetlany jest poziom debugowania.

Szablon wiadomości nie jest bardziej wydajny w przypadku, gdy rejestrowanie jest wyświetlane, ale jest znacznie bardziej efektywny (szczególnie w przypadku nietrywialnego rejestrowania), gdy rejestrowanie nie jest wyświetlane. Jednym z celów rejestrowania powinno być to, że jeśli rejestrowanie jest wyłączone, ma najmniejszy możliwy wpływ na wydajność systemu.

Powiązane problemy