Monday, May 21, 2012

Java equals ve hashCode Metodlarını kullanmak


Bugün evde işte karşılaştığım bir problemi nasıl çözebileceğimi düşünürken ürettiğim çözümü paylaşmak istiyorum.

Sorunum şu:
  1. Elimde bir liste içerisinde nesneler var. 
  2. Liste içerisinde bir eleman birden çok kez tekrar edebiliyor.
  3. Bana her nesneden yalnızca 1 tane içeren bir liste gerekiyor.
  4. Nesnelerin birbirine eşit olma durumlarını tekil id değerlerine bakarak ayırt edebiliyorum.
Eğer ki Liste içindeki elemanlar Integer, String gibi tiplerde olsaydı liste içerisindeki elemanları HashSet içerisine atarak tekilleştirebilirdim. HashSet bir elemandan sadece 1 tane barındırmayı garanti ediyor. Örnek kod aşağıdaki gibidir. Liste içerisinde 6 eleman yer alırken HashSet içerisinde ise tekil olan "String1", "String2" ve "String3" elamanları yer alıyor.

List<String> stringList = new ArrayList<String>();
stringList.add("String1");
stringList.add("String2");
stringList.add("String2");
stringList.add("String3");
stringList.add("String3");
stringList.add("String3");
  
Set<String> stringSet = new HashSet<String>();
stringSet.addAll(stringList);
  
System.out.println("list size: " + stringList.size());
System.out.println("hash set size: " + stringSet.size());
//derleyici çıktısı
//list size: 6
//hash set size: 3 

Kendi sınıfımda verileri tekilleştirmek için for döngüsü içinde bir şeyler yapmak yerine işi java'ya bırakmaya karar verdim. HashSet'in elemanların tekilliğinin kontrolü için hashCode metodunun ürettiği değeri kontrtol ettiğini biliyorum. hashCode metodu için java dökümantasyonu şöyle diyor:

This method returns the hash code value for the object on which this method is invoked. This method returns the hash code value as an integer and is supported for the benefit of hashing based collection classes such as Hashtable, HashMap, HashSet etc. This method must be overridden in every class that overrides the equals method.

Bir anlaşma olarak equals metodunun override edildiği her sınıftta hashCode metodu da override edilmelidir.
  • Sadece equals metodunu override edersem nesnelerim equals metodu ile eşit görünse de hash kod  değerleri farklı olacak.
  • Sadece hashCode metodunu override edersem nesnelerim aynı hash code değerine sahip olmasına rağmen equals metodu bu 2 nesnesin farklı olduğunu söyleyecek.
Java dökümantasyonu equals metodu ile aynı olan 2 nesnenin aynı hash kod değerine sahip olması gerektiğini söylüyor. Daha ayrıntılı bilgi için yazının sonundaki kaynaklar  bölümünde bulunan linke göz atabilirsiniz. Yararlı bir makale olmuş.

equals metodunu da override etmem gerektiğini düşünüyorum. Böylece  equals metodu ile nesnelerimin eşitlik durumlarını kontrol edebilirim.

Sorunu tekrar edebilmek için aşağıdaki gibi bir sınıf yazıyorum.

package org.guneriu.test.models;

public class Person {

 private Long identityNumber;
 private String name;

 public Long getIdentityNumber() {
  return identityNumber;
 }

 public void setIdentityNumber(Long identityNumber) {
  this.identityNumber = identityNumber;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((identityNumber == null) ? 0 : identityNumber.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if ( this == obj )
   return true;
  if ( obj == null )
   return false;
  if ( getClass() != obj.getClass() )
   return false;
  Person other = (Person) obj;
  if ( identityNumber == null ) {
   if ( other.identityNumber != null )
    return false;
  } else if ( !identityNumber.equals(other.identityNumber) )
   return false;
  return true;
 }

}


Person sınıfının identityNumber alanı benim için tekil bir değer (T.C. no diyelim). HashCode üretirken kullandığımız alanın değişmez (immutable) bir değer olması önemlidir. Aksi takdirde hash tabanlı koleksiyonlarda koleksiyon içerisinden bulunan bir nesnenin hashCode değeri değişirse beklenmedik sorunlar ortaya çıkabilir.

equals ve hashCode metodlarını oturup kendim yazabilirdim. Ancak bu işi Eclipse'e bıraktım. equals ve hashCode metodlarının override edilmesi ile ilgili Java'nın sunduğu bazı tavsiyeler var. Eclipse bunları benim için yerine getirerek güvenliğimi arttırıyor. Eclipse source menü'de (alt + shift + s) "Generate hashCode() and equals()" özelliğini kullandım. Basitçe algoritmada sınıf içerisinde hangi değerleri kullanmak istediğimi sordu ve metodları oluşturdu.

Şimdi çalışıp çalışmadığına bakmak için 4 tane Person nesnesi oluşturuyorum. Bunlarda 2 tanesi aynı identityNumber değerine sahip. Bana tekil olan 3 tane Person nesnesi gerekiyor.

package org.guneriu.test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.guneriu.test.models.Person;

public class PersonTest {


