Czy istnieje jakiś powód wydajnościowy, aby deklarować parametry metody jako ostateczne w Javie?

117

Czy istnieje jakiś powód wydajnościowy, aby deklarować parametry metody jako ostateczne w Javie?

Jak w:

public void foo(int bar) { ... }

Przeciw:

public void foo(final int bar) { ... }

Zakładając, że barjest to tylko do odczytu i nigdy nie modyfikowane w foo().

Wyrko
źródło
Nie mogę wymyślić powodu, dla którego kompilator miałby się przejmować, czy zadeklarowałeś parametr metody jako końcowy, czy nie. Ale prawdziwa odpowiedź na to pytanie brzmi - napisz dwie funkcje, jedną z parametrami końcowymi, a drugą z parametrami regularnymi. Uruchom je milion razy i zobacz, czy jest jakaś zauważalna różnica w czasie wykonywania. Jeśli martwisz się o wydajność, bardzo ważne jest, aby wykonać pewne prace związane z profilowaniem kodu i dowiedzieć się, co dokładnie Cię spowalnia. Prawie na pewno nie jest to, czego byś się spodziewał :)
Mike Blandford
1
Sugerowałbym, abyś nigdy nie pisał mikro-benchmarków. Nie wiesz, jaką optymalizację może wykonać JIT i kiedy, i prawdopodobnie miałbyś błędne wyobrażenie o tym, jak się zachowuje, wykonując tylko „prosty przypadek testowy”
Edmondo1984
cóż, może tak być, ale nikt tutaj nie napisał ani nie zasugerował mikroznaku ...
Kip
1
Odpowiedź @Mike'a Blandforda sugeruje użycie mikro-testu, prawda?
Ben Page
Pisanie mikro-benchmarków w Javie jest czymś bardzo trudnym
Edmondo1984,

Odpowiedzi:

97

Ostatnie słowo kluczowe nie pojawia się w pliku klasy dla lokalnych zmiennych i parametrów, dlatego nie może wpływać na wydajność środowiska wykonawczego. Służy jedynie do wyjaśnienia zamiaru programistów, aby zmienna nie była zmieniana (co wielu uważa za wątpliwy powód jej użycia) i radzenia sobie z anonimowymi klasami wewnętrznymi.

Istnieje wiele argumentów na temat tego, czy ostateczny modyfikator samej metody ma jakikolwiek wzrost wydajności, ponieważ metody i tak zostaną wbudowane przez optymalizujący kompilator w czasie wykonywania, niezależnie od modyfikatora. W tym przypadku należy go również używać tylko do ograniczenia nadpisywania metody.

Rudzik
źródło
5
można by pomyśleć, że końcowe zmienne / parametry mogą być zoptymalizowane jako zmienne pętlowe ... ale dobry kompilator / środowisko uruchomieniowe i tak powinien być w stanie to rozgryźć bez finału ...
John Gardner
9
Widziałem, jak kompilator Sun'a emitował nieznacznie krótszy kod bajtowy, podczas gdy jedyną różnicą między tymi dwiema metodami była „ostateczność” zmiennych lokalnych. Mikrooptymalizacje to rzeczywistość, a kompilatory faktycznie je tworzą. To, co naprawdę ma znaczenie, to oczywiście to, co JIT robi z kodem bajtowym, a lokalne odwołania tracą swoją „ostateczność” po kompilacji do kodu bajtowego. Myślę, że właśnie dlatego jest tak wiele spekulacji na temat końcowych zmiennych lokalnych: wyniki są dość niedeterministyczne. Jednak użycie ostatecznych lokalizacji lokalnych może wpłynąć na kod bajtowy - bez względu na to, co jest warte.
Christopher Schultz,
Ponieważ nie jest deterministyczny, tak naprawdę nie ma sposobu, aby polegać na optymalizacji. Oczywiście wiele mogło się zmienić w implementacjach maszyn wirtualnych od czasu oryginalnej odpowiedzi w 2008 roku ;-)
Robin
15

Jedyną zaletą końcowego parametru jest to, że można go używać w anonimowych klasach zagnieżdżonych. Jeśli parametr nigdy nie zostanie zmieniony, kompilator już wykryje to w ramach swojej normalnej pracy, nawet bez końcowego modyfikatora. Rzadko zdarza się, że błędy są spowodowane nieoczekiwanym przypisaniem parametru - jeśli twoje metody są wystarczająco duże, aby wymagać tego poziomu inżynierii, zmniejsz je - metody, które wywołujesz, nie mogą zmienić parametrów.

Dobes Vandermeer
źródło
8
„Bardzo rzadko zdarza się, że błędy są spowodowane nieoczekiwanym przypisaniem parametru”. To bardziej powszechne niż myślisz ...
RAY
2
@RAY, możesz mieć rację, w rzeczywistości nie mam żadnych danych (poza własnym doświadczeniem) na poparcie tego twierdzenia.
Dobes Vandermeer
@DobesVandermeer, mówiąc dokładniej, nie jest to tak naprawdę „korzyść dla końcowego parametru ”. To, co opisujesz, jest po prostu wymaganą składnią dla wszelkich zmiennych lokalnych (do których dołączam parametry jako), aby były widoczne dla lokalnego zakresu anonimowej klasy zagnieżdżonej.
swooby
0

Kompilatory działające po załadowaniu klasy, takie jak kompilatory JIT, mogą korzystać z metod końcowych. W konsekwencji metody uznane za ostateczne mogą przynieść pewne korzyści w zakresie wydajności.

http://www.javaperformancetuning.com/tips/final.shtml

Aha i kolejny dobry zasób

http://mindprod.com/jgloss/final.html

branchgabriel
źródło
10
Pytanie dotyczyło zadeklarowania parametrów jako ostatecznych, co nie ma wpływu na wydajność.
Robin
Na współczesnym JIT'S (Hotspot) finał nie ma żadnego (mierzalnego) wpływu na wydajność, czy to w odniesieniu do parametrów, czy klasy
kohlerm
2
Dwa artykuły, które łączysz, sugerują, że final jest raczej znacznikiem semantycznym dla programistów i że kompilatory JIT mogą używać final (ale jak zauważyli inni, tak naprawdę nie potrzebują tych informacji). Tak więc finał jest raczej semantyczny, co jest równoległe do zdolności współczesnych kompilatorów C / ++ do wnioskowania o stałości zmiennych i metod, nawet jeśli nie są one jawnie oznaczone jako const.
ron
0

Jeszcze tylko jeden punkt wyżej, niż użycie nieostatecznych zmiennych lokalnych zadeklarowanych w metodzie - instancja klasy wewnętrznej może przeżyć ramkę stosu, więc zmienna lokalna może zniknąć, gdy obiekt wewnętrzny wciąż żyje

user666
źródło
-2

Zakładam, że kompilator mógłby ewentualnie usunąć wszystkie prywatne statyczne zmienne końcowe, które mają typ prymitywny, taki jak int, i wstawić je bezpośrednio do kodu, tak jak w przypadku makra C ++.

Nie mam jednak pojęcia, czy robi się to w praktyce, ale można to zrobić, aby zaoszczędzić trochę pamięci.

user1402866
źródło
Nie chodzi o końcowe zmienne statystyk prywatnych.
Markiz Lorne