Cumartesi, Mart 29, 2008

F# Nedir?

Bu makalemizde kolay, basit, tipleri fonksiyonel olarak programlayabilen ve yepyeni bir dil olan F#(Fsharp) ‘ı incelemeye çalışacağız.

Yeni çıkmış olan bir dili anlatan makaleler genellikle programlama dilini ve dilin oluşmasını sağlayan etmenlere değinerek giriş yapar. Bizde bu makalemizde bu yolu izleyerek başlayacağız. Temel etmenlere de değinmeden önce daha önemli olan “F# nedir” ‘i ve “Fonksiyonel Programlama nedir” ‘i incelemek daha mantıklı olacaktır.

Fonksiyonel Programlama Nedir?

Fonksiyonel programlama (FP) çok eski zamanlardan, ileri düzey programlama dillerinden beri kullanılan bir yapıydı. FP ‘yi 1955 yılında IPL bulmuştur. İlk olarak ise FORTRAN dili tarafından kullanılmıştır. İkinci olarak kullanan dil COBOL olmuştur. FORTRAN ve COBOL prosedürsel bir mantıkla programlarını oluşturabilme olanağı tanıdığı için bilimden mühendisliğe kadar birçok alanda kullanılmışlardır. Bu mantık 1970 ’li yıllara kadar devam ettikten nesne tabanlı programlama çıkarılmıştır. Nesne tabanlı programlama mantığını kullanabilen programlama dilleri günümüzün en popüler dileri arasında yer almaktadırlar. Kullanmayanlar ise büyük oranda arka plana itilmişlerdir.

Mimari mantıklar bu oranda geliştirilirken fonksiyonel programlama dilleri de kararlı ve güçlü bir biçimde geliştirilmeye devam etmişlerdir. En güçlü fonksiyonel programlama dilleri: SML, OCaml, Haskell, Clean ve diğerleridir. En çok sevilen fonksiyonel programlama dilleri ise: APL ve List ‘dir. Tabii bu bahsettiğimiz dillerin yaşadığı zamanlar 1950 lerdir. Fakat akademik çevreler fonksiyonel programlama kavramını birinci öncelik olarak tutarak geliştirmeye devam etmişlerdir. Bu gelişimlerden de en çok söz getirenleri İngiltere Cambridge üniversitesinde gerçekleştiği akademik yayınlar ile bütün dünyaya duyurulmaktaydı. Çok öncelerden tamamlanmış olan bu dil global dünyanın gerçekleri ile karşılaştığında ise on yıllar önce ömrünü tamamlamış olarak görülüyordu. Fakat yurtdışındaki üniversitelerde karmaşık ve oldukça zor problemler fonksiyonel programlama ile çözülmeye devam edilmiştir. Zaten bu gelişimlerin bir yansısı olarak ta günümüzde birçok üniversitede mühendislik bilimleri fakültelerinde ders olarak okutulmakta olan MATLAB programının oluşmasına sağlamıştır. Matlab programının özelliği matematiksel, fiziksel ve mühendisteki birçok işlemi oldukça kolay fonksiyonlarla yapabilmemize olanak tanıyordu. Ayrıca kolay fonksiyonlar ile yapılabilmesinin dışında oldukçada performanslıydı. Fakat matematiksel işlemleri günümüz programlama dilleri ile yapmaya çalıştığımızda performans olarak ne Matlab ‘te ne fonksiyonel programlama da ne de bu yapıda olan programlama dilleri ile alabildiğimiz sonuçları alamıyorduk. Bugün ise, fonksiyonel programlama kavramını net olarak anlayabilmemiz durumunda en karmaşık problemleri bile çok basit yöntemlerle çözebileceğimiz belirtiliyor.

Fonksiyonel programlama, bütün programlama dillerinin derlemlerini (collection) başka fonksiyonlardan etkilenmemiş biçimde alarak bağımsız değişkenlerini geri dönüş değerleri olarak kabul eder. Nesne tabanlı programlama gerek görülmeyen problemlerin döngülerinin sonucunda oluşan yan ektilere izin vermektedir. Veri yapıları olarak kullandığımız tiplerin büyük bir çoğunluğunu, bellek yönetim kodlarımızı ve diğer birçok alıştığımız mantıkları fonksiyonel programlama ile kullanabilmemiz mümkündür.

Basit matematiksel modellerden yararlanılarak çözülebilen uygulamalar az ve öz kod yazılarak, uygulamalarımızı geliştirecek olduğumuz uygulamalarda yalnızca gerekli olan bileşenlerin referansa edilmesi ve görev çubuğunda minimum düzeyde bellek sarfiyatı yapması gibi özellikler fonksiyonel programlamanın temel yapı taşlarını oluşturmaktadır. Günümüzde fonksiyonel programlamayı kullanabileceğimiz dil F# ‘dır. F# ‘da fonksiyonel programlar yardımı ile karmaşık uygulamaları rahatlıkla geliştirebilmemiz mümkündür.

Niçin Fonksiyonel Programlama Önemlidir?