 public static void main(String[] args) {
  Person firstPerson = new Person(123L);
  Person secondPerson= new Person(1234L);
  Person thirdPerson= new Person(12345L);
  Person fourthPerson= new Person(123L);
  
  
  List<Person> personList = new ArrayList<Person>();
  personList.add(firstPerson);
  personList.add(secondPerson);
  personList.add(thirdPerson);
  personList.add(fourthPerson);
  
  Set<Person> personSet = new HashSet<Person>();
  personSet.addAll(personList);
  
  System.out.println("list size: " + personList.size());
  System.out.println("hash set size: " + personSet.size());
  //equals metodunu da kullanarak eşitlik durumuna bakabiliyorum
  System.out.println("is firstPerson equals fourthPerson: " + firstPerson.equals(fourthPerson));
  System.out.println("is firstPerson equals secondPerson: " + firstPerson.equals(secondPerson));
  
  //derleyici çıktısı
  //list size: 4
  //hash set size: 3
  //is firstPerson equals fourthPerson: true
  //is firstPerson equals secondPerson: false
 }
 
}

Kendi algoritmamı yazmak yerine işi Java'ya bırakarak hem zaman kazanıyorum hem ortaya daha temiz bir kod çıkıyor.
Kaynaklar: http://www.technofundo.com/tech/java/equalhash.html

Saturday, May 12, 2012

IDE Metin Editörü Değildir

Java yazmaya başladıktan sonra IDE olarak Eclipse kullanmaya başladım. Kısayolları öğrenmeye başladıktan sonra hayatım fazlasıyla kolaylaştı. Basit işleri mouse kullanmadan daha kolay ve hızlı yapmaya başladım.

Çoğu kimsenin Eclipse'i bir IDE olarak değilde bir metin editörü gibi kullandığını gördüm. Bu başlığı çok uzatmamak için IDE vs Text Editör isimli başka bir başlık açtım, göz atmak isteyebilirsiniz. Bu alışkanlıkları değiştirmek için kod yazan bir iş arkadaşlarımın temel bir işi bildiği yolla yaptığını gördükten sonra onlara bu işi bir kısayolla çok daha hızlı yapabileceğini göstererek ilerledim.
Bu yazıyı yazarken kendi kullandığım kısayolları paylaşmak niyetindeydim. Ancak bu konuda daha iyi bir yazıyı Taner Diler'in bloğunda buldum. Eclipse ve Hayat Kurtaran KısaYol Tuşları isimli yazıya buradan ulaşabilirsiniz.

Bu noktada bir IDE'yi etkili kullanmanın avantajlarından bahsetmek istiyorum.

Normal bir sürüm gecesinden farklı olarak saat gece 4 ve geliştirmeniz testden dönmüş. Bu noktada neden geliştirme o saatte sürümden dönüyor sorusu akıllara geliyor. Haklısınız ama müşteri faktörü deyip geçmek istiyorum. Geliştirmenizin sürüme girmesi gerekiyor. Çalışma arkadaşlarınız sizi bekliyor. Üzerinizde yoğun bir baskı hissediyorsunuz (bilgisayar mühendisi iş ilanlarında bahsedilen stres altında çalışabilme bu olsa gerek :) )
Biraz sakinleşip sorunun buluyorsunuz. Kafanızda çözüm şekilleniyor. Geriye kaldı bunu koda dönüştürmek. Bu noktada bir IDE'yi etkili kullanabilmek hızınızı 2'ye katlayabilir. Hayatımda o gece olduğu kadar hızlı kod yazdığımı hatırlamıyorum :)

Geliştirme yaparken değiştirmem gereken bir sınıf ile uğraşıyorum. Bu sınıf login işlemlerini yöneten bir sınıf. Değiştireceğim metod projede yaklaşık 30 farklı yerden çağrılıyor. Bu noktada bu bilgiye ulaşmak için metod ismini java uzantılı dosyalarda aramak bir çözüm olsa da IDE'nin call hierarchy özelliğini kullanarak bu bilgiye daha sağlıklı bir yoldan ulaşıyorum. Biraz düşündükten sonra bu sınıfın singleton olması gerektiğine karar veriyorum. Değişikliği yapabilmek için kodda sınıfın yenilendiği her yerde
DummyProvider dummyProvider = new DummyProvider();
çağrımını
DummyProvider dummyProvider = DummyProvider.getInstance();
ile değiştirmem gerekiyor. Bu işi teker teker yapmam hem hataya açık bir yöntem hem de fazlasıyla zaman alacak. Eclipse'in rafactoring desteğinden yararlanıyorum. Bu değişikliği "Introduce Factory" rafactoringi ile yapmam sadece 1 dk sürüyor.

