Sayfalar

7 Ekim 2015 Çarşamba

Java Performans Notları: Autoboxing / Unboxing

0 yorum
English version is at DZone

Aşağıdaki kod parçasında sadece 1 karakteri değiştirerek, işlem süresini yaklaşık 5’te 1’ine indirebileceğimizi söylesem ne düşünürsünüz?

long t = System.currentTimeMillis(); Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println("toplam:" + sum); System.out.println("işlem süresi: " + (System.currentTimeMillis() - t) + " ms") ;

Çıktı:
toplam:2305843005992468481
işlem süresi:  6756 ms



Yukarıdaki kod parçası hakkında biraz düşündükten sonra, aşağıdaki daha hızlı çalışan kod parçasını inceleyebilirsiniz.

long t = System.currentTimeMillis(); //Long sum = 0L; long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println("toplam:" + sum); System.out.println("işlem süresi: " + (System.currentTimeMillis() - t) + " ms") ;

Çıktı:
toplam:2305843005992468481
işlem süresi: 1248 ms

Yukarıdaki hız farkının, Java 1.5 ile hayatımıza giren “Autoboxing” özelliğinin dikkatsiz kullanımından kaynaklandığını söyleyebiliriz.

Farkın nedenine devam etmeden, öncelikle Java’da “Autoboxing” ve “Unboxing” kavramını açıklamaya çalışalım. 

Java’da tipler primitive ve referans olmak üzere ikiye ayrılmaktadır. Java’da 8 adet primitive tip bulunmaktadır. Her primitive tipe karşılık gelen de bir referans tipi(wrapper class) vardır. 

Primitive tipler
Referans Tipler(Wrapper Class)
boolean
Boolean
byte
Byte
char
Character
float
Float
int
Integer
long
Long
short
Short
double
Double

Aşağıdaki örnek kod parçasında autoboxing ve unboxing kavramlarına birer örnek görebilirsiniz. Burada Long bekleyen bir ArrayList’e long bir değer eklenmektedir. Java 1.4’te bu işlemin yapılabilmesi için primitive değerin uygun bir referans tip içine eklenerek(boxing) yapılması gerekirdi. Java 1.5 itibariyle bu işlemi compiler bizim için yapmaktadır. Böylece fazladan kod yazmak zorunda kalmıyoruz.

Yani aşağıdaki kod;

List<Long> longList = new ArrayList<>(); long i = 4; longList.add( i ); //autoboxing long j = longList.get( 0 ); //unboxing

compiler tarafından otomatik olarak aşağıdaki koda çevrilmektedir.

List<Long> longList = new ArrayList<>(); long i = 4; longList.add(Long.valueOf( i ) ); long j = longList.get( 0 ).longValue();

Buradan ilk kodumuzun da aslında aşağıdaki gibi bir koda çevrildiğini söyleyebiliriz. Bu işlemin uzun sürmesinin nedenini de kod çalışırken, 2147483647 adet gereksiz Long instance’ı oluşturmaya çalışması olarak açıklayabiliriz.

long t = System.currentTimeMillis(); Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += new Long(i); } System.out.println("toplam:" + sum); System.out.println("işlem süresi: " + (System.currentTimeMillis() - t) + " ms") ;

Çıktı:
toplam:2305843005992468481
işlem süresi: 6764 ms

Sonuç olarak, daha hızlı çalışacak Java kodları yazmak için, autoboxing ve unboxing durumlarını dikkate almalıyız. Gereksiz instance oluşturma işlemlerinden kaçınmalı, hesap gerektiren çoklu işlemlerde primitive tipleri tercih etmeliyiz diyebiliriz.

Yararlandığım Kaynaklar
Autoboxingand Unboxing
Autoboxing


ali kemal taşçı