Fonksiyonel programlamayı düşünen insanlar genellikle kusurlu, hatalı, yaklaşılmaması gereken dil olarak görürlerdi. Fakat bunu düşünen insanları fonksiyonel programlananın kendilerine katacağı avantajları düşünmeden bu tür yargıları düşünüyorlar. Tartışılan bir diğer nokta ise günümüz programlama dilleri ile yaptığımız işleri fonksiyonel programlama dili yapamayacağımız yönünde şekillenmiştir. Günümüz dünyasında fonksiyonel programlamanın avantajlarını her durumda reddeden insanlara karşı tartışmalar esnasında verilmiş en iyi cevabı Chalmer teknik üniversitesinden John Hughes vermiştir. ( http://www.math.chalmers.se/~rjmh/Papers/whyfp.html )

John Hughes derki, “Fonksiyonel programcıların(FP) konuştukları orta çağ rahiplerinin konuştuklarına benzetilmemelidir. Çünkü FP ‘cılar bu dili sevdikleri için geliştirmektedirler. Rahipler ise maddi çıkar için işlerini yapmaktadırlar.”

Bir örnek ile fonksiyonel programlamayı anlatmak gerekirse, kendimizin düşünerek oluşturduğumuz fonksiyonların değerlini başka fonksiyonlara aktarabilmemize olanak tanınmaktadır. Bu özellik sizlere ilk görüşte önemsiz gelebilir, fakat değerlerin kullanılmasını olağanüstü oranda arttırmaktadır. Ayrıca veri ve fonksiyonlar arasındaki anlam farklarını da birbirinden rahatlıkla ayırabilmekteyizdir. Fonksiyonel programlama da kullanılan kısa ve basit yapıya nesne tabalı programlamalarda uymak zorundadır ve uymaktadırlar.

Ayrıca, fonksiyonları geri dönüş değerleri çokluda olabilmekte ve çağırılan fonksiyonların boşa kullanılması önlenmektedir. Bu mantığa uygun örnekleri gelecek makalelerimizde vereceğiz.

F# Nedir?

Fonksiyonel programlama çözülmesi zor olan bilgisayar problemlerini basit yöntemler ile çözmemize yarıyor fakat genel programlama teknikleri ile yapılan çözümler için yeterince iyi değildi. Bu nedenle fonksiyonel programlama nesne tabanlı programlama mimarisinin mantıki yapısını da bünyesine katarak işlemlerin daha rahat yapılabilmesine olanak tanır. Nesne tabanlı mimari yapısını bünyesine katarken de fonksiyonel programlama prensiplerinden vazgeçilmeden bu hafif geçiş yapılmıştır. Birleşimlerin sonucunda da karşımıza diğerlerinin özelliklerini taşıyan fakat kendine özgü olan bir dil ortaya çıkmıştır. Bu dilin adı ise F# ‘dır. F#, fonksiyonel programlama dilinin daha da iyileştirilmiş halidir.

Diğer popüler fonksiyonel programlama dillerinden OCaml, Haskell, Lisp ve Scheme dillerinin içerikleri, geleneksel kullanım yapıları ve gereklilikleri F# dilinin içerisine çalışma prensibine zarar vermeyecek şekilde eklenmiştir. Ayrıca F# .NET dilinin gücünü de diğer dillerle birlikte bünyesine katmıştır. F#, yaratıcıları tarafından araştırmalar sonrasında kriterlere uygun ve düzgün görülen üç dilin birleştirilmesi sonucunda oluşmuştur. F# ile problemlerin üzerinden çalışılması ve çözüm yollarını ararken uğraştığımız metotların azalması avantajları arasında yer almıştır. F#, karmaşık fonksiyonların çözüm yöntemlerine getirdiği yaklaşımların çabukluğu açısından fonksiyonel programlamaya benzemesi ile birlikte günümüzün en iyi mimarisi olarak kabul edilen nesne tabanlı programlama tekniğini de problem çözümlerinde kullanabilmesi iyi kabul edilebilecek yaklaşımlarıdır. Üç farklı dilin birleşiminden oluştuğundan bahsetmiştik. F# oluşurken yararlandığı ilk yapı .net olmuştur. .NET ‘in temel sınıf kütüphanelerini kullanılmıştır. Kullanılan .net kütüphaneleri Base Class Libary(BCL) ‘dir. .NET bünyesinde bulunup da temel olarak kullanılan dillerde C# ve VB ’dir.

F# ‘ın nesnesel modelleri oluşturulurken ise OCaml ’i nesnesel programlama mimarisine aykırı olmayacak biçimde kullanılmaya çalışılmıştır. Tekniksel felsefisi ise .NET ‘ten alınmıştır. Derleme işlemleri için kullanılan mimaride Common Language Infrastructure (CLI) ‘dır. .NET ‘in genel yapı tipleri de F# ‘ın bünyesinde kullanılmaya devam edilmiştir.

F# ‘ı geliştiren kişi, England Cambridge üniversitesinden Dr. Don Syme ‘dir. Ayrıca Dr. Syme Microsoft Research Lab(MSL) ‘da da akademik programlama dilleri üzerine çalışma yapmaktadır. Fonksiyonel programlama dilinin .Net mimarisi ve Visual Studio IDE ‘si ile de uyumlu çalışması için oldukça fazla çalışması olmuştur.

F# ‘ı kimler kullanmalıdır sorusuna gelirsek, MSL çalışanlarının C# ile F# arasında yaptıkları testlerin sonuçlarına göre eğer finansal veriler, matematiksel işlemler ve matematik fonksiyonları ile yapacağımız işlemler var ise F# ‘ın performansının C# ‘a göre daha iyi olduğunu söylemektedirler. Ayrıca oldukça büyük verilerle veya Matlab de olduğu gibi matrisler ile matematiksel işlemleri yapmak istiyorsak yine C# yerine F# ile çalışmamız öneriliyor. Çünkü fonksiyonel programlama dilinin mimari yapısından ötürü F# ile yapacağımız karmaşık işlemlerin çözüm süresi oldukça kısalacaktır. Ayrıca .NET 4.0 gelişimlerinde matematik fonksiyonlarının daha ayrıntılı bir biçimde çözümlenebilmesi içinde Linear Algebra sınıflarının geliştirildiği bilinmektedir. Bu gelişimler esnasında yararlanılan yöntem yine fonksiyonel programlama teknikleridir.

Çarşamba, Mart 26, 2008

F#


Combining the efficiency, scripting, strong typing and productivity of ML with the stability, libraries, cross-language working and tools of .NET.

F# is a programming language that provides the much sought-after combination of type safety, performance and scripting, with all the advantages of running on a high-quality, well-supported modern runtime system. F# gives you a combination of

The only language to provide a combination like this is F# (pronounced FSharp) - a scripted/functional/imperative/object-oriented programming language that is a fantastic basis for many practical scientific, engineering and web-based programming tasks.

F# is a pragmatically-oriented variant of ML that shares a core language with OCaml. F# programs run on top of the .NET Framework. Unlike other scripting languages it executes at or near the speed of C# and C++, making use of the performance that comes through strong typing. Unlike many statically-typed languages it also supports many dynamic language techniques, such as property discovery and reflection where needed. F# includes extensions for working across languages and for object-oriented programming, and it works seamlessly with other .NET programming languages and tools.

For further information, read about F# in more detail, download the F# distribution, read the getting started pages (a guide to installation and running your first program), go to the F# Manual, and learn about the growing F# Community. A short FAQ is also included on this site.

Some Starting points

Original web site:http://research.microsoft.com/fsharp/fsharp.aspx

See you later...

Olasılıksız - Kitap Yorum


Olasılıksız hayatımda okuduğum en iyi kitaptı. Tek çırpıda hiç sıkılmadan, eğlenerek okudum bu kitabı, tavsiyem sizinde okumanız.

Kitabın kapağı ve içeriği ile ilgili kısa bilgi aşağıdadır.

0000000193708_3_1Olasılık, tahmin, düşünceler, nöbetler, karışıklıklar, ileriyi görebilme zannı, dejavu ve tabii ki olasılıksız şeyler. Bu kelimelerle içli dışlı olabileceğiniz, bütün bu kelimelerin yaşamdaki yerini kavrayabileceğiniz müthiş bir uyarlama.

Adam Fawer' ın ortaya çıkardığı bu uyarlama romanın müthiş bir çalışmanın ve araştırmanın sonucu ortaya çıktığının kitabın başından sonuna kadar farkındasınız. Bu uyarlamasını, derin araştırmalarıyla birleştirip romanı tekdüzelikten çıkarıp müthiş bir yere koyduğu için de Fawer' a müteşekkir oluveriyorsunuz. Sıkıcı diye nitelendirebileceğiniz teorik bilgileri bile bir çırpıda okuyuveriyorsunuz.

Teorik bilgiler dahi olaylarla sonuna kadar bağlantılı aktarılmış. Tekdüzelikten çıkmış bir roman; olasılıksız. Her an olayın kurgusunun değişmesi olasılık dahilinde. Her köşesinde farklı bir renk. Kitabın kapağında da yazdığı gibi; başkasına anlatmak için yarını beklemiyorsunuz. Her köşesine sıkışmış renklerle ortaya müthiş bir karışım eseri renk çıkıyor.

Adam Fawer, bazen olasılıksızı aktarıyor kitabında. Siyahla beyazı karıştırıp yeşil yada mavi ya da daha farklı renkler sunabiliyor; grinin dışında.Ortaya çıkan gri yeşil görünüyor belki de.

linizden bırakamayacağınız kadar güzel bir kitap olmuş; olasılıksız..Kitap gerçekten etkileyici... Kağıtlar, zarlar, zaman, tren ve hatta kuşlar; inanın hepsi çok anlamlı...

Salı, Mart 25, 2008

Java - Exceptions

Bu yazımızda istisnalar üzerinde durulacaktır. İstisna deyince aklınıza ne geliyor? Yanlış yazılmış uygulama mı? Beklenmeyen durum mu? Yoksa her ikisi de mi? İstisna demek işlerin sizin kontrolünüzden çıkması anlamına gelir. Yani karışıklık ortamı, önceden kestirilemeyen... Bir şeylerin ters gitmesi sonucu uygulamanın normal akışına devam edememesi demektir. Bu ters giden bir şeyler ne olabilir? Örneğin kullanıcının uygulamanıza istemeyen veri girmesi olabilir veya açmak istediğiniz dosyanın yerinde olmaması olabilir, örnekleri çoğaltmak mümkündür.

İstisnalara Giriş

Gerçekten tam bir uygulama yazmak ne demektir? Uygulamadan beklenen görevleri yerine getirmesi onu tam bir uygulama yapar mı? Tabii ki yapmaz. Uygulama zaten kendisinden beklenen işi yapmalı, aksi takdirde zaten uygulama olmaz. Bir uygulamanın tam olmasının iki şartı vardır; Birincisi uygulamanın kendisinden beklenen görevleri doğru bir şekilde yerine getirmesidir yani doğruluk, ikincisi ise hatalı davranışlara karşı dayanıklı olmasıdır, sağlamlık. Örneğin bizden iki sayıyı bölmek için bir uygulama istense ne yapılmalıdır, A/ B - A bölüm B çok basit değil mi?. İlk etapta karşı tarafın bizden istediği şey, girilen iki sayının doğru şekilde bölünmesidir - doğruluk, bu öncelikli şarttır, bunda herkes hemfikir. Peki ikinci şart nedir? İkinci şart ise sağlamlıktır, ikinci şart olan sağlamlık genellikle önemsenmez. Bu örneğimizde karşı tarafın bizden istediği olay, iki sayının bölünmesidir ama dikkat edin sayı dedim, kullanıcı int, double veya short ilkel tiplerinde sayı girilebilir. Peki ya kullanıcı String bir ifadeyi uygulamanıza yollarsa ne olur? veya A=5, B=0 girince uygulamanız buna nasıl bir tepki verir? (Not :5/0=sonsuz) Uygulamanız direk olarak kapanır mı? Veya uygulamanız bu anlamsız ifadeleri bölmeye mi çalışır? Eğer siz uygulamayı tasarlayan kişi olarak, bu hataları önceden tahmin etmiş ve önlemleri almışsanız sorun ortaya çıksa bile, uygulama için sorun olmaz ama gerçek dünyada her şeyi öngörebilmek imkansızdır.

Java programlama dili, oluşabilecek hatalara karşı sert bir yaptırım uygular. Dikkat edin, oluşabilecek diyorum. Java programlama dili, ortada hata oluşmasına sebebiyet verebilecek bir durum var ise yazılan Java dosyasını derlemeyerek kodu yazan kişiye gerekli sert tavrı gösterir. Java programlama dilinin bu tavrı doğru mudur? Kimileriniz diyebilir ki, "Java sadece üstüne düşen görevi yapsın, oluşabilecek hataları bana söyleyerek canımı sıkmasın". Bu yaklaşım yanlıştır, Java programlama dilinin amacı kodu yazan kişiye maksimum şekilde yardımcı olmaktır, daha doğrusu insana dayalı oluşabilecek hataları kendi üstüne alıp, hatalı uygulama üretimini minimuma indirgemeyi amaçlayarak tasarlanmıştır. Bunun ilk örneğini çöp toplama (garbage collector) mekanizmasında görmüştük. Diğer dillerde oluşturulan nesnelerin, daha sonradan işleri bitince bellekten silinmemelerinden dolayı bellek yetmezlikleri oluşmaktadır. " Kodu yazan insan, oluşturduğu nesneyi bellekten temizlemez mi? Ben bunu şahsen hiç yapmam. O zaman dalgın insanlar kod yazmasın aaa! " diye bir söz sakın demeyin, çünkü insanoğlu yeri geldiğinde çok dalgın olabilir ve bu dalgınlık uygulamayı bir bellek canavarına dönüştürebilir ayrıca bu tür hataları, uygulamanın içerisinden ayıklamak cidden çok zor bir iştir. Bu yüzden Java programlama dilinde, bir nesnenin bellekten silinmesi kodu yazan kişiye göre değil, çöp toplama algoritmalarına göre yapılır. Java’nın oluşabilecek olan hatalara karşı bu sert tutumu da gayet mantıklıdır. Bu sert tutum sayesinde ileride oluşabilecek ve bulunması çok güç olan hataların erkenden engellenmesini sağlar.

İstisna Nasıl Oluşabilir?

İstisna oluşumuna en basit örnek olarak, yanlış kullanılmış dizi uygulamasını verebiliriz. Java programlama dilinde dizilere erişim her zaman kontrollüdür. Bunun anlamı, Java programlama dilinde dizilerin içerisine bir eleman atmak istiyorsak veya var olan bir elemana ulaşmak istiyorsak, bu işlemlerin hepsi Java tarafından önce bir kontrolden geçirilir. Bunun bir avantajı, bir de dezavantajı vardır. Avantaj olarak güvenli bir dizi erişim mekanizmasına sahip oluruz, dezavantaj olarak ufakta olsa hız kaybı meydana gelir. Fakat böyle bir durumda hız mı daha önemlidir yoksa güvenlik mi? Bu sorunun cevabı Java programlama dili için güvenliktir. Aşağıdaki örneğe dikkat edelim;

package makaleKod;

public class DiziErisim {public DiziErisim()
{
}
public static void main(String[] args) {
{
int sayilar[]={1,2,3,4};
System.out.println("Basla");
for (int i = 0; i < 5; i++) {
System.out.println("--> " + sayilar[i]);
}
System.out.println("Bitti");

}
}
}

ayilar[],ilkel (primitive) int tipinde dizi değişkenidir ve bağlı bulunduğu dizi nesnesinin içerisinde 4 adet int tipinde eleman vardır. for döngüsü sayesinde dizi içerisindeki elemanları ekrana bastırmaktayız. Bu örneğimizdeki hata, for döngüsünün fazla dönmesiyle dizinin olmayan elemanına ulaşmak istememizden kaynaklanmaktadır. Böyle bir hareket, çalışma-anında (run-time) hata oluşmasına sebebiyet verip uygulamamızın aniden sonlanmasına sebebiyet verecektir. Uygulamayı çalıştırıp, sonuçları hep beraber görelim.



Bu örneğimizdeki istisna, ArrayIndexOutOfBoundsException istisnasıdır. Bu istisnanın sebebi, bir dizinin olmayan elemanına erişmeye çalıştığımızı ifade eder. Fark edildiği üzere Java programlama dilinde, oluşan istisnaları anlamak ve yerlerini belirlemek çok zor değildir. Örneğin bu uygulamada istisnanın 10. satırda ortaya çıktığı anlaşılabilmektedir.

Başka İstisnalar Neler Olabilir?

Bir uygulama içerisinde, başka ne tür istisnalar oluşabilir ? Bir kaç örnek verirsek;

Açmak istediğiniz fiziksel dosya yerinde olmayabilir.
Uygulamanıza kullanıcılar tarafında, beklenmedik bir girdi kümesi gelebilir.
Ağ bağlantısı kopmuş olabilir.
Yazmak istediğiniz dosya, başkası tarafından açılmış olduğundan yazma hakkınız olmayabilir.

Olabilir, olmayabilir, belki... Yukarıdaki istisnaların, bir uygulamanın başına gelmeyeceğini kim garanti edebilir? Kimse, peki Java program içerisinde tam bir uygulama nasıl yazılır. Başlayalım...

İstisna Yakalama Mekanizması

Bir istisna oluştuğu zaman uygulamamız aniden kapanmak zorunda mı? Oluşan bu istisnayı daha şık bir şekilde yakalayıp uygulamanın devam etmesini sağlamak mümkün mü? Cevap olarak evet;

try{// Istisnaya sebebiyet verebilecek olan kod
} catch(Exception1 e1) {
//Eger Exception1 tipinde istisna firlatilirsa buraya
} catch(Exception2 e2) {
//Eger Exception2 tipinde istisna firlatilirsa buraya
}

İstisnaya sebebiyet verebilecek olan kod, try bloğunun içerisinde tutularak güvenlik altına alınmış olur. Eğer istisna oluşursa, istisna yakalama mekanizması devreye girer ve oluşan bu istisnanın tipine göre, uygulamanın akışı catch bloklarından birinin içerisine yönlenerek devam eder.

İstisnalar nesnedir. Bir istisna oluştuğu zaman bir çok olay gerçekleşir. İlk önce yeni bir istisna nesnesi belleğin heap alında new() anahtar kelimesi ile oluşturulur. Oluşan bu istisna nesnesinin içerisine hatanın oluştuğu satır yerleştirilir. Uygulamanın normal seyri durur ve oluşan bu istisnanın yakalanması için catch bloğunun olup olmadığına bakılır. Eğer catch bloğu varsa uygulamanın akışı uygun catch bloğunun içerisinden devam eder. Eğer catch bloğu tanımlanmamış ise hatanın oluştuğu yordamı (method) çağıran yordama istisna nesnesi paslanır, eğer bu yordam içerisinde de istisnayı yakalamak için catch bloğu tanımlanmamış ise istina nesnesi bir üst yordama paslanır, bu olay böyle devam eder ve en sonunda main() yordamına ulaşan istisna nesnesi için bir catch bloğu aranır eğer bu yordamın içerisinde de catch bloğu tanımlanmamış ise, uygulananın akışı sonlanır. Bu olayları detaylı incelemeden önce temel bir giriş yapalım;

package makaleKod;

public class DiziErisim2 {

private void calis() {
int sayilar[]={1,2,3,4};
for (int i = 0; i < 5; i++) {
try {
System.out.println("-->"+sayilar[i]);
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("Hata olustu" +ex);
}
}
}
public static void main(String args[]) {
System.out.println("Basla");
DiziErisim2 de2=new DiziErisim2();
de2.calis();
System.out.println("Bitti");
}
}

Yukarıdaki uygulamamızda, dizi elemanlarına erişen kodu try bloğu içerisine alarak, oluşabilecek olan istinaları yakalama şansına sahip olduk. Sahip olduk da ne oldu diyenler için gereken açıklamayı hemen yapalım. try-catch istisna yakalama mekanizması sayesinde istisna oluşsa bile uygulamanın akışı aniden sonlanmayacaktır. DiziErisim.java ile DiziErisim2.java uygulamalarının çıktısına bakılırsa aradaki kontrolü hemen fark edilecektir. DiziErisim2.java uygulama örneğimizin çıktısı aşağıdaki gibidir.



Kontrol nerede? Yukarıdaki DiziErisim2.java uygulamasının çıktısının son satırına dikkat ederseniz, "Bitti" yazısının ekrana yazıldığını görürsünüz oysaki bu ifade DiziErisim.java uygulamasının çıktısında görememiştik. İşte kontrol buradadır. Birinci kuralı daha net bir şekilde ifade edersek; try-catch istisna yakalama mekanizması sayesinde, istisna oluşsa bile uygulamanın akışı aniden sonlanmaz.

Yukarıdaki örneğimizde, try-catch mekanizmasını for döngüsünün içerisine koyulabileceği gibi, for döngüsünü kapsayacak şekilde de tasarlanıp yerleştirilebilir.

package makaleKod;

public class DiziErisim3 {

private void calis() {
try {
int sayilar[]={1,2,3,4};
for (int i = 0; i < 5; i++) {
System.out.println("--> " + sayilar[i]);
}
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("Hata Yakalandi");
}
}

public static void main(String[] args) {
System.out.println("Basla");
DiziErisim3 de3=new DiziErisim3();
de3.calis();
System.out.println("Bitti");
}
}

Bu uygulama örneği ile DiziErisim2.java örneğimiz arasında sonuç bakımından bir fark yoktur. Değişen sadece tasarımdır, try-catch bloğunun daha fazla kodu kapsamasıdır.

İstisna İfadeleri

Bir yordam hangi tür istisna fırlatabileceğini önceden belirtebilir veya belirtmek zorunda kalabilir. Bu yordamı (method) çağıran diğer yordamlar da, fırlatılabilecek olan bu istisnayı, ya yakalarlar ya da bir üst bölüme iletirler. Bir üst bölümden kasıt edilen, bir yordamı çağıran diğer bir yordamdır. Şimdi bir yordamın önceden hangi tür istisna fırlatacağını nasıl belirtmek zorunda kaldığını inceleyelim.

package makaleKod;

import java.io.*;

public class IstisnaOrnek1 {

public void cokCalis() {
File f = new File("ornek.txt");
BufferedReader bf = new BufferedReader( new FileReader( f ) );
System.out.println(bf.readLine());
}

public void calis() {
cokCalis();
}

public static void main(String args[]) {
IstisnaOrnek1 io1 = new IstisnaOrnek1();
io1.calis();
}
}

java.io paketinin içerisindeki sınıfları henüz incelemedik ama bu örneğimizde kullanılan sınıfların ne iş yaptıklarını anlamak çok zor değil. Burada yapılan iş, aynı dizinde bulunduğu farz edilen ornek.txt dosyasının ilk satırını okumaya çalışmaktır. Yukarıdaki uygulamamızı derlemeye çalışırsak, derleyicinin bize vereceği mesaj aşağıdaki gibi olur.



Biz diskimizde bulunduğu varsayılan bir dosyaya erişip onun ilk satırını okumaya çalışmaktayız. Çok masum gibi gözüken ama tehlikeli istekler. Peki daha detaylı düşünelim ve oluşabilecek olan istisnaları tahmin etmeye çalışalım.

İlk oluşabilecek olan istisna, o dosyanın yerinde olmayabileceğidir. Bu beklenmeyen bir durum oluşturabilir, başka neler olabilir? Bundan ayrı olarak biz sanki o dosyanın orada olduğundan eminmişiz gibi birde onun ilk satırını okumaya çalışıyoruz, bu isteğimizde istisnaya sebebiyet verebilir çünkü dosya yerinde olsa bile dosyanın ilk satırı olmayabilir. Dikkat ederseniz hep olasılıklar üzerinde durmaktayım ama güçlü olasılıklar. Peki bu uygulamayı derlemenin bir yolu yok mu?

Az önce bahsedildiği gibi bir yordam içerisinde oluşmuş olan istisnayı bir üst bölüme yani o yordamı çağıran yordama fırlatabilir. Eğer bir istisna oluşursa bu anlattıklarımıza göre bir yordamın iki şansı vardır diyebiliriz. Birincisi oluşan bu istisnayı ya yakalayıp gereken işlemleri kendi içerisinde sessizce gerçekleştirebilir veya bu istisna ile ben ne yapacağımı bilmiyorum beni çağıran yordam düşünsün diyip, istisna nesnesini bir üst bölüme fırlatabilir.

Aşağıdaki örnekte, oluşan istisnayı aynı yordamın içerisinde yakalanmaktadır; bu yüzden yordamın hangi istisnayı fırlatabileceğini açıklamasına gerek yoktur. Bir yordamın hangi tür istisnayı nasıl fırlatabileceğini açıklama olayını az sonra göreceğiz ama önce aşağıdaki örneğimizi inceleyelim.

package makaleKod;

import java.io.*;

public class IstisnaOrnek2 {

public void cokCalis() {
try {
File f = new File("ornek.txt");
BufferedReader bf=new BufferedReader(new FileReader(f) );
System.out.println(bf.readLine());
} catch (IOException ex) {
System.out.println("Hata Yakalandi =" + ex);
}
}

public void calis() {
cokCalis();
System.out.println("calis() yordamı");
}

public static void main(String args[]) {
IstisnaOrnek2 io2 = new IstisnaOrnek2();
io2.calis();
System.out.println("main() yordamı");
}
}

Verilen örnekte, dosyaya erişirken veya ondan birşeyler okumak isterken oluşabilecek olan istisnalar; java.io.IOException istisna tipini kullanarak yakalanabilir. Zaten IstisnaOrnek1.java uygulamasının derlemeye çalışırken alınan hatadan hangi tür istisna tipinin kullanılması gerektiğini de çıkartabiliriz. java.io.FileNotFound Exception istina tipini, java.io.IOException tipi kullanılarak yakalanabilir bunun nasıl olduğunu biraz sonra göreceğiz.

Yukarıdaki uygulama güzel bir şekilde derlenir çünkü oluşabilecek olan tüm istisnalar için tedbir alınmıştır. Olayların akışını inceliyelim, bu uygulamayı çalıştırdığımız zaman (java IstisnaOrnek2) ilk olarak main() yordamından akışa başlanır. Daha sonra calis() yordamının ve cokCalis() yordamının çağrılması şeklinde akış devam ederken olanlar olur ve cokCalis() yordamının içerisinde istisna oluşur. Çünkü ornek.txt diye bir dosya ortalarda yoktur (yok olduğunu varsayın) ama olsun içimiz rahat çünkü try-catch hata yakalama mekanizmamız mevcuttur.

Olayın akışını açıklamaya başlayalım;

Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
Evet, cokCalis() yordamının içerisinde try-catch mekanizması olduğu için, catch bloğuna yazılmış olan kodlar çalışır. Bu uygulamamızda ekrana " Hata Yakalandi =java.io.FileNotFoundException: ornek.txt (The system cannot find the file specified) " basılır, yani dosyanın olmayışından dolayı bir istisna olduğu belirtilir. Not: java.io.IOException istisna tipi, java.io.FileNotFound Exception istisna tipini kapsadığından bir sorun yaşanmaz bunun nasıl olduğunu biraz sonra inceleyeceğiz.
Bitti mi? Tabii ki hayır, uygulamamız kaldığı yerden devam edecektir. Şimdi sıra calis() yordamının içerisindeki henüz çalıştırılmamış olan kodların çalıştırılmasına. Burada da ekrana "calis() yordamı" basılır.
Son olarak akış main() yordamına geri döner ve main() yordamının içerisinde çalıştırılmamış olan kodlar çalıştırılır ve ekrana "main() yordamı" basılır.
Ve uygulamamız normal bir şekilde sona erer.

Uygulamamızın toplu olarak ekran çıktısı aşağıdaki gibidir.



Akıllara şöyle bir soru gelebilir, "Eğer ornek.txt dosyası gerçekten olsaydı yine de try-catch mekanizmasını yerleştirmek zorundamıydık". Cevap evet, az önce bahseldiği gibi ortada istisna oluşma tehlikesi varsa bile bu tehlikenin önlemi Java programla dilinde önceden kesin olarak alınmalıdır.

İstisnaOrnek2.java uygulamamızda, oluşan istisna aynı yordamın içerisinde yakalanmıştır ve böylece uygulamanın akışı normal bir şekilde devam etmiştir. Peki oluşan bu istisnayı aynı yordamın içerisinde yakalamamak gibi bir lüksümüz olabilir mi? Yani oluşan istisna nesnesini -ki bu örneğimizde oluşan istisnamız java.io.FileNot FoundException tipindeydi, bir üst kısma fırlatılabilir mi? Bir üst kısma fırlatmaktan kasıt edilen, istisnanın meydana geldiği yordamı çağıran yordama bu istisna nesnesini fırlatmaktır. "Peki ama niye böyle bişeye ihtiyaç duyalım ki?" diyebilirsiniz. Bunun başlıca sebebi, istisnanın oluştuğu yordam içerisinde, o istisna nesnesi ile ne yapılabileceğinin bilenememesi olabilir. Bir üst kısımda elimizde daha fazla bilgi olabilir, ve bu bilgi çerçevesinde, elimizdeki istisna nesnesini daha güzel bir şekilde değerlendirip, uygulamanın akışını ona göre yönlendirebiliriz.

package makaleKod;

import java.io.*;

public class IstisnaOrnek3 {

public void cokCalis() throws IOException{

File f = new File("ornek.txt");
BufferedReader bf= new BufferedReader( new FileReader(f) );
System.out.println(bf.readLine());

}

public void calis() {
try {
cokCalis();
System.out.println("calis() yordamı");
} catch(IOException ex) {
System.out.println("Hata Yakalandi-calis() =" + ex);
}

}

public static void main(String args[]) {
IstisnaOrnek3 io3 = new IstisnaOrnek3();
io3.calis();
System.out.println("main() yordamı");
}
}

IstisnaOrnek3.java örneğimizde oluşan istisna oluştuğu yordam içerisinde yakalanmamıştır. Peki nasıl olurda derleyici buna kızmaz, cevabı hemen aşağıdadır.

public void cokCalis() throws IOException {
//..
}

Eğer bir istisna oluşursa, istisnanın oluştuğu yordamın yapacağı iki şey vardır demiştik. Birincisi oluşan istisnayı kendi içerisinde try-catch mekanizmasıyla yakalayabilir. İkincisi ise oluşacak olan istisnayı bir üst bölüme (kendisini çağıran yordama) fırlatabilir. Örneğin cokCalis() yordamı "throws IOException" diyerek, kendisini çağıran yordamlara şöyle bir mesaj gönderir, "Bakın benim içimde istisnaya yol açabilecek kod var ve eğer istisna oluşursa ben bunu fırlatırım, bu yüzden başınız çaresine bakın". Olayın akış şemasını anlatmaya çalışalım;

Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
Hayır, cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur(try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
calis() yordamının içerisinde hata yakalama mekanizması vardır (try-catch) bu yüzden catch bloğunun içerisindeki kod çalıştırılır ve ekrana " Hata Yakalandi-calis() =java.io.FileNotFoundException: ornek.txt (The system can not find the file specified) " basılır, yani dosyanın olmayışından dolayı bir istisna olduğu belirtilir. Dikkat edilirse ekrana " calis() yordamı " basılmadı bunun sebebi istisnanın oluşmasından dolayı akışın catch bloğuna dallanmasıdır. Not: java.io.IOException istisna tipi, java.io.FileNotFoundException istisna tipini kapsadığından bir sorun yaşanmaz bunun nasıl olduğunu biraz sonra inceleyeceğiz.
Son olarak akış main() yordamına geri döner ve main() yordamının içerisinde çalıştırılmamış olan kodlar çalıştırılır ve ekrana "main() yordamı" basılır.
Ve uygulamamız normal bir şekilde sona erer.

Bu örneğimizdeki ana fikir, bir istisna kesin olarak oluştuğu yordamın içerisinde yakalanmayabileceğidir. Fırlatma özelliği sayesinde istisna nesnesi (eğer istisna oluşmuş ise) bir üst bölüme yani istisna oluşan yordamı çağıran yordama fırlatılabilir.

Peki bu istisna nesnesi (java.io.IOException) calis() yordamın yakalanmasaydı ne olurdu? Cevap: O zaman main() yordamın yakalanırdı. Nasıl? Hemen gösterelim.

package makaleKod;

import java.io.*;
public class IstisnaOrnek4 {
public void cokCalis() throws IOException {
File f = new File("ornek.txt");
BufferedReader bf = new BufferedReader( new FileReader( f ) );
System.out.println(bf.readLine());
}
public void calis() throws IOException {
cokCalis();
System.out.println("calis() yordamı");
}
public static void main(String args[]) {
try {
IstisnaOrnek4 io4 = new IstisnaOrnek4();
io4.calis();
System.out.println("main() yordamı");
} catch(IOException ex) {
System.out.println("Hata Yakalandi-main() =" + ex);
}
}
}

Bu sefer biraz daha abartıp, oluşan istisna nesnesini son anda main() yordamında yakalıyoruz. Bu örneğimizde hem istisnanın meydana geldiği cokCalis() yordamı hem de calis() yordamı oluşan istisnayı fırlatmışlardır. Buraya kadar anlattıklarımızı adım adım açıklamaya çalışalım;

Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur (try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
Cevap hayırdır. calis() yordamı da oluşan istisna nesnesini bir üst bölüme yani kendisini çağıran main() yordamına fırlatmıştır.
İstina nesnemiz main() yordamının içerisine geldi. Sorulması gereken soru " main() yordamının içerisinde hata yakalama mekanizması var mıdır? "
Cevap evettir. Böylece akış main() yordamının içerisindeki catch bloğuna dallanır ve catch bloğunun içerisindeki kod çalıştırılır.
Ve uygulamamız normal bir şekilde sona erer.

Uygulamanın toplu olarak çıktısı aşağıdaki gibidir.



Oluşan bir istisna nesnesini catch bloğunda yakalamanın ne gibi avantajları olabilir? Bu sorunun cevabına değinmeden önce olaylara eğer istisna nesnesi main() yordamında yakalanmasaydı neler olacağını inceleyerek başlayalım.

package makaleKod;

import java.io.*;
public class IstisnaOrnek5 {
public void cokCalis() throws IOException {
File f = new File("ornek.txt");
BufferedReader bf = new BufferedReader( new FileReader(f));
System.out.println(bf.readLine());
}
public void calis() throws IOException {
cokCalis();
System.out.println("calis() yordamı");
}
public static void main(String args[]) throws IOException {
IstisnaOrnek5 io5 = new IstisnaOrnek5();
io5.calis();
System.out.println("main() yordamı");
}
}

Görüldüğü üzere cokCalis() yordamının içerisinde oluşan istisna hiçbir yordam içerisinde hata yakalama mekanizması kullanılarak yakalanmamıştır (try-catch). Bunun yerine tüm yordamlar bu istisna nesnesini fırlatmayı seçmiştir, buna main() yordamıda dahildir. Böyle bir durumda akışın nasıl gerçekleştiğini, adım adım anlatmaya çalışalım;

Öncelikle akış, main() yordamının içerisinden başlar. Bu uygulamamızda main() yordamının içerisinden calis() yordamı çağrılmıştır.
calis() yordamının içerisinden cokCalis() yordamı çağrılmıştır.
cokCalis() yordamının içerisinde istisna oluşmuştur çünkü uygulamamızın yer aldığı dizinin içerisinde ornek.txt dosyası aranmış ve bulunamamıştır. Şimdi kritik an geldi, cokCalis() yordamının içerisinde try-catch mekanizması var mı?
cokCalis() yordamının içerisinde oluşan istisnayı yakalama mekanizması yoktur (try-catch) ama java.io.IOException tipinde bir hata nesnesi fırlatacağını "throws IOException" diyerek belirtmiştir. İstisna oluşmuş ve istisna nesnesi (java.io.IOException) bir üst bölüme yani calis() yordamına fırlatılmıştır.
Artık istisna nesnemiz calis() yordamının içerisindedir, şimdi sorulması gereken soru " calis() yordamının içerisinde hata yakalama mekanizması var mıdır? "
Cevap hayırdır. calis() yordamı da oluşan istisna nesnesini bir üst bölüme yani kendisini çağıran main() yordamına fırlatmıştır.
İstina nesnemiz main() yordamının içerisine geldi. Sorulması gereken soru " main yordamının içerisinde hata yakalama mekanizması var mıdır? "
Cevap hayırdır. Peki ne olacak? Çok basit, uygulama doğal olarak sonla-nacaktır.

Uygulamanın toplu olarak çıktısı aşağıdaki gibidir.



"Hata yakalama mekanizması koyduğumuzda da uygulama sonlanıyordu, şimdide sonlandı bunda ne var ki" diyebilirsiniz. Haklı olabilirsiniz ama önce oluşan bir istisna nesnesi catch bloğunda yakalamanın ne gibi avantajları olabilir?

Oluşan bir istisna nesnesini catch bloğundan yakalamak, daha doğrusu hata yakalama mekanizması kullanmak uygulamayı yazan kişilere büyük kolaylıklar sağlar. En büyük avantaj oluşan hatayı catch bloğunun içerisinde kaydedilirsiniz (logging) (dosyaya ama veri tabanına... gibi gibi...) . Örneğin iyi işleyen bir uygulama yazdınız ve bu uygulama yaptığınız tüm -daha doğrusu aklınıza gelen- testlerden geçmiş herşey harika, kendinize güveniniz gelmiş, dünya gözünüze artık bambaşka bir yer gibi geliyor ama bir gün bir bakıyorsunuz ki uygulamanız çalışması durmuş!! ilk yapacağınız şey "bu uygulamayı kim kapattı!" diye etrafa sormak oysaki kimsenin günahı yok, kimse elini uygulamanıza sürmemiştir zaten böyle bir riski kim alabilir ki? Asıl gerçek, uygulamada ters giden bir şey olmuş ve uygulama kapanmıştır. İşte tam o anda tutunacağınız tek dal dosyaya veya veri tabanına kayıt ettiğiniz hata mesajlarıdır. Bu bakımdan catch bloğunun içerisine oluşan hata ile alakalı ne kadar detaylı bilgi gömerseniz, bu bilgi sizi ileride -eğer hata oluşursa- o kadar yardımcı olacaktır.

IstisnaOrnek5.java kötü bir uygulama örneğidir. Oluşabilecek olan bir istisna, hata yakalama mekanizması (try-catch) ile sizin öngördüğünüz bir yerde yakalanmalıdır. Bir istisna meydana geldiği zaman uygulama mutlaka sonlanmak zorunda değildir. Eğer bir telafisi var ise bu catch bloğunun içerisinde yapılmalı ve uygulama tekrardan ayağa kaldırılmalıdır ama çok ölümcül bir hata ise o zaman hata mesajını kaydetmekten (dosyaya veya veri tabanına.. gibi gibi...) başka yapılacak pek fazla bir şey yoktur.

İstisna Tip Hiyerarşisi

Nasıl olurda java.io.IOException istisna tipi, java.io.FileNotFoundException istisna tipini kapsayabilir? Kapsamak ne demektir? Kapsamak demek, eğer uygulamanızda java.io.FileNotFoundException tipinde bir istisna nesnesi oluşmuşsa (bir istisna oluşmuşsa) bu istisna tipini java.io.IOException tipini kullanarak da catch bloğunda yakalayabileceğiniz anlamına gelir.



Yukarıdaki şemamızdan görüleceği üzere, FileNotFoundException istisna tipi, IOException istisnasının alt kümesi olduğu için, FileNotFoundException tipinde bir istisna nesnesini catch bloğunun içerisinde IOException istisna tipiyle yakalayabiliriz.

Throwable istisna nesnesi, tüm istisna nesnelerinin atasıdır. Yukarıdaki şemamızıa bakarak istisnaları 3 gruba ayırabiliriz.

Error istisna tipi ölümcül bir hatayı işarettir ve telafisi çok zordur, neredeyse imkansızdır. Örneğin OutOfMemoryError (yetersiz bellek) istisnası oluşmuş ise uygulamanın buna müdahele edip düzeltmesi imkansızdır.
RuntimeException istisna tipleri, eğer uygulama normal seyrinde giderse ortaya çıkmaması gereken istisna tipleridir. Örneğin ArrayIndexOutOfBoundsException istisna tipi, bir dizinin olmayan elemanına eriştiğimiz zaman ortaya çıkan bir istisnadır. RuntimeException istisna tipleri, kontrolsüz kodlamadan dolayı meydana gelen istisna tipleri diyebiliriz. Biraz sonra bu istisna tipini detaylı biçimde inceleyeceğiz.
Ve diğer Exception tipleri. Bu istisna tipleri çevresel koşullardan dolayı meydana gelebilir. Örneğin erişmeye çalışan dosyanın yerinde olmaması (FileNotFoundException) veya network bağlantısının kopması sonucu ortaya çıkabilecek olan istisnalardır ve bu istisnalar için önceden bir tedbir alınması şarttır.

Tüm Diğer Exception İstisna Tiplerini Yakalamak

Bir uygulama içerisinde oluşabilecek olan tüm istisna tiplerini yakalamak için aşağıdaki ifadeyi kullanabilirsiniz.

catch (Exception ex) {
//......
}

Tüm istisnaları yakalamak (Error, RuntimeException ve diğer Exception türleri) için Throwable istisna tipini kullanmak iyi fikir değildir. Bunun yerine bu üç gruba ait daha özellikli istisna tiplerinin kullanılmasını önerilir.

RuntimeException İstisna Tipleri

DiziErisim.java uygulama örneğimiz içerisinde istisna oluşma riski olmasına rağmen nasıl oldu da Java buna kızmayarak derledi? Peki ama IstisnaOrnek1.java uygulamasını niye derlemedi? Bu soruların cevapları istisna tiplerinin iyi bilenmesi ile ortaya çıkar.

DiziErisim.java uygulama örneğinde istisna oluşma riski vardır. Eğer uygulamayı yazan kişi dizinin olmayan bir elemanına erişmeye kalkarsa ArrayIndexOutOfBounds Exception hatası alacaktır, yani RuntimeException (çalışma-anı hatası). Peki bunun sebebi nedir? Bunun sebebi kodu yazan arkadaşın dikkatsizce davranmasıdır. Bu tür hatalar derleme anında (compile-time) fark edilemez. Java bu tür hatalar için önceden bir tedbir alınmasını şart koşmaz ama yine de tedbir almakta özgürsünüzdür. Bir dosyaya erişirken oluşacak olan istisnaya karşı bir tedbir alınmasını, Java şart koşar çünkü bu tür hatalar diğer Exception istisna tipine girer. Genel olarak karşılaşılan RuntimeException istisna türlerine bir bakalım;

AritmeticException: Bir sayının sıfıra bölünmesiyle ortaya çıkabilecek olan bir istisna tipidir.
• NullPointerException: Bir sınıf tipindeki referansı, o sınıfa ait bir nesneye bağlamadan kullanmaya kalkınca alınabilecek bir istisna tipi.
String ad == null;
// NullPointerException ! hata !
System.out.println("Ad = " + ad.trim() );

Bu hatayı almamak için,

String ad = " Java Makale Projesi "; // baglama islemi
System.out.println("Ad = " + ad.trim() ); //dogru
// NullPointerException ! hata !

NegativeArraySizeException: Bir diziyi negatif bir sayı vererek oluşturmaya çalışırsak, bu istisna tipi ile karşılaşırız

// NegativeArraySizeException ! hata !
int dizi[] = new dizi[ -100 ];

• ArrayIndexOutOfBoundsException: Bir dizinin olmayan elemanına ulaşmak istendiği zaman karşılaşılan istisna tipidir

• SecurityException: Genellikle tarayıcı (browser) tarafından fırlatılan bir istisna tipidir. Bu istisnaya neden olabilecek olan sebepler aşağıdaki gibidir;
Applet içerisinden, yerel (local) bir dosyaya erişilmek istendiği zaman.
Appletin indirildiği sunucuya (server) değilde değişik bir sunucuya bağlantı kurulmaya çalışıldığı zaman.
Applet içerisinde başka bir uygulama başlatmaya çalışıldığı zaman.

SecurityException istisna tipi fırlatılır.
Önemli noktayı bir kez daha vurgulayalım, RuntimeException ve bu istisna tipine ait alt tipleri yakalamak için, Java derleme anında (compile-time) bizlere bir bir zorlama yapmaz.

Bu makalemizde genel olarak javada istisnalar kavramına giriş yapmaya çalıştık. Bir sonraki java makalemizde istisnalar konusunu incelemeye devam edeceğiz.

Umarım yararlı olmuştur.

Uygulamada bahsettiğimiz sınıfların kaynak kodlarına linkten erişebilirsiniz.

Pazar, Mart 23, 2008

ASP.NET MVC Framework - III

Daha önceki MVC makalelerimizde bu kavramı incelemiş ve genel bir sorgu işlemi ile Product tablosunda yer alan ürün isimlerini sıralamıştık.

Bu makaleler eşliğinde bir LinQ to SQL 'in temel olarak nasıl kullanılabileceğine değinirken arka planda oluşturmuş olduğu kodların ve bu kodlara bağlı olarak yapabilecek olduğumuz işlemlerin oldukça fazla olduğunu incelemiştik. LinQ to SQL kodlarını incelediğimizde MVC için çalışma mantığını da çok az da olsa değinmeye çalışmıştık. Tekrardan bu mantığın nasıl işlediğini hatırlamak gerekirse, son kullanıcıdan sunucuya yapılan istek ile web sayfasına bir çağrı gelir. Bizim sayfamız için gerekli olan servis içerik kontrolleri yardımı ile hangi sayfanın çağırılacağı anlaşılır. Bu çağırılan sayfanın içeriğine bağlı olarak gerekli yönlendirmeler sonucunda veri tabanı işlemleri olacaksa bu işlemler için LinQ to SQL sınıfına gider verileri belleğe alarak kullanıma hazır duruma getirir. Hazırlanmış veriler doğrultusunda tekrardan yönlendirme görüntülenecek olan sayfaya geçirilir ve sayfa içerisinde veri gözlemlenmesi sonucunda işlemlerimiz devam ederdi.

Özellikle ilk makalelerimizde bu işlemleri yapmanın ne kadar kolay olduğu görmüşsünüzdür. Bu kolay işlemleri yaparken yönlendirme mantıklarını ve hangi sayfa çağırılırken hangi içeriğin gösterileceğine çok dikkat edilmesi gerekmektedir.

Yönlendirme işlemlerinden bahsetmişken isterseniz bir kez daha hatırlamaya çalışalım.



Yukarıdaki yönlendirme işlemi gelen isteğe göre gerekli Controller ‘ı bulur sonrasında ise bu Controller gerekli web sayfasına göndererek işlemini yaptırır. Bu ana şablon işlemleri genellikle ilk sayfa çağırılmalarında veya bütün kayıtların listelendiği sayfalarda gerçekleştirilir. Daha kapsamlı işlemler için ise bu yönlendirme yapısını biraz özelleştirmemiz gerekecektir. Örneğin karşımıza çıkan onlarca veriden ID numarasına bağlı olarak tekini seçip bu seçtiğimiz veri üzerinde işlemler yapmak istiyoruz. Bu işlemi gerçekleştirirken bizim yönlendirme yapımızın nasıl çalışacağı konusunda biraz yorum yapalım. Diğer zamanlarda olduğu gibi yine Controller son kullanıcıdan gelen ilk isteği karşılayarak gerekli olan yere göndermek için yönlendirme mantığında bir sonrakine bakar. Bu baktığı değer normal zamanlar için action olacaktır. Fakat bizim şimdi düşündüğümüz farklı zamanlar esnasında bu işlem nasıl yapılacaktır. Bu tür işlemleri yapacağımız zaman aklımıza MVC Framework öncesinde bu işlemleri nasıl yaptığımızı aklımıza getirelim. Genellikle bir sayfanın içerisindeki değerleri detay sayfasına yönlendirerek detaylarını göstermeye çalışırdık. Detay sayfasını ise hiçbir zaman ayrı ayrı oluşturmazdık. Tek bir detay sayfası oluşturur ve bu oluşturduğumuz detay sayfasının içeriğini istek alınan ID ‘ye bağlı olarak doldururduk.

MVC mimarisinde de bu mantıktan farklı bir yönü yoktur. Yine istek yapılan ID alınarak gerekli sayfa çağırılır ve işlemlerde ona göre yapılır. Fakat biraz önce yazdığımız cümleye dikkat etmelisiniz. ID ‘den alınan değerlere göre görüntülenecek sayfa çağırılır. Bu mantıktan yola çıkarak yönlendirme işlemlerimizde biraz değişiklik yapmamız gerektiğini anlamış oluyoruz. Bu değişiklik ise ilk olarak ID ‘nin alınabilmesi için action ile ID ‘nin değiştirilmesi yeterli olacaktır.

Şimdi ise bir önceki makalede hangi ekran görüntüsünde kaldığımıza göz attıktan sonra bu makalemizde karşımıza çıkan listedeki sonuçları linkleyerek içeriklerini güncellemeyi nasıl yapacağımıza değinmeye çalışacağız.



En son Product sayfasında veri tabanında yer alan ürün isimlerini sıralamıştık. Artık bu ürün isimlerinin üzerlerine tıklayarak ayrıntılarını görmeyi ve düzenleme işlemlerini yapmaya başlayabiliriz. Fakat ilk başta yapmamız gereken bu ürün isimlerinin linklendirilmesi olacaktır.

Link verme işlemini yaparken a tagının içerisinde gidilecek yolu verir ve işlememizi tamamlardık.



Fakat bu işlemler MVC mimarisi kullanmadığımız zamanlar içindir. MVC mimarisinin temel kurallarına yeniden gerekirse, yönlendirme işlemlerinin hepsinin Controller katmanında olduğunu ve bu sebepten dolayı da View ‘da herhangi bir yönlendirme işlemi yapmamız gerektiğini hatırlarsınız. Yani yönlendirme işlemlerimizi Controller katmanını temel alarak yapmamız gerekiyor. Bu mantık ile yönlendirme işlemlerini yapmak istediğimizde ise yazmamız gereken kod View klasörünün altında yer alan Home klasörünün altındaki herhangi bir web sayfasına işaret etmelidir.



Kodun altına yazmış olduğumuz mesaja dikkat ederseniz yönlendirme sınıfında bulunan Controller ve Action değerlerini almış oluyor. Fakat bir eksik daha var. ID ‘yi nasıl alacak. Bunu almak için de dbml dosyamızın içeriğinden yararlanarak ürünlerin ID ‘sini kullanabileceğiz.



Bu ufak ID işlemi alma sonrasında ise internet tarayıcımızda linklerimizin gözüktüğüne ve bu gözüken linklerin ID ‘lerinin de durum çubuğunda beliren linkte olduğunu görebiliriz.



Fakat hala biraz önce bahsettiğimiz mantığa ulaşabilmiş değiliz. Şu ana kadar yaptıklarımızın sonucunda tek tek sayfa açtırabiliriz. Bu sayfa açtırmanın yerine link ile aktarımın başlaması için 8 overload ‘ı olan ActionLink ‘i kullanmamız mantıklı olacaktır.

ActionLink ‘te string ifade tanımlamak, nesne olarak verileri algılatmak ve Expression metotları tanımlamak gibi bir çok aşırı yüklemesi vardır.

ActionLink kullanımını örnek üzerinden vermeden önce değinmek istediğimiz birkaç püf nokta var. ActionLink MVC Framework ‘ün ASP.NET 3.5 Extensions ‘u ile gelen sürümünde yalnızca 3 aşırı yüklemesi bulunmaktadır. Bu aşırı yüklemelerin iyileştirilmiş ActionLink ‘in aşırı yüklemeleri arasındaki en büyük fark eski sürümde string, Object tiplerini alırken MVC Framework Preview 2 ‘de string, string, Object tipinde değerler alabilmektedir. Bu değişikliğin uygulamalarımızı geliştirirken görülebilecek sorunları vardır. Bu sorunlar ise web servis kontrol sınıfına gidecek olan verilerde ortaya çıkacaktır.

Global.asax ‘imizin içeriğinde alınan değerler {controller}/{action}/{id} biçimindedir. Bu değerlere ulaşabilmek için ActionLink ‘ten erişim sağlanabilir. Eski sürümünde bu işlem,



biçiminde gerçekleştirilebilirken, MVC Framework Preview 2 ile aşağıdaki biçimde kullanmamız gerekmektedir.



ActionLink kullanarak yukarıdaki kod parçasını uygulamamıza yazdığımızda ActionLink kullanmadan önceki işlem sonucuyla aynı sonucu verecektir.



Yukarıdaki ekran görüntüsünden de aynı sonucu verdiğini görebiliriz. Bu işlemimizde Edit ‘i bizim belirlediğimiz ActionLink ‘in içeriğinden alacaktır. Edit yerine hede yazsak ta çalışması ile ilgili herhangi bir sorun çıkmayacaktır. Sadece linke tıkladığımızda hede.aspx sayfası uygulamamızda bulunmadığı için o sayfanın olmadığı hatasını verecektir.

Şimdi routed sınıfını çağırarak yönlendirme işlemlerimizi kodu azcık değiştirelim. Orijinal hali {Controller}/{Action}/{id} ‘dır. Biz bu yönlendirmeyi {Controller}/{id}/{Action} olarak değiştiriyoruz. Bu değişikliğin sonucunda biz uygulamaya ürünID ‘sini verene kadar bizim liste sayfamız açılmayacaktır. Bu sayede biz istemediğimiz sürece veri tabanımızda bulunan binlerce kayıtta sayfada görüntülenmemiş olacaktır. Bunun en büyük katkısı sayfalarımızın oldukça hızlı açılıyor olmasıdır.



Yukarıda da gördüğünüz üzere ürünlerin ID ‘si bizim server kontrol sınıfında belirttiğimiz gibi ortada gözükmüştür.

Şimdi tek sonuçlu ID alabilmemiz için Controller katmanımızda yer alan Home Controller sınıfının içerisine aşağıdaki kodu yazıyoruz.



Bu kod parçacığını yazdıktan sonra da tek sonuç döndürecek olan dc.product.Single kodumuzun olduğu bloğa BreakPoint koyarak uygulamamızı derliyoruz.

Web sayfamız çalıştıktan sonra karşımıza gelen ürün listesinden herhangi birini tıkladığımızda debug işlemimiz başlamış olacaktır. Burada bakacak olduğumuz değer ID ‘nin doğru olarak alınıp alınmadığı ile ilgili olacaktır.



İstek yaptığımız ID ‘yi doğru bir biçimde kodumuz algılamış. Peki, Action olarak belirttiğimiz bölümü de uygulamamız anlamış mı? Bunu öğrenebilmek içinde uygulamamızın editörümüzün CallStack tagını inceleyebiliriz. Kontrol edeceğimiz DLL MVC, ilgili sınıfta InvokeAction ‘dur. Bu ikisini bulduğumuzda içeriğinde yer alan ActionName ‘i Edit olarak aldıysa işlemimizin ilk adımını başarı ile gerçekleştirmiş oluyoruz.



Veri tabanında yer alan tabloların nerede tutulduğu konusunda kafanıza bir soru takılırsa ise bunun cevabı da Products olacaktır. Ayrıntılarını merak ederseniz faremiz ile ikonu üzerine götürdüğümüzde ayrıntıları karşımıza çıkacaktır.



Debug ‘ı bir alt koda geçirdiğimizde hede ‘nin içeriği dolacak ve bizim istediğimiz değerleri gösterecektir. Bunu görebilmek için yine fareyi hede ‘nin üzerine getiririz.



Seçtiğimiz linkin adı, ID ‘si ve ürün numarası değerleri gözükmektedir.

Daha başka ayrıntıları da sizler isterseniz incelerseniz. debug işlemini tamamlayıp uygulamamızı derlediğimizde bir hata mesajı alıyoruz. Bu hata mesajı Edit.aspx sayfasının olmadığını bize belirtiyor. Bizde hemen yeni bir sayfa ekliyoruz. Bu işlem için Home klasörünün üzerinde Add-->NewItem yolunu izledikten sonra karşımıza çıkan ekranda MVC View Content Page ‘i seçiyoruz. Bu seçeneği seçip tamama bastığımızda bizden içeriği belirleyecek olan Master page ‘i belirlememizi isteyecektir. Bunun içinde View klasörünün altında bulunan Shared klasörünün içerisindeki Master page ‘i sayfaya göstererek tamam dediğimizde içeriği hazır bir sayfamız olmuş olur.

Edit.aspx sayfamız oluşturulduktan sonra veri tabanı işlemini gerçekleştirebilmemiz için edit.aspx.cs ‘i açarak sınıfımıza Product ‘ı TViewData ‘nın içerisinde tanımlıyoruz. Bu işlemi yaparken aynı zamanda Uygulamamızın Model ‘ını isim alanı olarak da belirtmeyi unutmamamız gerekmektedir.



Yine eski sürümünden bir fark ile devam edelim. Bir önceki MVC sürümünde ASPX sayfasının görünen kod bölümünde Extension metotlarını kullanamıyorduk. MVC Framework Preview 2 ile artık extensionlar herhangi bir eklenti gerektirmeden sorunsuz bir biçimde kullanılabilmektedirler.



Formdan gelen işlemleri kullanabilmemiz için Controller ‘i ve ActionName ‘i tutabilmemiz gerekmektedir. Bunun içinde kodumuzun ilk bölümünü oluşturabiliriz aşağıdaki gibi oluşturabiliriz.



Bu kodumuzu yazdıktan sonra uygulamamızı derleyerek yaptığımız işlemlerin doğru olup olmadığını kontrol edebiliriz. Bu kontrolü yapabilmek içinde ürünleri listelediğimiz sayfada herhangi bir linke tıklayarak edit.aspx sayfasına gitmesini sağlarız. Daha sonra karşımıza çıkan sayfanın kodlarını kaynağını görüntüle diyerek baktığımızda yaptığımız işlemin başarı ile gerçekleşmiş olduğunu görürüz.



Form action tagının ayrıntısına dikkat ederseniz bizim belirttiğimizin dışında birde ID ‘si belirmiştir. Bu da yönlendirme olarak belirlediğimiz {Controller}/{ID}/{Action} yapısına uygun olarak linki belirler ve gerekli olan sayfayı çağırır.

Şimdi güncelleştirme işlemlerinin gerçekleştirilebilmesi için gerekli olan form kontrollerini sayfamıza kod tarafından ekleyelim. Bu eklediğimiz kontrollerin içerisi istek yapılan linkin bilgileri ile otomatik olarak doldurulmasını istiyoruz. Bu işlemi gerçekleştirebilmek için kodumuzu aşağıdaki biçimde yazarız.



Sayfamızdaki değişiklikten sonra derlediğimizde Textboxlarımızın içeriği veri tabanındaki değeler yardımı ile dolar.



Veri tabanından aldığımız verileri formumuzda gösterdiğimize göre güncelleştirme işlemlerini yapmaya başlayabiliriz.

Home Controller sınıfını açarak aşağıdaki kodları yazıyoruz.



Uygulamamızı derlemeden önce Edit özelliğinde yapmış olduğumuz gibi update ‘te de Product.edi=… koduna BreakPoint koyuyoruz. Uygulamamızı derlemeden önce web sayfasının görünüm kısmındaki kodlarını aşağıdaki yapıyoruz.



Bu değişiklik sayesinde Update kontrolünden yararlanırken yararlanma kriterimizde ürünlerin ID ’si olacaktır. Bu ufak değişikliği yaptığımıza göre uygulamamızı debug edebiliriz.

Web sayfası açıldığı zaman herhangi ürünü seçerek içeriğini güncelledikten sonra Submit yazan butona tıklayarak debug işlemini başlatıyoruz.

CallStack ‘te MVC.Controller.InvokeAction bölümüne bakarsak ActionName ‘i doğru alıp almadığını görebiliriz.



Debug işlemini devam edipte ürünün isminin olduğu kod parçasının üzerine faremizi getirdiğimizde uygulamamızdan SQL işlemlerinin yapılması için değerlerin tutulmuş olduğunu göreceğiz.



Debug işlemine devam ettiğimizde ürün numarasına ait kodun “CA-5965” ‘ten “CANER-5965” ‘e değiştirileceğini görüyoruz.



Debug işlemimizi bitirdiğimiz karşımıza boş bir ekran çıkmaktadır. Evet, güncelleme işlemimiz gayet güzel bir biçimde gerçekleşti. Eksikliği ise işlem bittikten sonra yönlendirileceği bir sayfanın olmamasıdır. Bu eksikliği de Controller sınıfının içerisinde Update özelliklerine RedirectToAction(“List”); kodunu yazarak yeniden yönlendirmesini Controller da ki List özelliğine yapmasını isteriz. List özelliği de bize bütün ürünler listesini çıkartacaktır.

Tekrardan uygulamamızı çalıştırıp işlemlerimizi yaptığımızda uygulama sorunsuz bir biçimde çalışacaktır. Yeniden aynı seçeneği seçerek içeriği görüntülediğimizde değişikliğimizin gerçekleştiğini görmüş olacaksınız.



Güncelleştirme sonrası ürün özellikleri,



Güncelleme işlemlerini burada bitirmiş oluyoruz. Çok karmaşık gibi gözükse de kodlar bakımından bakıldığında toplam 15 satıra yakın kod hazırlanmıştır. Ayrıca uygulamamızın güvenliğinin de artmış olduğu işlerimizin göstergesidir.

Burada bir yazımızın daha sonuna gelmiş bulunuyoruz. Bu yazımız süresince kullanıcıdan alınan değeri nasıl uygulamamızda alabileceğimizi ve bu aldığımız değerleri ID ‘ler yardımı ile nasıl kullanabileceğimizi ayrıntılı bir biçimde incelemeye çalıştık. Bir sonraki MVC Framework makalemizde daha ayrıntılı bir örnek üzerinde daha karmaşık kodlar yardımı ile yapıyı incelemeye devam edeceğiz.

Umarım yararlı olmuştur. Bir sonraki yazımızda görüşünceye dek esenlikle kalın.

Uygulamanın kaynak kodlarına linkten erişebilirsiniz. Veri tabanı dosyası kaynak kodlarda değildir. SQL server örnek veritabanından erişebilmeniz mümkündür. Sizin örneği çalıştırabilmeniz için WebConfig dosyasında gerekli düzenlemeleri yapmanız gerekmektedir.

Perşembe, Mart 20, 2008

İnternete Erişim Özgürlüğü

Merhabalar bu sefer sizlerle teknik bir konuda değil genel bir konuda fikrimi paylaşmak istedim.

Bir kaç haftadır youtube sitesinin kapatılması konuşulup durdu. Benim aklıma takılan soru şu oluyor. Eğer internet özgür bir ortamsa ve bu ortamda da çöplüğe dönüşecek bile olsa her türlü bilgi yayınlanabiliyorsa neden kişilerin görüşlerini belirttiği siteler neden kapatılsın ki.

O kişinin düşüncesi ile ilgili sıkıntı çok artıyorsa sitenin yetkilileri aracılığıyla o yorumun, video 'nun veya da başka bir şeyin kaldırılması istenebilir. Kaldırılmıyorsa da yapılabilecek bir şey yoktur. Kişilerin görüşüdür diyip bırakılması gerekmektedir.

En ufak şeyde bir siteye erişim hakkının kısıtlanması bence oldukça yanlıştır. Bunun asıl sorunu kişilerin iyi eğitilmemiş olmasından şüphelenmemizdir. Eğerki bizlerin doğru ve düzgün bir biçimde eğitildiğimize inanılsa bunların bir çoğu yapılmayacaktır. Tabii bu olayın köküü inceledikçe gideceği yerler belli. O yüzden fazla kurcalamaya gerek yok.

Kısacası benim isteğim her ne içerikli olursa olsun. Her görüşün internette yer almaya ve bulunmaya hakkı vardır. İyi de olsaa kötüde olsa bunu kabullenmek zorundayız.

Ben artık internet sayfalarına girdiğimde aşağıdaki uyarıları almak istemiyorum. Ya siz?

yasak

Bu sadece bize yapılmış bir yasak değildir. Bütün Türkiye 'nin dünyaya olan imajını zedelemektedir.

Bu arada değinmek istediğim konu ben hayatım boyunca YouTube 'dan sadece 2 veya 3 video izledim. Ona rağmen bu yasak bana çok dokundu.

Umarım en kısa zamanda bu ayıp düzeltilir...

Windows Vista SP1

Merhabalar

Uzun zamandır beklenen Vista SP1 sonunda çıktı. Vista SP1 ile sistemimizin performansı iyileştiriliyor ve güvenlik açıklarıda düzeltiliyor. Özellikle de bir dvd 'yi 60 dakika yerine 2 dakika da kopyalayabilmek çok güzel bir duygu oldu. :)

Fakat hardiskiniz de 4GB 'dan az boş yer varsa maalesef kuramıyorsunuz. Bu ufak notuda belirtmek isterim...

Sizlerinde bu güncelleştirmeyi yüklemenizi öneriyorum.

Windows Vista Update ile gelen görünümü,

Vista sp1

Direk indirerek arşivlemek isteyenler için linki,

http://www.microsoft.com/downloads/details.aspx?FamilyID=b0c7136d-5ebb-413b-89c9-cb3d06d12674&DisplayLang=en

Herkese iyi çalışmalar...

Çarşamba, Mart 19, 2008

ASP.NET - MVC Framework - II

Bir önceki makalemizde MVC Framework ‘ün ne işe yaradığını, nasıl bir mimari düşünce içersinde çalıştığını ve bu mimarinin bize katkılarının neler olduğuna değinmeye çalıştık. Sonrasında ise ilk MVC uygulamamızı açarak bize hazır olarak oluşturulan klasörlerin sınıfların ve web servis kontrollerine göz atmaya çalıştık. Daha sonrasında ise View ve Controller içeriklerini kontrol ederek işlemlerimizi tamamlamış olduk.

View ve Controller kavramlarını inceledik fakat bir diğer katman olan Modele yalnızca isim olarak değindik ve ne işe yaradığından bahsetmiştik. Bu makalemizde ise MVC Framework ‘te veri tabanı işlemlerimizi yapmamıza yarayacak olan Model katmanını incelemeye çalışacağız.

Model katmanını incelerken LinQ to SQL ile sorgularımızı daha nesnesel bir şekilde kullanırken veri tabanı olarak da SQL SERVER 2005 ile birlikte gelen örnek veri tabanlarından Adventure Work 'u kullanacağız.



Yazımızın ayrıntılarına girmeden önce isterseniz tekrardan Modelin ne olduğunu hatırlayalım.

Model: Model genellikle veri tabanı işlemlerimizi yani işlerimizi( business ) yaptığımız yapıdır. Veri tabanımız üzerinde yapılabilecek sorgularımızı burada belirler ve Controller ’ı atamamızı sağlarız. Bu sayede veri tabanımıza dışarıdan daha kolay erişebilir ve çeşitli metotlarla daha kolay idare/müdahale edilebilir hale getirir.

Şimdi model katmanını incelemeye başlayabiliriz. Model veri tabanı işlemlerinin yapıldığı bir katman olduğundan ötürü bizde bunu örnek üzerinden anlatmaya çalışacağız.

Uygulamamıza başlarken File-->New-->Project adımlarını izleyerek ASP.NET MVC Web Application seçeneğini seçiyoruz. Projemizin ismini de AdventureWorkMerhaba olarak belirledikten sonra projeyi tamam butonuna basarak uygulamamızı oluşturuyoruz.



Veri tabanımızı uygulamamıza ekleyebilmek için Server Explorer bölümünden Data Connections ‘ın üzerinde sağa tıklayarak Add Connection seçeneğini tıklarız.



Karşımıza Server adını ve veri tabanı ismini girmemizi isteyen bir ekran gelecektir. Bu bölümde de server ismini (eğer SQLExpress kullanıyorsanız server ismi = sqlexpress ‘tir) girdikten sonra database isminin olduğu bölümün içeriği otomatik olarak bizim üzerinde çalışmakta olduğumuz veri tabanları ile doldurulur. Bizde oradan AdventureWork ‘ü seçerek tamam dediğimizde artık uygulamamızın bir veri tabanı oluyor.



Uygulamamızda kullanacak olduğumuz veri tabanına ait sorgularımızı model katmanının içerisinde oluşturacağımızdan ve bu sorguları da LinQ to SQL yardımı ile yapacağımızdan bahsetmiştik. Bu sebepten ötürü Model klasörümüzün içerisine gerekli olan sınıfı eklememiz için model klasörünün üzerine sağa tıklayarak Add-->NewItem basamaklarını uygulaya biliriz.



Yeni öğe ekleme seçeneğinin içeriği açıldığı zaman karşımıza her zamankinden farklı öğeler karşılamaktadır. Karşılaşılan öğeler MVC ile ilgili olanlardır. Bunların listede yer almasının başlıca sebebi MVC Framework ‘ü kurmamızdır. Eğer bu Framework ‘ü kurmadan MVC uygulaması yapmaya çalışsaydık daha önceki zamanlarda olduğu gibi bu öğelerin hazırlanması içinde uzunca bir zaman ayırmamız gerekecekti.



Bu öğeleri bir kenara bırakırsak bizim işimize yarayacak olan sınıfı eklemek için karşımızda listeden LinQ to SQL Classes ‘ı bularak ismini AdventureWork olarak belirledikten sonra tamamı seçerek uygulamamıza ekliyoruz.



Eklediğimiz zaman dikkatimizi çeken birkaç nokta oluyor. Bunlardan birinci referanslar bölümünde yeni eklenen referansların olması. Bu referanslar LinQ to SQL ile ilgili sınıfları ve özellikleri kullanmamız için gereklidir.



İkincisi ve en önemlisi olanda *.dbml uzantılı bir dosya oluşturuyor. DBML database Markup Language anlamına gelen ve yardımcı veri olarak kullanılmakta olan bir sınıftır.

AdventureWork.dbml ‘imizi oluşturduğumuzda bizden uygulamamızdaki veri tabanına ilişkin tabloları eklememizi beklemeye başlayacaktır. Şimdi de bu işlemleri nasıl yapacağımıza değinmeye çalışalım.

Daha önceden eklemiş olduğumuz veri tabanının tablolarından ihtiyacımız olanları Object Relationel Designer (ORD) yazan yere sürükleyip bırakıyoruz. Biz bu uygulama için tablolardan Product, ProductOrderDetail ve ProductCategory ‘i ORD ‘ye sürükleyerek tabloların ve bu tablolara ait özelliklerin ekran gözükmesini sağlamış oluruz. Ayrıca bu tablolar arasında herhangi bir ilişki var ise onlarda otomatik olarak ekranda oluşturulacaktır.


İlişkileri oluşmuş olan tablolarımızı kaydedip kapattıktan sonra dmbl dosyamızın arka planında oluşan kodlarına göz atalım. Bakalım veri tabanı tablolarımız ve bu tablolarımıza ilişkin özellikler nasıl oluşmuş.

Oluşmuş olan kodları aşağıdaki tablonun içersinde bulabilirsiniz. Fakat verecek olduğumuz kod bloğu oluşturulmuş olan kodun tümü değildir. Bunun sebebi ise yaklaşık 1250 satır kodun oluşturulmasıdır.

Kodları vermeden önce daha önceden asp.net, Java veya başka bir dille oluşturmuş olduğumuz model sınıflarında tek tek tablolarda yer alan özellikleri tanıtmak zorunda kalır ve bu özelliklere ilişkin verilen/alınan değerlerini de ayrıca elimiz yardımı ile girmek zorunda kalırdık. Bu işlem esnasında birçok sorunla da karşılaşmamız mümkündü. Biraz önce uygulamış olduğumuz yöntem sayesinde bize zaman kaybettiren birçok kodu yazmaktan kurtulabiliriz. Fakat aklınıza güvenli mi veya doğru mu oluşturuldu biçiminde sorular takılabilir. Bunun cevabı eper ekstra işlem yapmayacaksak doğru ve güvenilirdir. Fakat tablolar arası join gibi işlemler yapmak istersek tabii ki de otomatik olarak oluşturulan kodu düzenlememiz gerekecektir.

Join işlemlerini neden örnek verdiğimize gelirse. SQL de join işlemleri birçok tablodan alınan değerler sonucunda bize sonuçlar döndürebilmekteydi. Bu tür işlemleri sql kodları ile yapmak kolaydı. Çünkü herhangi bir sınıftan veya başka bir yerden özellik çağırmadan sql kodları ile işlemlerimizi yapabiliyorduk. Fakat Model katmanında tabloları ayrı ayrı parçalı sınıflar biçiminde tuttuğumuz için ve benzer isimli sütunlarda oluşabileceği için sorgulama işlemlerimizde sorunlar çıkabilmekteydi. Bu sorunların kaldırılması içinde model katmanda oluşturmuş olduğumuz sınıflara o kullanacak olduğumuz sütunlara ilişkin özellikleri tanımlamalı ve işlemlerimize öyle devam etmeliydik. İşte bizimde şu anda oluşturmuş olduğumuz dbml ‘in arka planındaki kodlar en basit biçimiyle oluşturulmaktadır. Bizler onu özelleştirmek istersek buna imkan tanınmıştır.

C#
[System.Data.Linq.Mapping.DatabaseAttribute(Name="AdventureWorks")]
public partial class AdventureWorkDataContext : System.Data.Linq.DataContext
{

private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();

#region Extensibility Method Definitions
//SQL ile yapılabilecek işlemler otomatik olarak tanımlandı
partial void OnCreated();
partial void InsertProduct(Product instance);
partial void UpdateProduct(Product instance);
partial void DeleteProduct(Product instance);
partial void InsertPurchaseOrderDetail(PurchaseOrderDetail instance);
partial void UpdatePurchaseOrderDetail(PurchaseOrderDetail instance);
partial void DeletePurchaseOrderDetail(PurchaseOrderDetail instance);
partial void InsertProductCategory(ProductCategory instance);
partial void UpdateProductCategory(ProductCategory instance);
partial void DeleteProductCategory(ProductCategory instance);
#endregion

-----------------------
//Product tablosuna ait parçalı sınıfa bakarsak
-----------------------

//Product tablosuna ilişkin özellikler ve değerleri
[Table(Name="Production.Product")]
public partial class Product : INotifyPropertyChanging, INotifyPropertyChanged
{

private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

private int _ProductID;
private string _Name;
private string _ProductNumber;
private bool _MakeFlag;
private bool _FinishedGoodsFlag;
private string _Color;
private short _SafetyStockLevel;
private short _ReorderPoint;
private decimal _StandardCost;
private decimal _ListPrice;
private string _Size;
private string _SizeUnitMeasureCode;
private string _WeightUnitMeasureCode;
private System.Nullable<decimal> _Weight;
private int _DaysToManufacture;
private string _ProductLine;
private string _Class;
private string _Style;
private System.Nullable<int> _ProductSubcategoryID;
private System.Nullable<int> _ProductModelID;
private System.DateTime _SellStartDate;
private System.Nullable<System.DateTime> _SellEndDate;
private System.Nullable<System.DateTime> _DiscontinuedDate;
private System.Guid _rowguid;
private System.DateTime _ModifiedDate;
private EntitySet<PurchaseOrderDetail> _PurchaseOrderDetails;
#region Extensibility Method Definitions

//Listenin bir kısmıdır. Aslında birçok metot bulunmaktadır.
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnProductIDChanging(int value);
partial void OnProductIDChanged();
partial void OnStandardCostChanged();
partial void OnListPriceChanging(decimal value);
partial void OnListPriceChanged();
partial void OnSizeChanging(string value);
#endregion

public Product()
{
this._PurchaseOrderDetails = new EntitySet<PurchaseOrderDetail>(new Action<PurchaseOrderDetail>(this.attach_PurchaseOrderDetails) , new Action<PurchaseOrderDetail>(this.detach_PurchaseOrderDetails));
OnCreated();
}

[Column(Storage="_ProductID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int ProductID
{
get
{
return this._ProductID;
}
set
{
if ((this._ProductID != value))
{
this.OnProductIDChanging(value);
this.SendPropertyChanging();
this._ProductID = value;
this.SendPropertyChanged("ProductID");
this.OnProductIDChanged();
}
}
}

[Column(Storage="_Name", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public string Name
{
get
{
return this._Name;
}
set
{
if ((this._Name != value))
{
this.OnNameChanging(value);
this.SendPropertyChanging();
this._Name = value;
this.SendPropertyChanged("Name");
this.OnNameChanged();
}
}
}

//Özelliklere ilişkin metotlar devam etmektedir...

dbml ‘in kod bloğu yukarda ki gibidir. Bu kod bloğunda yalnızca Product tablosu değil diğer eklemiş olduğumuz tablolarda bulunmaktadır.

Şimdi yapmamız gereken model içerisine eklemiş olduğumuz tablolara ilişkin verileri Controller üzerinden çağırarak kullanmaktır. Bu işlemi yapabilmemiz için bir parçalı sınıf oluşturmalı ve oluşturmuş olduğumuz bu sınıfı ControllerAction yardımı ile çağırılabilir bir biçime dönüştürmeliyizdir. Ayrıca oluşturmuş olduğumuz parçalı sınıfın içersinde de yapacağımız işlemleri list içerisinde belirlememiz gerekmektedir.

Sınıfımızı oluşturmaya başladığımızda uygulamamızda oluşturulmuş olan isim alanlarına ulaşmak istediğimizde uygulamaismi. dememiz yeterli olacaktır.



Karşımıza çıkan isim alanları listesinden Models ‘ı seçtikten sonra karşımıza dört farklı seçebileceğimiz sınıf çıkacaktır. Bunlardan üçü bizim eklediğimiz tabloları temsil etmektedir. Dördüncüsü ile veri içeriğini temsil etmektedir. Bu veri içeriği dbml dosyamızda oluşturulmuş olan sınıfın içerisinden bir tiptir. İçeriğe erişmek için kullanmakta yarar vardır.



Veri içeriğini tanımladıktan sonra ayrıntılarını görmek istediğimizde, tabloları LinQ içerisinde belirlenmiş olduğunu görürüz.



Daha sonra yapacağımız işlem ise çağıracak olduğumuz tablonun görülebilmesi için RenderView üyesinin içerisinde tanımlayarak Controller ‘a istek geldiğinde anlayabilmesine olanak tanımaktadır. Bu isteği algılayabilmesi de alınan değer ve değere ilişkin tablo biçimin kod bloğunda yazılması gerekmektedir.



Hazırlıklarımızı tamamladığımıza göre normal olarak uygulamamızı çalıştırdığımızda sorunsuz bir biçimde derlenmesi ve işlemesi gerekmektedir.

Uygulamamız sorunsuz bir biçimde derlendi ve web sayfamız karşımıza geldi. Şimdi ise bizden istek yapmamızı beklemektedir. Normal zamanlarda form üzeriden sayfaya istek yaptığımızda View ‘ın içerisinde olan sayfaları çağırmaya çalışacaktır.

Bizde oluşturmuş olduğumuz list öğesini çağırmak için tarayıcımızın adres çubuğunu http://localhost:49170/Home/List yazıyoruz. Bu yazdığımız adrese göre tarayıcımız isteğini yapacak ve Controller da bu istek doğrultusunda gerekli olan sayfayı çağıracaktır.

Fakat her şey düşündüğümüz gibi olmuyor ve aşağıdaki hatayı alıyoruz.



Karşılaştığımız hataya dikkat ettiyseniz Products.aspx sayfası bulunamadı diyor. Fakat bu Products.aspx ‘i neden arıyor? Biz internet tarayıcımızın adres çubuğuna home/List ‘i çağırmasını istemiştik. Bunun sebebi Controller içerisinde hazırlamış olduğumuz list member ‘inin içerisinde eğer kullanıcıdan böyle bir istek gelirse adı Product olan sayfaya yönlendirmesini istemiştik. O da görevini yaparak View/Home klasörünün altında Products.aspx ‘i aramaktadır. Fakat biz öyle bir sayfa eklemediğimiz için bulamamaktadır.

O zaman bizde Products.aspx sayfasını ekleyelim ve sonucun nasıl olacağını görmeye çalışalım. Bu işlemi yapabilmemiz için View/Home klasörünün üzerinde Add/NewItem diyerek karşımıza ekleyebileceklerimizin listesini çıkartıyoruz. Bu listeden standart aspx sayfasını seçmek yerine MVC ‘den türetilecek olan MVCViewPage ‘i seçmek bizim işimizi kolaylaştıracaktır.



Sayfamızı ekledikten sonra içeriğine rastgele bir şeyler yazarak derlediğimiz zaman adres çubuğunda Home/List şeklinde bir çağırma olduğu dikkatimizden kaçmamaktadır.

Şimdi ise web sayfamızın içerisinden modelde tanımlanmış olanların hangilerine ve nasıl erişeceğimize göz atalım.

Temel asp bilgimizden <% %> bloklarının arasına kod yazılabildiğini biliyoruz. Şimdi web sayfamızda bu blokları kullanarak verileri göstertmeyi deneyelim. Bunun için yazmamız kod ViewData ‘dır. Bu kodu kullanmamız sonrasında intellisense ile karşımıza gelen sınıfların arasında veri içeriğinin de olduğunu görürüz.



Şimdi ViewData ‘dan sonra alacağımız özellikleri, sınıfları v.b. diğer bir çok şeyi Product ‘ın içerisinden almak istiyoruz. Bunu yapmak için, web sayfamızın kod tarafında hazır olarak oluşturulmuş sınıfa generics (genel) tanımlayarak Product ‘taki bütün verileri almasını sağlayabiliriz. Bunu yapabilmek için aşağıdaki gibi bir kod oluşturmamız gerekmektedir.

Alınabilecek değerler,



Bu görünebilir veri değerine Product yazıpta uygulamamızı derledikten sonra web sayfamızın içeriğinden olan ViewData ‘nın intellisence ile bize getirecekleri aşağıdaki gibi olacaktır.



ViewData ‘nın içerisinde karşımıza çıkan bu properties ‘lerin içeriklerini görmek istersek yapmamız gereken işlem kod tarafında tanımlamış olduğumuz Product ‘ı IEnumerable ‘ın içeriğinde tanımlamak olacaktır.



Bu değişikliğin sonucunda ViewData ile intellisense kullandığımızda karşımıza extensionlar aşağıdaki gibidir.



Yapacağımız sıradaki işlem ise Product tablosunun altında yer alan ProductName ‘leri ekrana basmak olacaktır. Bunu yapabilmek için foreach kullanmamız yeterli olacaktır.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Products.aspx.cs" Inherits="AdventureWorkMerhaba.Views.Home.Products" %>
<%@ Import Namespace="AdventureWorkMerhaba.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
hede... bu bir deneme sayfasidir
<ul>
<% foreach (Product p in ViewData)
{

%>
<li><%=p.Name%></li>

<% } %>
</ul>
</div>
</body>
</html>

Sayfamızı derlediğimiz zaman aldığımız sonuç oldukça iyidir. Bütün liste karşımızdadır.



Fakat bütün liste karşımızda olmasına rağmen masterpage ‘in tasarımını almamıştır. Ona erişebilmek için ise index.aspx ‘in içerisinde yer alan MasterPageContainer ‘larını Product.aspx ‘e ekleyerek tasarımı kazanmasını sağlayabiliriz.

Master page ‘imizi ekledikten sonra ise karşılaştığımız listenin daha şirin ve düzenli gözükebilmesi için css ‘imizin içerisinde yeni bir tasarım oluşturalım. Oluşturacak olduğumuz tasarım aşağıdaki gibi olacaktır.



Bu hazırladığımız tasarım sonucunda ise derleme esnasında web sayfamız aşağıdaki gibi bir görünüme kavuşacaktır.



Bu makalemizde MVC Framework ‘ü ve LinQ to SQL ’i kullanarak verilere erişimi ve sayfada göstermeyi anlatmaya çalıştık. Bir sonraki makalemizde ise ID ‘ler aldığımız değerleri kullanarak güncelleme yapmayı ve silmeyi incelemeye çalışacağız.

Umarım yararlı olmuştur.

Uygulamanın kaynak kodlarına linkten erişebilirsiniz. Veri tabanı dosyası kaynak kodlarda değildir. SQL server örnek veritabanından erişebilmeniz mümkündür. Sizin örneği çalıştırabilmeniz için WebConfig dosyasında gerekli düzenlemeleri yapmanız gerekmektedir.