Java'da bir sınıf yazarken yazdığı alanların getter/setter metodlarını elle yazanları gördüm.

Sonuç olarak sadece kod tamamlama kullanmak yetmez. IDE'nin sağlamış olduğu özellikleri sonuna kadar kulanmak bize performans sağlayacaktır. IDE'mizi tanıyalım.

IDE vs Text Editor

Etrafınızda vim, emacs gibi metin editörleri kullanan insanlar görmüşsünüzdür. Vim ve Emacs normal bir metin editöründen çok daha fazla kabiliyete sahipler.
Bu araçları çok etkili kullanan çalışma arkadaşlarım var. Vim editörü içerisinde 4 ayrı ile uğraşmak bayağı etkileyici.
Bu editörler bu kadar etkileyici olmasına rağmen ne zaman kullanılmalı sorusu beliriyor kafamda. Bu konudaki gözlemlerimi aktarmak istiyorum. Java, C# gibi bir dille uğraşıyorsam tercihim her zaman bir IDE'den yanadır.
Zamanında C# yazmış birisi olarak Visual Studio olmaksızın .NET platformunu düşünemiyorum. Java yazan birisi olarak Eclipse, Intellij Idea veya NetBeans olmaksızın Java yazmanın anlamsız olduğunu düşünüyorum. Bu noktada bir IDE'nin bize sunacakları hayatımızı fazlasıyla kolaylaştırıyor.
Javascript, html, css yazacaksam Vim editörü fazlasıyla işimi görüyor. Javascript, html, css, php, python ile uğraşan insanların vim, emacs kullanması gayet mantıklı geliyor.
Hala ben Java'yı metin editörü ile de yazarım diyenlere tavsiyem bir IDE'yi metin editörü gibi değil IDE gibi kullanmaya çabalamaları olacaktır.
Vim ve Emacs'i kısayolları öğrenmeden kullanamayacağınız gibi bir IDE'yi de kısayollarını, özelliklerini öğrenmeden etkili olarak kullanamazsınız.
Stackoverflow'da IDE or Text Editör başlığı belki ilginizi çekebilir.

Sunday, May 6, 2012

The Avengers Filmi Kritiği

The Avengers

Captain America t-shirt'ümü giyip The Avengers (Yenilmezler) filmini izledikten sonra film hakkında birkaç şey yazmak istedim.
Marvel karakterleri tutkunu birisi olarak Marvel kahramanları ile alakalı hemen hemen tüm film ve animeleri izlemeye çalışıyorum. The Avengers filminden önce 2 adet anime filmi çekilmişti bunları izlemenizi tavsiye ederim.

Ayrıca hala devam etmekte olan The Avengers Earth's Mighties Heroes anime dizisi mevcut.

Filmde Iron Man, Hulk, Thor, Captain America, Black Widow, Hawkeye, Loki, NickFury rol alıyor.
Loki ve ordusuna karşı Avengers'lar dünyayı kurtarmaya çalışıyorlar. Konu bundan ibaret diyebilirim.

Geçen arkadaşımla yaptığımız sohbetde Hulk karakterini neden Edward Norton'un oynamadığını tartışıyorduk. Edward Norton'u ne kadar sevsem de Mark Ruffalo animelerde gördüğüm Bruce Banner'a çok fazla benziyor. Bruce Banner rolünü çok iyi oynamış.

Iron Man rolünde Robert Downey Jr. yine neşeli bir karakter sergiliyor. Tony Stark'ın küstah esprili hali fazlasıyla kullanılmış. Tony Stark'dan söz etmişlen onun yapay zekaya sahip bilgisayarı Jarvis'den bahsetmemek olmaz. Birgün bir yapay zekaya sahip bilgisayara Jarvis ismi verilirse şaşırmam. Eğer o bilgisayarı ben yapıyor olsam ismini Jarvis koyardım.

Daha önce Thor'da gördüğümüz Hawkeye filmde etkileyici ama animelerde fazlasıyla geveze bir karakter olarak görünüyordu.

Dikkat buradan sonrası spoiler içermektedir.

Filmin ilk yarısı hazırlık süreciyle geçiyor. Ancak 2. yarısında aksiyon görebiliyoruz. Filmi beğendim mi sorusunda cevabım Marvel ne yapsa izlerim oluyor. Ancak daha iyi kurgulanabilirdi gibime geliyor.

Filmdeki en iyi repliklerden biri.
- Loki: Benim bir ordum var.
- Iron Man: Bizde Hulk var.

Filme gideceklere uyarı:
Tüm Marvel filmlerinde olduğu gibi bu filmde de filmin sonunda, oyuncu isimleri sunulduktan sonra kısa bir bölüm daha yer alıyor. Genelde bu bölüm filmin devamı ya da başka bir Marvel filmi ile alakı oluyor. Film biter bitmez sinemanın %90'ı salonu terketti. Kalanlar 2. film hakkında küçük bir özet izledi.