C# ve T-SQL Geliştiriciler için Java ve Oracle

advertisement
YAZILIM VE VERİTABANI
C# ve T-SQL
Geliştiriciler için Java
ve Oracle
Yalçın Kaya
Editör C. Banu Üçüncüoğlu
19-0
C# ve T-SQL Geliştiriciler için Java ve Oracle
Yalçın Kaya
Editör: C. Banu Üçüncüoğlu
Kapak Tasarımı: Melih Sancar
Grafik Tasarım: Tuna Erkan
Grafik Uygulama: Soner Işık
Genel Yayın Yönetmeni: Mehmet Çömlekçi
1. Basım: Şubat 2008
Bilge Adam Yayınları: 21
Eğitim Yayınları Dizisi: 21
ISBN: 978-605-5987-19-0
Copyright © 2007, Bilge Adam Bilgisayar ve Eğitim Hizmetleri San. ve Tic. A.Ş.
Eserin tüm yayın hakları Bilge Adam Bilgisayar ve Eğitim Hizmetleri San. ve Tic. A.Ş.’ye aittir. Yayınevinden yazılı izin
alınmadan kısmen ya da tamamen alıntı yapılamaz, hiçbir şekilde kopya edilemez, çoğaltılamaz ve tekrar yayımlanamaz.
Bilge Adam’ın öğrencilerine ücretsiz armağanıdır, para ile satılamaz.
Bilge Adam Bilgisayar ve Eğitim Hizmetleri San. ve Tic. A.Ş.
19 Mayıs Mahallesi, 19 Mayıs Caddesi, UBM Plaza, No: 59-61, Kat: 4-7; Şişli, İstanbul
Telefon: (212) 272 76 00 – (212) 217 05 55 Faks: (212) 272 76 01
www.bilgeadam.com - info@bilgeadam.com
Tanıtım nüshasıdır, para ile satılamaz.
İçindekiler
Java’ya Giriş��������������������������������������������������������������������������������������������������������������������������������3
Java Nedir?����������������������������������������������������������������������������������������������������������������������������� 3
Windows Ortamında Java Kurulumu������������������������������������������������������������������������������3
Java Uygulamaları Nasıl Çalışır?�������������������������������������������������������������������������������������������� 7
Basit Veri Tipleri���������������������������������������������������������������������������������������������������������������������� 9
Ondalıklı Tipler�������������������������������������������������������������������������������������������������������������11
Mantıksal Tip����������������������������������������������������������������������������������������������������������������11
Karakter Tipi�����������������������������������������������������������������������������������������������������������������11
Aritmetik İşlemler ve Taşma�����������������������������������������������������������������������������������������11
Java’da Operatörler��������������������������������������������������������������������������������������������������������������� 14
Kaydırma (Shift) İşlemleri���������������������������������������������������������������������������������������������15
İşlemlerde Parantez Kullanımı�������������������������������������������������������������������������������������16
Karar Vermek ve Koşullu İfadeler��������������������������������������������������������������������������������16
Döngüler�������������������������������������������������������������������������������������������������������������������������������������23
While Döngüsü���������������������������������������������������������������������������������������������������������������������� 23
do Döngüsü��������������������������������������������������������������������������������������������������������������������������� 24
for Döngüsü��������������������������������������������������������������������������������������������������������������������������� 24
break ve continue Deyimleri������������������������������������������������������������������������������������������������� 25
Niteleyiciler (Modifiers)�������������������������������������������������������������������������������������������������������������29
Access Modifiers (Erişim Niteleyicileri)���������������������������������������������������������������������������������� 29
Niteleyicilerde Metod Ezme (Access Modifiers Overriding) ����������������������������������������30
Diğer Niteleyiciler ��������������������������������������������������������������������������������������������������������30
Casting ve Conversion�������������������������������������������������������������������������������������������������������������35
Basit Tiplerde Conversion����������������������������������������������������������������������������������������������������� 36
Basit Tiplerde Conversion: Atama��������������������������������������������������������������������������������36
Basit Tiplerde Conversion: Metod Çağırma�����������������������������������������������������������������38
Basit Tiplerde Conversion: Aritmetik Yükseltme ���������������������������������������������������������38
Basit Tiplerde Casting��������������������������������������������������������������������������������������������������39
Referans Tiplerde Conversion ���������������������������������������������������������������������������������������������� 40
Referans Tiplerde Conversion: Atama ������������������������������������������������������������������������40
Referans Tiplerde Csonversion: Metod Çağırma ��������������������������������������������������������41
IV
İçindekiler
Yapısal Programlama����������������������������������������������������������������������������������������������������������������45
Yapısal Programlama Nedir?������������������������������������������������������������������������������������������������ 45
Nesne Yönelimli Programlamanin Temel Bileşenleri���������������������������������������������������45
Nesne Yönelimli Programlamanın Temel Kavramları����������������������������������������������������������� 51
Kapsülleme (Encapsulation) ���������������������������������������������������������������������������������������51
Swing������������������������������������������������������������������������������������������������������������������������������������������67
Swing’e Giriş������������������������������������������������������������������������������������������������������������������������� 67
JButton�������������������������������������������������������������������������������������������������������������������������68
JLabel���������������������������������������������������������������������������������������������������������������������������69
JTextField���������������������������������������������������������������������������������������������������������������������70
Event Handling Mekanizması���������������������������������������������������������������������������������������71
JTextArea���������������������������������������������������������������������������������������������������������������������74
JOptionPane����������������������������������������������������������������������������������������������������������������75
JCheckBox�������������������������������������������������������������������������������������������������������������������77
JRadioButton����������������������������������������������������������������������������������������������������������������79
JComboBox������������������������������������������������������������������������������������������������������������������81
JList �����������������������������������������������������������������������������������������������������������������������������83
Mouse Event’lerinin Yönetilmesi:���������������������������������������������������������������������������������89
Klavye Event’lerinin Yönetilmesi������������������������������������������������������������������������������������������� 94
JDBC�����������������������������������������������������������������������������������������������������������������������������������������103
Veritabanı Bağlantısının Kurulması������������������������������������������������������������������������������������� 108
Veri Değiştirme Komutları (insert, update, delete)�������������������������������������������������������������� 109
Veri Sorgulama Komutları (Select)�������������������������������������������������������������������������������������� 110
Parametreli SQL İfadelerinin Çalıştırılması����������������������������������������������������������������112
Stored Procedure’lerin Çalıştırılması�������������������������������������������������������������������������113
JSP��������������������������������������������������������������������������������������������������������������������������������������������123
JSP Teknolojisinde Kullanılan Etiketler������������������������������������������������������������������������������� 128
JSP Direktifleri������������������������������������������������������������������������������������������������������������128
JSP Script Etiketleri����������������������������������������������������������������������������������������������������129
Form Verilerinin Kullanılması���������������������������������������������������������������������������������������������� 129
Durum Yönetimi ������������������������������������������������������������������������������������������������������������������ 131
JAVA I/O ����������������������������������������������������������������������������������������������������������������������������������143
Dosyalar ve Dizinler ����������������������������������������������������������������������������������������������������������� 143
İçindekiler
FilterInputStream Sınıfları������������������������������������������������������������������������������������������145
FileInputStream ve FileOutputStream Sınıflarının Kullanımı�������������������������������������146
Reader ve Writer Sınıfları: �����������������������������������������������������������������������������������������150
Standart Giriş-Çıkış Biriminin Kullanılması:���������������������������������������������������������������154
Java ile Ağ Programlama: �������������������������������������������������������������������������������������������������� 155
Oracle Veritabanı Ailesi����������������������������������������������������������������������������������������������������������161
Oracle Üzerinde Uygulama Geliştirme�������������������������������������������������������������������������������� 161
Oracle Veri Tabanı Sisteminin Kurulması������������������������������������������������������������������161
Tablespace�����������������������������������������������������������������������������������������������������������������167
Undo Tablespace�������������������������������������������������������������������������������������������������������167
Oracle’da Veri Tabanı Oluşturmak�����������������������������������������������������������������������������168
Temel Veri Tipleri�������������������������������������������������������������������������������������������������������179
Oracle’da Kullanıcı Yönetimi ve Güvenlik������������������������������������������������������������������179
Oracle Üzerinde Programlama�����������������������������������������������������������������������������������������������185
PL/SQL Nedir?�������������������������������������������������������������������������������������������������������������������� 185
SQL Plus��������������������������������������������������������������������������������������������������������������������185
TOAD�������������������������������������������������������������������������������������������������������������������������187
PL/SQL ile Programlama�������������������������������������������������������������������������������������������189
PL/SQL’de Kontrol Yapıları����������������������������������������������������������������������������������������191
PL/SQL’de Alfanümerik Tipler������������������������������������������������������������������������������������201
PL/SQL’de Mantıksal Tipler���������������������������������������������������������������������������������������207
PL/SQL’de Tarih ve Zaman Tipleri�����������������������������������������������������������������������������207
Referans Tipleri����������������������������������������������������������������������������������������������������������213
LOB (Large Object) Tipleri�����������������������������������������������������������������������������������������216
PL/SQL’de Döngü Yapıları�����������������������������������������������������������������������������������������216
1
Java’ya
Giriş
1 Java’ya Giriş
• Java Nedir?
• Java Uygulamaları Nasıl Çalışır?
• Basit Veri Tipleri
• Java’da Operatörler
Java’ya Giriş
Bölüm Hedefleri:

Java platformu üzerinde Java diliyle basit uygulamalar yazmak.

Temel veri tiplerini tanımak.
Java Nedir?
Java, işlemci mimarisinden ve işletim sisteminden bağımsız olarak tasarlanmış bir platformdur.
Aynı zamanda da bu platform üzerinde uygulama geliştirilen dilin adıdır. Microsoft .NET platformuyla karşılaştırdığımızda .NET platformuna karşılık gelen yapının adı Java olduğu gibi C#
.NET, Visual Basic .NET gibi .NET dillerine karşılık gelen dilin adı da Java’dır. Bu açıklamadan
anlaşılacağı gibi Microsoft .NET platformundan farklı olarak Java platformunda uygulama geliştirilebilecek tek dil vardır. Java platformu pek çok yönden Microsoft .NET platformuna benzediği
gibi Java dili de yetenekleri bağlamında C# diline çok benzer.
Java platformu da Microsoft .NET platformu ve modern nesne yönelimli diller gibi geniş bir sınıf
kütüphanesine sahiptir. Yine .NET platformuna benzer olarak bir Java uygulamasının çalışması
için doğrudan işletim sistemi kullanılmaz. Bu sebeple bir Java uygulaması, işletim sistemine ve
mimari platforma göre geliştirilmiş olan JVM (Java Virtual Machine) aracılığıyla çalıştırılır.
Java ile uygulama geliştirme için kullanılan ortamlar (IDE – Integrated Development Environment),
.NET için kullanılan ortamlara göre çok daha fazla sayıdadır ve kolaylık olarak farklılık gösterir.
Yaygın olarak kullanılan bütünleşik geliştirme ortamlarından (IDE) biri Eclipse’tir. Eclipse’i http://
www.eclipse.org adresinden indirebilirsiniz. Kitaptaki örnekleri gerçekleştirmek için herhangi bir
bütünleşik geliştirme ortamı indirmenize gerek yoktur, bütün örnekleri Windows üzerinde Notepad
ya da herhangi bir metin editörü ile gerçekleştirebilirsiniz.
Windows Ortamında Java Kurulumu
Java platformunu Windows işletimi üzerinde kurmak ve uygulamaları yazabilir hale gelmek için
öncelikle Java Development Kit’i (JDK) bilgisayarınızda kurmalısınız. JDK’nın sürümlerini http://
www.javasoft.com adresinden indirebilirsiniz. İndirdiğiniz dosyayı Windows’un tüm sürümlerinde
kurabilirsiniz.
Kurulumu gerçekleştirdikten sonra Windows ortamında çevre değişkenleri (environment variables) üzerinde işlem yapmamız gerekir. Komut satırında herhangi bir noktadan derleme ve çalıştırma programlarını kullanabilmek için Path değişkenine Java’yı kurduğumuz dizinin içindeki bin
dizinini eklemelisiniz.
Bölüm 1
Uygulama 1.1:
Windows XP:
1� Şekil 1’de gösterilen, Bilgisayarım (My Computer) ikonunu sağ tıklayın. Açılan menüde Özellikler (Properties) öğesini seçin.
Şekil 1
2. Şekil 2’de gösterildiği gibi, açılan pencerede Gelişmiş (Advanced) sekmesini tıklayın.
3� Şekil 2’de gösterildiği gibi, gelen pencerede Çevre Değişkenleri (Environment Variables) butonuna tıklayın.
Şekil 2
4. Şekil 3’te gösterilen, Sistem Değişkenleri (System Variables) içinde Path’i bulun ve en sonuna
“;” ekleyin.
Java’ya Giriş
Şekil 3
5. Şekil 4’te olduğu gibi, sonuna da <Java’yi kurduğunuz yer>\<JDKxxx>\bin yazın.
şekil 4
Windows Vista:
1� Şeki 5’daki gibi, Bilgisayarım (My Computer) ikonunu sağ tıklayın. Açılan menüde Özellikler
(Properties) öğesini seçin.
Şekil 5
Bölüm 1
2. Şekil 6’de gösterilen, Tasks bölümünden Advanced System Settings link’ine tıklayın.
Şekil 6
3� Şekil 8’de gösterildiği gibi, gelen pencerede Çevre Değişkenleri (Environment Variables) butonuna tıklayın.
Şekil 7
Java’ya Giriş
4. Şekil 8’da gösterildiği gibi, Sistem Değişkenleri (System Variables) içinde Path’i bulun ve en
sonuna “;” ekleyin.
Şekil 8
5. Şekil 9’daki gibi, sonuna da <Java’yi kurduğunuz yer>\<JDKxxx>\bin yazın.
Şekil 9
Java Uygulamaları Nasıl Çalışır?
Bir Java uygulamasının makinenizde çalışması için JVM’in kurulu olması gerekir. JVM Microsoft
.NET platformunun IL (Intermediate Language - MSIL) üzerinden çalışması mantığına benzer
bir mantıkla çalışır. Java tarafında IL’e karşılık gelen yapı bytecode’dur. JVM sadece bytecode
üzerinden çalışır. Bu sebeple yazmış olduğunuz Java kaynak kodunu öncelikle Java derleyicisiyle derleyerek bytecode’a çevirmelisiniz. Bununla birlikte dikkat edilmesi gereken bir nokta da bir
Java sınıfının derlenebilmesi için kaynak kodu tutan .java uzantılı dosyanın adının, içindeki public
sınıfın adıyla aynı olması gerektiğidir.
Örnek Uygulama 1.1:
1public class IlkJavaUygulamasi
2{
3
public static void main( String[] args)
4
{
5
6
}
7}
System.out.println(“Ilk Java Uygulamasi”);
Bölüm 1
İşlem adımları:
Örnekleri kolaylık açısından Windows’ta oluşturacağınız bir dizin içinde toparlamanız faydalı olacaktır.
1� Yukarıdaki kodu herhangi bir metin editöründe yazın ve “IlkJavaUygulamasi.java” adıyla kaydedin.
2. Command Prompt’u açın.
3� Dosyayı kaydettiğiniz dizine girin.
4. javac IlkJavaUygulamasi.java ifadesini çalıştırın.
5. Eğer hata almazsanız IlkJavaUygulamasi.class dosyasının kaynak kodla aynı yerde oluştuğunu görmelisiniz.
6. Java IlkJavaUygulamasi ifadesini çalıştırdığınızda komut satırında “Ilk Java Uygulamasi” ifadesini görmelisiniz.
Uygulamanın açıklaması: 1 numaralı satırda C#’ta olduğu gibi IlkJavaUygulamasi adında bir
sınıf tanımlanır. Java dilinde de, C#’ta olduğu gibi kod blokları sınıfların içinde yer almalıdır. 2
numaralı ve 4 numaralı satırlarda “{“ (küme parantezi, curly brace) işareti aynen C#’ta olduğu gibi
blok başı işaretidir. 2 numaralı satırdaki “{“ sınıf için tanımlanan bloğun başlangıcıyken 4 numaralı
satırdaki “{“ işareti de main metodunun başlangıcıdır.
6 numaralı ve 7 numaralı satırlardaki “}” işareti blok sonu işaretidir. 6 numaralı satırdaki “}” işareti
main bloğunun sonuyken, 7 numaralı satırdaki “}” işareti sınıf için açılan bloğun sonudur.
Blok başı ve blok sonu ifadelerinde dikkat etmeniz gereken en önemli nokta son açılan blok her
zaman ilk kapatılan bloktur ve her açılan blok mutlaka kapatılmalıdır.
3 numaralı satırda aynen C#’ta olduğu gibi main metodunun tanımını görebilirsiniz. public
static void ifadelerinin anlamları C# ile aynı olmakla birlikte daha sonra detaylı olarak incelenecektir. Main metodunun parametresi olan String[] args de metodun parametre olarak
bir String dizisi aldığını belirtir. Main metodu, Java’da da konsol uygulamalarının otomatik olarak
çalışan ilk metodudur.
5 numaralı satırda main metodu çalıştığında ne yapacağını gösterir. System.out.println();
ifadesi C#’taki Console.WriteLine() ifadesine karşılık gelir. Burada System.out standart
çıktı birimini temsil eder. Varsayılan olarak kullandığınız ekrandır. println() metodu, kendisine
parametre olarak verilen ifadeye yazar ve sonundaki “ln” (line) kısmından dolayı bir satır aşağıya
geçer. İfadenin sonundaki “;” işareti Java’da da C#’taki her ifadenin sonunda mutlaka bulunması
gereken satır sonlandırıcısıdır.
Bu basit uygulamaya bakarak C# dili ile Java dilinin birbirine pek çok noktada benzediğini görebilirsiniz. Bundan sonraki pek çok aşamada C# dili ile Java dili arasındaki benzerliklere tanık
olacaksınız.
İlk uygulamada konsola System.out.println() yazdırdığımız ifadeyi bir mesaj kutusunda
yazdırmak istersek bir miktar değişiklik yapmamız gerekecektir.
Örnek Uygulama 1.2a:
1public class MesajKutusu
2{
3 public static void main( String[] args)
4 {
5
6 }
7}
javax.swing.JOptionPane.showMessageDialog(null, “Ilk Java Uygulamasi”);
Java’ya Giriş
Uygulamanın açıklaması: Bu uygulamanın 5 numaralı satırı dışındakiler önceki uygulamadan
farklı değildir. 5 numaralı satırda da C#’taki MessageBox.Show() metodunun Java’daki benzeri
olan JoptionPane.showMessageDialog() metodu kullanılmıştır. Bu kodun başındaki javax.swing de JOptionPane sınıfının içinde bulunduğu pakettir. Java’daki paketleri .NET’teki
assembly’ler gibi düşünebilirsiniz. Dolayısıyla C#’taki using ifadesinin karşılığı olarak import
ifadesini kullanarak kodumuzu aşağıdaki şekilde güncelleyebiliriz.
Örnek Uygulama 1.2b:
1import javax.swing.JOptionPane;
2public class MesajKutusu
3{
4
public static void main( String[] args)
5
{
6
7
}
JOptionPane.showMessageDialog(null, “Ilk Java Uygulamasi”);
8}
Bu örnekte 1 numaralı satırdaki import ifadesi javax.swing paketindeki JOptionPane sınıfının yüklenmesini sağlar. Bir kere yüklendikten sonra tekrar paket adının kod içinde kullanmamıza
gerek kalmaz. Burada yapılan yükleme işlemi, .NET’teki gibi, yüklenen paketin içerdiği kodu,
oluşturulan .class dosyasının içine eklemez, sadece o pakete erişimi sağlayacak kodu oluşturur.
Uygulama 1.2b’deki 6 numaralı satırda JOptionPane sınıfının
showMessageDialog metodunun ilk parametresi swing paketinin detaylarına gelene kadar sürekli null olarak kullanılacaktır. 2.
parametre de tahmin edebileceğiniz gibi mesaj kutusunda yazdırılacak ifadedir.
Java’da comment’lerin kullanımı C# ile aynıdır. // Satır comment. /* */ Blok comment.
Basit Veri Tipleri
Java’daki basit (primitive) veri tipleri .NET’teki basit veri tipleriyle çok benzerdir. Herhangi bir veri
tipinin tanımlanması C#’takinden farklı değildir. Bununla birlikte Java’daki sayısal tiplerin hepsi
işaretlidir (signed – hem negatif hem de pozitif sayıları tutar), işaretsiz veri tipi yoktur. Öncelikle
tam sayısal veri tiplerinden başlayalım:
byte: Adından da anlaşılabileceği gibi 1 byte’lık, tam sayı tutan veri tipidir. C#’ta sbyte’a, .NET
CTS’te System.SByte’a karşılık gelir. Herhangi bir byte değişken tanımlaması aşağıdaki şekillerde yapılabilir:
byte yas; //ilk değer verilmeden.
byte yas = 67; //ilk değer verilerek.
short: 2 byte’lık, tam sayı tutan veri tipidir. C#’ta short’a, .NET CTS’te System.Int16’ya
karşılık gelir. Herhangi bir short değişken tanımlaması aşağıdaki şekillerde yapılabilir:
short derinlik; //ilk değer verilmeden.
short derinlik = 23245; //ilk değer verilerek.
int: 4 byte’lık, tam sayı tutan veri tipidir. C#’ta int’e, .NET CTS’te System.Int32’ye karşılık
gelir. Herhangi bir int değişken tanımlaması aşağıdaki şekillerde yapılabilir:
10
Bölüm 1
int sayi; //ilk değer verilmeden.
int sayi = 12; //ilk değer verilerek.
long: 8 byte’lık, tam sayı tutan veri tipidir. C#’ta long’a, .NET CTS’te System.Int64’e karşılık
gelir. Herhangi bir long değişken tanımlaması aşağıdaki şekillerde yapılabilir:
long GNP; //ilk değer verilmeden
long GNP = 1234567890; //ilk değer verilerek
Bunların dışında basit veri tipi olmamakla birlikte şu aşamada bilmeniz gereken bir veri tipi daha
var: String. String tipi referans üzerinden çalışan bir veri tipidir. Yani, aslında basit veri tiplerinden farklı olarak bir nesne üzerinden çalışırlar; fakat tanımlaması şu ana kadar bahsedilen
veri tiplerinden farklı değildir. String’in detaylarına ilerleyen bölümlerde değineceğiz. Burada
dikkat etmemiz gereken nokta Java’da küçük harf “s” ile başlayan string tanımının olmamasıdır.
Herhangi bir String veri tanımlaması aşağıdaki şekillerde yapılabilir:
String Ad; //ilk değer verilmeden
String Ad = “Yalcin”; //ilk değer verilerek
Artık kullanıcıdan 2 sayı alıp bunları matematiksel herhangi bir işlem içinde kullanabilecek hemen
her şeye sahibiz. Tek eksiğimiz bu sayıları kullanıcıdan nasıl alacağımız. Matematiksel işlemlerin
nasıl yapıldığına gelirsek, ileride farklılıklarına değineceğemizi belirterek C#’taki yazılışlarından
şu an için hiçbir farkı yoktur diyebiliriz. Şimdi bunu örnekleyelim:
Örnek Uygulama 1.3:
1import javax.swing.JOptionPane;
2public class MesajKutusu
3{
4
public static void main( String[] args)
5
{
6
String birinciSayi, ikinciSayi;
7
int toplam, sayi1, sayi2;
8
birinciSayi = JOptionPane.showInputDialog(“Birinci sayiyi giriniz:”);
9
ikinciSayi = JOptionPane.showInputDialog(“Ikinci sayiyi giriniz:”);
10
sayi1 = Integer.parseInt(birinciSayi);
11
sayi2 = Integer.parseInt(ikinciSayi);
12
toplam = sayi1 + sayi2;
13
JOptionPane.showMessageDialog(null, toplam);
14
}
15}
Kod Açıklaması: 6 numaralı satırda String tipinde 2 değişken tanımlanmıştır. Unutmayın ki bu
2 değişken de basit veri tipi değil referans tipli değişkenlerdir. Bu değişkenler JOptionPane sınıfının showInputDialog metodunun döndürdüğü değerleri tutmak için kullanılmıştır. 7 numaralı
satırda 3 tane tam sayı tanımlanmıştır. toplam adlı değişken JOptionPane.showInputDialog() metoduyla aldığımız değerlerin sayıya dönüştürülmüş hallerini toplamak için kullanılmıştır. sayi1 ve sayi2 değişkenleri de JOptionPane.showInputDialog() metoduyla aldığımız
Java’ya Giriş
değerlerin sayıya dönüştürülmüş hallerini tutacaktır. 8 ve 9 numaralı satırlarda JOptionPane.
showInputDialog() metodlarıyla, yukarıda tanımladığımız String’lerin içine, kullanıcının gireceği değerler alınmaktadır. Burada dikkat etmemiz gereken nokta, rakamlar dışında değerler
girdiğimizde 10 ve 11 numaralı satırlarda dönüştürme hatasıyla karşılaşma durumumuzdur. Bu
satırlarda kullanıcı tarafından girilmiş olan String’ler Integer sınıfının parseInt() aracılığıyla int’e çevrilmeye çalışılır. Integer sınıfı .NET’teli System.Int32 sınıfına karşılık gelen
sınıftır ve terimsel olarak wrapper class olarak geçer. parseInt() metodu da Int32 sınıfının
Parse() metoduyla aynı şekilde çalışır. Eğer kendisine gönderilen parametre int’e çevrilemiyorsa “NumberFormatException” oluşturur. Bunun için de C#’taki gibi istisna yönetimi (exception handling), yani try-catch-finally bloklarını kullanabiliriz.
10 ve 11 numaralı satırlarda eğer herhangi bir exception oluşmazsa, yani bir int’in alabileceği
değer aşılmazsa 12 numaralı satır çalışır. Eğer 2 değerin toplamı bir int’in alabileceği en büyük
değeri aşıyorsa toplam değişkeninin alacağı değer negatif bir sayıya dönecektir. Çünkü Java, C
geleneğinden dolayı sayıları kontrol etmez. Bu durumu daha küçük bir tam sayı tipi olan byte
üzerinden Uygulama 1.4’te açıklayacağım.
13 numaralı satırda bir önceki örnekte kullandığımız JOptionPane.showMessageDialog()
metoduyla toplam değişkeninin değerini yazdırıyoruz. Sınıf adıyla kullanılması sebebiyle showMessageDialog() metodunun JOptionPane sınıfının static bir metodu olduğunu anlayabilirsiniz.
Ondalıklı Tipler
double: 8 byte’lık ondalıklı veri tipidir. Tanımlandığı standart (IEEE 754) çerçevesinde yüksek doğruluk isteyen işlemlerde kullanılmamalıdır; ancak ondalıklı kısımda yüksek yoğunluk çok
önemli değilse kullanılabilir. C#’ta float’a, .NET CTS’te System.Single’a karşılık gelir.
float: 4 byte’lık ondalıklı veri tipidir. Hem tanımlandığı standart çerçevesinde hem de double
veri tipine göre daha küçük bir veri tipi olması sebebiyle yüksek doğruluk isteyen işlemlerde kullanılmamalıdır; ancak ondalıklı kısımda yüksek yoğunluk çok önemli değilse kullanılabilir. Eğer bellek yetersizliği ile ilgili bir problem yoksa float yerine double tercih edilmelidir. C#’ta double’a,
.NET CTS’te System.Double’a karşılık gelir.
Her 2 ondalıklı veri tipinin yerine java.math paketinde bulunan BigDecimal sınıfı kullanılabilir.
Mantıksal Tip
boolean: true ya da false değerlerinde birini taşıyabilen basit veri tipidir. Taşıdığı veri sadece 1 bit ile gösterilebiliyor olsa da kapladığı alan 1 bit değildir. C#’ta bool’a, .NET CTS’te System.Boolean’a karşılık gelir.
Karakter Tipi
char: 2 byte’lık Unicode karakter olarak herhangi bir karakter bilgisini tutmak için kullanılır. C
ailesi geleneğinden dolayı işaretsiz tam sayısal veri tipi olarak değerlendirilebilir. C#’ta char’a,
.NET CTS’te System.Char’a karşılık gelir.
Aritmetik İşlemler ve Taşma
Java’da tam sayısal aritmetik işlemler, işleme giren değerlerin tipleri eğer birer int değilse int’e
dönüştürülerek yapılır. Eğer işleme giren tiplerden en az biri long ise long’a dönüştürülerek
yapılır.
Eğer tipler ondalıklı ise işlemler, işleme giren tipler double’a dönüştürülerek yapılır. Dolayısıyla
aşağıdaki örnekleri dikkatle incelemek gereklidir:
11
12
Bölüm 1
Örnek Uygulama 1.4a:
1public class TipDonusumleri1
2{
3
public static void main( String[] args)
4
{
5
byte sayi1 = 120;
6
byte sayi2 = 110;
7
byte toplam = sayi1 + sayi2;
8
}
9}
Bu örnekte 7 numaralı satırda sayi1 + sayi2 ifadesi, işlem int üzerinden yapıldığından çalışacaktır; ancak toplam değişkeninin tipi byte olduğu için derlenemeyecektir ve possible loss of
precision (değer kaybı ihtimali) hatası verecektir. Bunun sebebi toplanan byte tipindeki değişkenlerin değerlerinin toplamının, byte tipindeki bir alana sığmaması değildir. (120 + 110 = 230,
byte tipinin alabileceği en büyük değer ise 127’dir). Bunu sayi1’in değerini 12, sayi2’nin değerini
11 yaparak görebilirsiniz. Possible loss of precision hatasını bu durumda da alacaksınız. (12 +
11 = 23, byte tipinin içine sığar). Dolayısıyla bu hatanın sebebi, sayi1 + sayi2 işleminin int üzerinden yapılmasıdır. Bunu anlamak için 7 numaralı satırda tanımlanan toplam değişkeninin tipini
byte’tan short’a çevirip tekrar derleyerek de görebilirsiniz. Bu durumda 120 ile 110’un toplamı
olan 230 değeri short tipine sığacak bir değer olmasına rağmen possible loss of precision hatasını yine alırsınız; ancak toplam değişkeninin değerini int ya da long yaparak bu hatadan
kurtulabilirsiniz.
Uygulama 1.4a örneği üzerinde düşündüğümüzde yapılan işlem anormal gelmemelidir. Çünkü
burada 2 tane byte tipli değişkenin toplamının değerinin byte tipine sığmaması ihtimali yüksektir. Bu durumda, eğer bu işlemi byte tipi üzerinden gerçekleştirmek istersek ne yapmalıyız?
Bunun cevabını da Uygulama 1.4b’de görebilirsiniz.
Örnek Uygulama 1.4b:
1public class TipDonusumleri2
2{
3
public static void main( String[] args)
4
{
5
byte sayi1 = 12;
6
byte sayi2 = 11;
7
byte toplam = (byte)(sayi1 + sayi2);
8
System.out.println(toplam);
9
}
10}
Örnek Uygulama 1.4b’de 7 numaralı satırda yaptığımız işlem bir explicit cast (göstererek dönüştürme) işlemidir. Uygulama 1.4a’da int’e dönüştürme ise implicit cast (gizli dönüştürme) işlemi
olarak adlandırılır. Daha sonra bu işlemleri farklı isimlerle tekrar değerlendireceğiz. Burada sayi1
+ sayi2 işlemi önce yine int üzerinden yapılır ve sonra byte’a dönüştürme yapılır. Bu şekilde
12 ile 11’in toplamı olan 23 değerini byte olarak elde edebilirsiniz. Buraya kadar herşey güzel; ancak bu noktada Uygulama 1.3’deki taşma problemimize geri dönelim ve 5 ve 6 numaralı
satırlarda tanımladığımız byte tipli değişkenlerimizin değerlerini sırasıyla 120 ve 110 yapalım.
Yeni değerlerin her ikisi de byte tipine sığabilirler; fakat toplamları olan 230 değeri byte tipine
Java’ya Giriş
sığmaz. Java uygulaması bu durumda hata vermeyecektir ve 8 numaralı satırdaki System.out.
println()’den dolayı konsola -26 yazacaktır. Bunu detayıyla şu şekilde açıklayabiliriz:
Bildiğiniz gibi güncel bilgisayar sistemleri 2’lik (binary) sistemle çalışırlar, yani herşey 1 ve 0 ile
ifade edilir. Dolayısıyla sayi1 ve sayi2 değişkenlerimizin 2’lik sistemdeki karşılıkları şu şekildedir:
sayi1 = 120 = (01111000)2
sayi2 = 110 = (01101110)2
Sayıların 2’lik sistemdeki karşılıklarının başındaki 0, byte tipinin 1 byte’lık yani 8 bitlik olmasından dolayı sayıyı 8 bite tamamlamak içindir; ancak en başa eklediğimiz bu 0’ın taşıdığı çok
daha farklı bir anlam vardır, Bu ilk değer sayının pozitif ya da negatif olmasını belirler. Eğer 0 ise
arkasından gelen tüm bitler pozitif sayıya göre yorumlanacaktır, eğer 1 ise negatif sayıya göre
yorumlanacaktır. Şimdi de sayıları toplayalım:
sayi1 + sayi2 = 120 + 110 = 230
sayi1 + sayi2 = (01111000)2 + (01101110)2 = (11100110)2
toplam = (11100110)2
Az önce bahsettiğimiz işaret biti durumundan dolayı 2’lik sayının en başındaki değer olan 1, gerisindeki 7 bitin negatif sayıya göre yorumlanacağını gösterir. Dolayısıyla Java’da tamsayıların
tümünde sayı değeri en soldaki bitin pozitif ya da negatif olması durumu netleştikten sonra ortaya
çıkar. Örnek olarak şu sayıları ele alalım:
5 = (00000101)2
En baştaki 0 sayının pozitif olduğu anlamına gelir. Devamındaki 0000101’de de ilk 1’e kadar olan
0’ların bir anlamı yoktur. Böylece elimizde (101)2 kalır. Bunun da karşılığı 10’luk sistemde 5’tir.
Açılımı ise şu şekildedir.
1 x 20 = 1
0 x 21 = 0
1 x 22 = 4
1 + 0 + 4 = 5
Bu noktadan sonra eğer sayımız negatif ise durumun değiştiğini göreceğiz. Örnek olarak -1’i ele
alacağız.
Eğer 1 = (00000001)2 ise; -1 = (11111110)2 + (00000001)2’dir. Yani (11111111)2’dir. Bu yönteme
2’nin tamlayanı yöntemi denir. (11111110)2 de (00000001)2’nin bire tamlayanıdır. Burada niçin bu
kadar dolandırılmış diye düşünebilirsiniz; ancak unutmayın ki gündelik hayatta kullandığımız gibi
bir “-” işaretine sahip değiliz. Bu durumu -1 ile 1’i toplayarak deneyelim:
(00000001)2 + (11111111)2 = (100000000)2
Elimizde 9 bitlik bir veri oluştu; ancak byte veri tipi 8 bitlik bir veri tipiydi. Bu durumda en baştaki
1 değeri hiçbir değerlendirmeye katılmadan son 8 bit değerlendirilir; yani (00000000)2 değeri kullanılır. Burada ilk bit 0 olduğu için sayı pozitiftir diyebiliriz. Geri kalan 7 bit de 0 olduğu için sayı
10’luk sistemdeki 0’a karşılık gelir. Bu durumda aklınıza takılabilecek olan soru 0’ın pozitifliği ya
da negatifliği olabilir. 0 sayısı matematikte ne pozitif tam sayılar kümesinin ne de negatif tamsayılar kümesinin bir üyesidir; ancak programlama dillerinde 0 değeri pozitiftir.
13
14
Bölüm 1
Sonuç olarak bilgisayar için negatif bir sayının 2’lik sistemde nasıl yazıldığını bulmak istiyorsak şu
şekilde bir işlem gerçekleştirmeliyiz:
Sayıyı 2’lik sistemde pozitif olarak yazın.
Oluşan sayıdaki 0’ları 1, 1’leri 0 yapın.
Sayıya 2’lik sistemde 1 ekleyin.
Örnek olarak -5’e ulaşmaya çalışalım:
5 = (00000101)2
1’ e tamlayan = (11111010)2
2’ye tamlayan = (11111011)2
Böylece Uygulama 1.4b’nin açıklamasında elde ettiğimiz (11100110)2 değerini irdeleyebilir duruma geldik. Yukarıdaki işlemi tersten yaptığınızda da sayıya ulaşabilirsiniz.
(11100110)2 – (00000001)2 = (11100101)2
1’e tamlayan = (00011010)2
(00011010)2 = 26
Dolayısıyla elimizdeki sayı 10’luk sistemdeki -26’ya karşılık gelir. Bu detayları bilmemeniz halinde
basit bir sayısal problem üzerinde çok zaman harcayabilirsiniz. Çünkü gördüğünüz şekilde Java
aritmetik işlemlerde taşan sayılar için hata vermez.
Java’da Operatörler
Java’da tipler üzerinde işlem yapmak için pek çok operatör bulunur. Bu operatörlerin çoğu C#’ta
da aynı şekilde mevcuttur.
Öncelik Sırası
Öne gelen (prefix)
++ifade, --ifade
Sona gelen (postfix)
ifade++, ifade--
Tek ifade alan
+ifade, -ifade, ~, !
Çarpımsal
*, /, %
Toplamsal
+, -
Kaydırma
<<, >>, >>>
İlişkisel
<, >, <=, >=, instanceof
Eşitlik
==, !=
Bit üzerinde (bitwise) VE (AND)
&
Bit üzerinde özel VEYA (EX-OR)
^
Bit üzerinde VEYA (OR)
|
Mantıksal VE (AND)
&&
Mantıksal VEYA (OR)
||
Üçlü ifade alan (ternary) operatör
?:
Atama
=, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=
Java’ya Giriş
Gördüğünüz gibi Java’daki birkaç operatör dışında hemen hemen tüm operatörler C# ile aynıdır.
Bit üzerinde işlem yapan operatörler kestirmeli (shortcut) operatörlerdir. Yani operandlarından
(işleme giren değerlerinden) biri işlemin sonucunu kesin olarak ortaya koyuyorsa işlemin devamındaki operand değerlendirilmez.
Örnek Uygulama 1.5a:
1public class Operatorler1
2{
3
public static void main( String[] args)
4
{
5
int sayi, sonuc;
6
sayi = 5;
7
sonuc = sayi++ + ++sayi;
8
System.out.println(sonuc);
9
System.out.println(sayi);
10
}
11}
Bu uygulamada 8 ve 9 numaralı satırlar işlendiğinde ekranda yazacak değerlerin ne olduğunu ve
7 numaralı satırın nasıl işlediğine bakalım. 6 numaralı satırda sayi değişkeninin değeri 5 yapıldıktan sonra 7 numaralı satırda sonuc = sayi++ + ++sayi; ifadesi işletilmektedir. Bu satırı
daha detaylı inceleyelim:
sonuc = sayi++ + ++sayi; ifadesinde önce ++sayi ifadesi çalışacaktır ve sayi değişkenine 1 ekleyerek değerini 6 yapacaktır. Daha sonra sayi++ işlemeden sayi değeri ile artırılmış
sayi değerleri toplanarak sonuc değişkenine atama yapılacaktır. Böylece 6 + 6 = 12 değeri sonuc değişkeninin değeri olur. Bu atama yapıldıktan sonra sayi değişkenine sayi++’dan dolayı
tekrar 1 eklenecektir ve sayi değişkeninin değeri 7 olacaktır.
Kaydırma (Shift) İşlemleri
Kaydırma işlemleri genellikle sistem programlama, oyun programlama gibi uzmanlık gerektiren
alanlarda kullanılır. Değerimizi temsil eden 2’lik sayı sistemindeki değeri sağa ya da sola belirtilen bit sayısı kadar kaydırır ve kaydırılan alanlara 0 değerini koyar. İşaret bitiyle ilgili detayları da
vardır. Bu sebeple bir örnekle gösterip detaylı olarak anlatmayacağım.
Örnek Uygulama 1.5b:
1public class Operatorler2
2{
3
public static void main( String[] args)
4
{
5
int sayi;
6
sayi = 5;
7
sayi <<= 2;
8
System.out.println(sayi);
9
}
10}
Bu örnekte 7 numaralı satırda sayi değişkeninin bitleri 2 kademe sola kaydırılmaktadır. Bu işlem
nasıl yapılıyor inceleyelim:
15
16
Bölüm 1
int 32 bit (4 byte) olduğu için 2’lik sayı sisteminde aşağıdaki gibi gösterilir.
sayi = 5 = 00000000 00000000 00000000 00000101
Bu değer sola 1 bir kaydırıldığında;
sayi = 0 00000000 00000000 00000000 00001010 = 10
değeri elde edilir. En baştaki 0 düşen bittir, ve en sondaki 101 değerleri sola kaydırılarak en sona
da 1 tane 0 eklenmiştir.
sayi <<= 2 ifadesi sola doğru 2 bitlik kaydırma işlemi olduğu için sayi 1 bit daha sola kaydırılmalıdır.
sayi = 00 00000000 00000000 00000000 00010100 = 20
Böylece sayi değişkeninin değeri 20 olur. Dikkat ederseniz sola kaydırma 2 ile çarpma gibidir.
İşlemlerde Parantez Kullanımı
Matematiksel ya da mantıksal işlemlerde parantezlerin içine alınan ifadelerin önceliği ilk sıraya çıkar. Matematik bilgimizden tek farkı kullandığımız tek işaretin sadece normal parantez olmasıdır,
köşeli parantez ya da küme parantezi kullanılmaz.
Örnek: Bu ifadeyi matematiksel olarak yazmak istediğimizde eğer;
d = m * P / n * r * T;
şeklinde yazarsak çarpma ve bölmenin önceliklerinin aynı olması sebebiyle işlem soldan sağa
sırayla gerçekleşecektir. Böyle olunca m ile P çarpıldıktan sonra n ile bölünecek, bunun sonucu
da r ile T’nin çarpımıyla çarpılacaktır. Oysa ifadenin gösterdiği m ile P’nin çarpımının n, r ve T’nin
çarpımına bölünmesi şeklindedir. Bu sebeple bu matematiksel ifadeyi;
d = m * P / (n * r * T);
şeklinde yazmalıyız.
Karar Vermek ve Koşullu İfadeler
Java’da da C#’taki gibi karar verme ve koşullu ifade yazmak için 2 ifade ve 1 operatör söz konusudur. Bunlar:
1� if...else
2. Üçlü ifade alan operatör (? :)
3� switch...case
if...else Yapısı
if... else yapısı Java’da da aynen C#’taki gibi kullanılır. En basit yapısı sadece if’in kullanıldığı
şeklidir. Koşullu ifadelerde dikkat edilmesi gereken nokta koşulun sonucunun true ya da false,
yani boolean bir ifade üretmesi gerekliliğidir. Bu yönüyle C geleneğiyle farklılaşır.
Java’ya Giriş
Örnek Uygulama 1.6a:
1import javax.swing.JOptionPane;
2public class Kosul1
3{
4
public static void main( String[] args)
5
{
6
int sayi1 = Integer.parseInt(JOptionPane.
showInputDialog(“Birinci sayıyı giriniz”));
7
int sayi2 = Integer.parseInt(JOptionPane.
showInputDialog(“Ikinci sayıyı giriniz”));
8
if( sayi1 < sayi2)
9
{
10
JOptionPane.showMessageDialog(null, sayi1 +
“ kucuktur “ + sayi2);
11
}
12
}
13}
8 numaralı satırda yapılan karşılaştırmanın sonucu, yani sayi1 değişkeninin değerinin sayi2 değişkeninin değerinden küçük olma durumu true ya da false, daha genel bir ifadeyle boolean bir sonuç üretir. Eğer karşılaştırmanın sonucu true ise if bloğunun içi çalıştırılır, if bloğu sonlandığında
da akış kaldığı yerden devam eder; aksi takdirde if bloğunun içi çalıştırılmadan programın akışı if
bloğu yokmuş gibi çalışmaya devam eder. Koşullar gibi bir sonraki bölümde inceleyeceğimiz döngü ve
tekrarlı yapılarda da kodun okunurluğunu artırmak için if bloğunun içi tek ifadeden oluşsa bile blok
parantezlerini, tek ifade için şart olmamasına rağmen kullanmayı alışkanlık haline getirin.
Örnek Uygulama 1.6b:
1import javax.swing.JOptionPane;
2public class Kosul2
3{
4
public static void main( String[] args)
5
{
6
int sayi1 = Integer.parseInt(JOptionPane.
showInputDialog(“Birinci sayıyı giriniz”));
7
int sayi2 = Integer.parseInt(JOptionPane.
showInputDialog(“Ikinci sayıyı giriniz”));
8
if( sayi1 < sayi2)
9
{
10
JOptionPane.showMessageDialog(null, sayi1 +
“ kucuktur “ + sayi2);
11
}
12
else if( sayi1 > sayi2)
13
{
14
JOptionPane.showMessageDialog(null, sayi1 +
“ buyuktur “ + sayi2);
15
}
16
}
17}
17
18
Bölüm 1
Bu örnekteki çalışma şekli Uygulama 1.6a’dakiyle aslında aynı şekildedir. Eğer 8 numaralı satırdaki karşılaştırma true sonuç vermezse akış 12 numaralı satırdan devam edecektir. Bu blok da
else bloğudur. else bloğu aslında if bloğundan sonraki akışın ilk parçasıdır. else bloğunda
bir karşılaştırma daha yapılmaktadır. Bu karşılaştırmada da aynen 8 numaralı satırdaki if bloğu
gibi bir çalışma mekanizması söz konusudur. Eğer karşılaştırma sonucu true ise else bloğu çalışır; aksi takdirde else bloğundan sonraki noktadan; yani 16 numaralı satırdan itibaren çalışma
devam eder. Bu uygulamada, Örnek Uygulama1.6a’ya göre farklılaşan tek nokta eğer 8 numaralı
satırdaki karşılaştırma true sonuç üretirse 12 numaralı satırdaki else bloğu, her ne kadar kendinden sonra gelen ilk ifade olsa da çalışmaz.
Örnek Uygulama 1.6c:
1import javax.swing.JOptionPane;
2public class Kosul3
3{
4
public static void main( String[] args)
5
{
6
int sayi1 = Integer.parseInt(JOptionPane.
showInputDialog(“Birinci sayıyı giriniz”));
7
int sayi2 = Integer.parseInt(JOptionPane.
showInputDialog(“Ikinci sayıyı giriniz”));
8
if( sayi1 < sayi2)
9
{
10
JOptionPane.showMessageDialog(null, sayi1 +
“ kucuktur “ + sayi2);
11
}
12
else if( sayi1 > sayi2)
13
{
14
JOptionPane.showMessageDialog(null,sayi1 +
“ buyuktur “ + sayi2);
15
}
16
else
17
{
18
JOptionPane.showMessageDialog(null, sayi1 +
“ esittir “ + sayi2);
19
}
20
}
21}
Bu uygulamada değişen tek nokta 16 numaralı satırdaki koşulu olmayan else bloğudur. Böylece
sayi1 değişkenin değeri ile sayi2 değişkeninin değeri arasında yapılan karşılaştırmada durum
ne olursa olsun, bir exception üretilmediği sürece, bu 3 bloktan birinin çalışması kesindir. 16 numaralı satırdaki else bloğunun çalışması için 8 ve 12 numaralı satırlardaki karşılaştırmalardan
false üretilmesi gerekir. Bu örnekte bu durum 2 sayıyı karşılaştırırken, iki sayının birbirine eşit
olması durumudur. Bu bloklardan hangisi çalışırsa çalışsın, akış 20 numaralı satırdan devam
edecektir.
Java’ya Giriş
Örnek Uygulama 1.6d:
1import javax.swing.JOptionPane;
2public class Kosul4
3{
4
public static void main( String[] args)
5
{
6
int sayi1 = Integer.parseInt(JOptionPane.
showInputDialog(“Birinci sayıyı giriniz”));
7
int sayi2 = Integer.parseInt(JOptionPane.
showInputDialog(“Ikinci sayıyı giriniz”));
8
if( sayi1 < sayi2)
9
{
10
JOptionPane.showMessageDialog(null, sayi1 +
“ kucuktur “ + sayi2);
11
}
12
else if( sayi1 < sayi2)
13
{
14
JOptionPane.showMessageDialog(null, sayi1 +
“ buyuktur “ + sayi2);
15
}
16
}
17}
Bu uygulamalarda göstermek istediğim durum 8 ve 12 numaralı satırlardaki karşılaştırmaların
aynı olmasıdır. Bu durumda eğer 8 numaralı satırdaki karşılaştırma true üretirse 12 numaralı
satır, aynı karşılaştırmayı yapmasına rağmen çalışmayacaktır. Eğer 8 numaralı satırdaki karşılaştırma false üretirse 12 numaralı satırdaki aynı karşılaştırma tekrar yapılacaktır ve doğal olarak
o da false üreteceğinden else bloğu da çalışmayacaktır. Bunun da anlamı uygulamada durum
ne olursa olsun hiçbir zaman else bloğunun çalışmayacağıdır.
Sayısal karşılaştırmalardan sonra şimdi mantıksal işlemlere bakalım. Mantıksal işlemler sayısal
ifadelerden farklı olarak zaten boolean sonuç üretir. Mantıksal işlemler AND (VE), OR (VEYA),
EX-OR (ÖZEL VEYA), NOT (DEĞİL) işlemleridir. Mantıksal işlemlerin kestirmeli ve kestirmesiz
olmak üzere 2 şekli vardır. Kestirmeli (short-circuited) işlemler doğruluğu kontrol edilecek ifadenin içinde bulunan ifadelerden herhangi biri bütün ifadenin sonucunu belirlediği anda diğer
ifadeler kontrol edilmez. Kestirmeli (short-circuited) işlemlerde, bir ifadenin içinde bulunan bütün
ifadelerin doğruluğu kontrol edilir, sonuç belirlense bile işlem sona ermez.
19
2
Döngüler
2 Döngüler
• While Döngüsü
• do Döngüsü
• for Döngüsü
• break ve continue Deyimleri
Döngüler
Birçok programlama dilinde olduğu gibi, Java dilinde de döngüler önemli bir yere sahiptir. Döngüler, yinelenen işlemler için oluşturulan kod bloğunun, belirli bir koşula bağlı olarak tekrarlanmasını
sağlayan yapılardır.
Java dilinde 3 tip döngü mevcuttur. Bunlar;

while

do

for
döngüleridir.
Oluşturulan döngü yapıları birkaç farklılık dışında, içinde bulunan kod parçacığını baştan belirlenen ya da program akışı içerisinde belirlenen sayıda tekrarlanmasını sağlar. Döngüler belirli sayıda işlenmek üzere kurulabileceği gibi kod bloğu içerisinde gerçekleştirilecek bir koşul sağlanana
kadar tekrarlanmak üzere de gerçekleştirilebilir.
Döngülerin oluşturulması sırasında dikkat edilmesi gereken en önemli noktalardan biri, döngü
içerisinde işlenecek kod parçacığının işlem sayısıdır. Belirli bir sayı ya da bir kontrol koşulu ile
kurulmayan döngüler, program akışının sürekliliğini bozarak çalışan kodu sonsuz döngüye sokabilir.
Bir döngünün işlenmesi sırasında ya da sonsuz döngü durumunda, kod bloğunun içerisinde müdahaleler gerekli olabilir. Bu müdahaler de break ve continue yapıları ile sağlanmaktadır.
While Döngüsü
while döngüsünün genel yapısı aşağıdaki gibidir.
while( boolean_kontol_ifadesi) {
Tekrarlanan_Ifade(ler) ;
}
Bu ifadede yer alan boolean_kontol_ifadesi kontrolu sonrasında boolean bir sonuç veren herhangi bir ifade olabilir. Tekrarlanan_Ifade(ler) ise yinelenmesi istenen kod bloğudur.
C ve C++ dillerinde farklı veri tipleri ile kontrol yapılabilirken, Java da farklı olarak buradaki kontrol
boolean bir ifade ile yapılabilir.
While döngüsünde yineleme, belirlenen koşulun sağlanmasına kadar devam edecektir. Yineleme
kontrolu çevrimin başında yapılır. Kontol ifadesinin sağlanmaması halinde, döngü içerisinde tekrarlanması istenen kod parçacığı hiç çalışmayabilir.
Örnek uygulama 2.1:
1 int sayac=0;
2
while (sayac++ < 5) {
3
system.out.println(“Merhaba Dünya”)
4}
Uygulama 2.1’ i incelediğimizde, ilk satırda, sayac adlı bir değişken tanımlanarak 0 değeri atanmıştır. Kontrol ifadesi, sayac++ ifadesiyle artırılan sayac değeri 5’ten küçük olduğu sürece “Merhaba Dünya” ifadesi yazdırılacaktır. Bu örnekte “Merhaba Dünya” ifadesi 5 kez yazılacaktır.
24
Bölüm 2
do Döngüsü
Genel yapısı,
do {
Tekrarlanan_Ifade (ler) ;
} while (boolean_kontol_ifadesi)
şeklindedir.
do döngüsü işleyiş biçimi olarak while döngüsüne benzer. Benzer şekilde bu yapıda da boolean
bir koşul ile döngünün yinelenmesi kontrol edilmektedir. do döngüsünün en önemli farkı, kontol
ifadesi başta değil sonda yapıldığından tekrarlanan ifade(ler) en azından bir kere işlenecektir.
for Döngüsü
Birçok programlama dilindeki temel gereksinimlerden biri olan, bir değişkenin belirli bir aralıkta
artırılması ile kurulan döngü yapılarının en çok kullanılanı for döngüsüdür.
Genel yapısı;
for(ifade; booelan_kontrol_ifadesi ; deyim) {
tekrarlanan_ifade(ler)
}
şeklindedir.
ifade olarak adlandırılan kod, sıra döngünün işlenmesine geldiğinde ilk olarak çalışan ifadedir.
Henüz döngü içerisindeki kod parçacığı çalışmaya başlamadan bir defaya mahsus olarak çalışacak, sonraki iterasyonlarda bu ifade çalışmayacaktır. Çoğunlukla döngüde kullanılacak değişkenin başlangıç değer atamasında kullanılır.
boolean_Kontrol_ifadesi doğru değerini verdiği sürece döngünün yinelenmesini sağlayan kontrol ifadesidir. while döngüsünde olduğu gibi koşulun sağlanmaması durumunda for döngüsü
de hiç çalışmayabilir.
deyim ise döngü bloğunun sonunda çalışır. Çoğunlukla kullanılan değişkenin arttırımı bu bölümde yazılan kod ile sağlanır.
Örnek Uygulama 2.2:
1For(int x=0; x < 10; x++) {
2
System.out.println(“Değer=” + x );
3}
Uygulama 2.2’de, döngüde kullanılan sayısal bir x değişkeni ilk ifadede tanımlanmış ve 0 değer
ataması yapılmış, deyim bölümünde ise arttırımı gerçekleşmiştir. Kontrol ifadesi x değişkeninin
10’ dan küçük olduğu tüm değerler için doğrulanacak ve döngü aşağıdaki sonucu üretecektir:
Değer=0
Değer=1
.....
Değer=8
Değer=9
Döngüler
for döngülerinde genellikle döngünün sayılması için kullanılan bir değişken ihtiyacı oldduğundan, ifade bölümünde değişken tanımlamasına ve değer atamasına izin verilmektedir. Burada tanımlanan değişken, sadece for döngüsü içinde geçerlidir. Böylece diğer kısımlarda tanımlanan
değişkenler ile çakışma ihtimali engellenmektedir.
Döngü bloğu (scope) içerisinde kullanılacak başka değişkenler de yine ifade olarak adlandırılan
bölümde tanımlanabilir. Bu işlem Örnek Uygulama 2.3’de belirtildiği gibi, tanımlanacak değişkenler arasına virgül konularak yapılır.
Örnek Uygulama 2.3:
1int j,k;
2For(j = 3, k = 6; j + k < 20 ; j++, k +=2 ) {
3
System.out.println(“ j değeri=” + j +” k değeri= “ + k);
4}
break ve continue Deyimleri
break ve continue deyimleri Java’da da C#’ ta olduğu gibi kullanılır.
Döngü yapıları içerisinde zaman zaman kod bloğunun işlenmesi ile ilgili müdahale ihtiyaçları ortaya çıkabilir. Belirli bir noktada döngüden çıkmak ya da o anda işlenen çevrimin sonlandırılması
istenebilir. Bu ihtiyaçlar break ve continue deyimleri ile sağlanır.
break deyimi, kod bloğunda kullanıldığı yerde döngünün tamamen sonlandırılmasını sağlar. Ancak dikkat edilmesi gereken en önemli nokta, içiçe (nested) yapılar kullanıldığında break sadece
bulunduğu döngü bloğunun sonlandırılmasını sağlar, bir üst döngü işlenmeye devam edecektir.
25
3
Niteleyiciler
(Modifiers)
3 Niteleyiciler (Modifiers)
• Access Modifiers (Erişim Niteleyicileri)
• Niteleyicilerde Metod Ezme (Access
Modifiers Overriding)
• Diğer Niteleyiciler
Niteleyiciler (Modifiers)
Niteleyiciler derleyiciye, kod bloğu içinde oluşturulan sınıf ve sınıf elemanları ile ilgili bilgi sağlayan anahtar kelimeler grubudur.
En sık kullanılan niteleyiciler erişim niteleyicileridir. Bunlar;

public

protected

private
Erişim niteleyicileri dışında belirli bir biçimde kategorize edilemeyen niteleyiciler de bulunmaktadır. Bunlar ise;

final

abstract

static

transient

synchoronized

volatile
Tanımlama sırasında bir niteleyici ile belirlenmeyen sınıf elemanları default olarak belirlenir. Default kod içerisinde kullanılan bir anahtar kelime olmayıp, bir niteleyici saptanmamasını ortadan
kaldırmak için otomatik olarak atanır.
Access Modifiers (Erişim Niteleyicileri)
Erişim niteleyicileri olarak adlandırılan niteleyiciler, sınıf ve sınıf elemanlarının (değişken, method)
erişim seviyeleri ile ilgili kısıtlama sağlar.
Sınıf, değişken ya da metodların tanımlamalarında kullanılan bu anahtar kelimelerle erişim kısıtlamaları belirlenerek oluşturulan kodun güvenliği artırılır.
Bazı istisnalar dışında erişim niteleyicileri tarafından kontrol edilebilen değişkenler sınıf seviyesi
değişkenlerdir. Bir sınıfın içerisinde tanımlanan değişkenler erişim niteleyicileri ile belirlenmemiş
olabilir. Bir metod değişkeni sadece o metodun içerisinde kullanılır.
public
Bir Java programında public olarak tanımlanan bir sınıf, değişken ya da metod herhangi bir kısıtlama olmaksızın kullanılabilir. Bir uygulamanın main() metodu, tüm Java runtime ortamlarından
çağırılabilmesi için public olarak tanımlanır.
Üst sınıflarda (top-level class) kullanılabilen tek erişim niteleyicisi public’tir. Üst sınıflarda private ya da protected tanımlaması yapılmamaktadır.
private
private olarak tanımlanan değişken ya da metodlar, sadece bulunduğu sınıf içinde kullanılabilir. Tanımlandığı sınıf dışından erişimi mümkün değildir.
protected
Sadece değişken ve metodlar protected olarak tanımlanabilir. protected sınıf elemanları bulundukları paket (package) içerisinde erişilebilir durumdadır. Bu özelliğiyle default yapısında benzemekle beraber, yer aldığı sınıfın alt sınıfları (sub classes) tarafından da erişilebilir durumdadır.
protected olarak tanımlanan sınıf elemanı, bulunduğu sınıfın inherit edildiği bir başka package
içerisinden de erişilebilir durumdadır.
30
Bölüm 3
Niteleyicilerde Metod Ezme (Access Modifiers Overriding)
Niteleyici olarak adlandırılan sınıf elemanlarında overriding aşağıda belirtilen biçimlerde gerçekleşir.
Geçerli Overriding
Şekil 1:
private
default
protected
public

private olarak tanımlanan bir metod; private, default, protected ve public metodlar tarafından override edilebilir.

Default bir metod; default, protected ve public metodlar tarafından override edilebilir.

protected bir metod; protected ve public metodlar tarafından override edilebilir.

public bir metod ise sadece public bir metod tarafından override edilebilir.
Geçersiz Overriding
Şekil 2:
public
protected
default
private

Default bir metod; private bir metod tarafından override edilemez.

protected olarak tanımlanan bir metod; default ve private metodlar tarafından override
edilemez.

public bir metod ise; protected, default ve private metodlar tarafından override edilemez.
Diğer Niteleyiciler
Java’da kullanılan diğer niteleyicilerin tanımlanmasında sıra önem taşımaz. Örneğin public
final tanımlaması ile final public tanımlaması birbirinden farklı değildir. Yine ptotected
static ile static protected tanımlamaları aynı şekilde geçerli olacaktır.
final
final niteleyicisi, sınıf, metod ve değişkenlere uygulanmaktadır. final olarak belirlenen bir
sınıf elemanı değiştirilemez.
Örneğin,
class SubMath extends java.lang.Math { }
ifadesi derlendiğinde, “Can’t subclass final classes.” hatası verecektir.
Dikkat edilmesi gereken önemli noktalardan biri, final bir değişken bir nesneye refere edildiğinde, değiştirilemeyen nesnenin instance’ı (örnek) değil, referans tipli değişkendir. Bir başka deyişle; final bir referans nesne değişkeni değiştirilemez ancak yaratılan instance bu kısıtlanmadan
etkilenmez. Final niteleyicisinin C#’taki karşılığı sealed anahtar kelimesidir.
Niteleyiciler (Modifiers)
abstract
abstract niteleyicisi sınıf ve metodlara uygulanmaktadır. abstract,. Microsoft .NET platformu üzerinde kullanılan Visual Basic .NET dilinde abstract bir sınıf oluşturmak için kullanılan
anahtar kelime MustInherit’tir. Buradan anlayacağınız gibi, abstract bir sınıftan mutlaka
türetme yapılmalıdır ve türetilen sınıf kullanılmalıdır.
Eğer bir sınıf birden fazla abstract metoda sahipse, derleyici sınıfın abstract olarak tanımlanmasını zorlar. Bu durum kullanılabilirliği artırır. Sınıfı kullanırken, türetilen sınıf
kullanılması gerektiğini ya da örneklenebileceğinin belirlenmesi için bakılması gereken yer sınıfın
tanımlamasıdır.
Aşağıda belirtilen durumlardan en az birisi gerçeklendiğinde, derleyici bir sınıfın abstract olarak
tanımlanmasını zorlayacaktır.

Sınıf birden çok abstract metoda sahipse

Sınıf implementasyon sağlamayan bir veya birden çok abstract metod inherit ediyorsa

Sınıf bir arayüz (interface) implemente etmek üzere tanımlandığı halde, interface’in tüm metodları için implementasyon sağlamıyorsa
static
static niteleyicisi değişkenler, metodlar hatta bir metodun parçası olmayan kod blokları için
kullanılabilir. static olarak belirlenen sınıf elemanları bir sınıfla bağlantılı olmaktan çok sınıfa
ait olarak düşünülebilir.
static olarak belirlenmiş bir değişkenin değeri, ne kadar instance (örnek) türetilmiş olursa olsun
değerini koruyarak sabit kalacaktır.
static bir değişkeni refere etmenin iki yolu vardır:

Sınıfın instance’ına referans verme yolu ile.

Sınıf adı ile.
Metodlar da static olarak tanımlanabilir. Sınıfın static verilerine ulaşabildikleri ve sınıfın
diğer static metodlarını çağırabildikleri halde, static metodlar sınıflarının non-static (statik
olmayan) elemanlarını kullanamazlar.
Non-static metodlar this adlı örtülü (implicit) bir değişkene sahiptir. Non-static metodlarda, hangi
nesnenin ya da metodun olduğunu belirtmeden bir değişken veya metod çağırılabilir.
Örnek Uygulama 3.1:
1class Xyz
2{
3
int ix;
4
void f1() {
5
ix++;
6 }
7}
Örnek Uygulama 3.1’de tanımlanan ix değişkeni, hangi nesne ya da metoda ait olduğu belirtilmeden ix++ ifadesi ile artırılmaktadır. Derleyici varsayılan olarak bu ifadeyi this.ix++ olarak
algılar ve doğru bir biçimde işler.
static metodlarda ise this yapısı bulunmamaktadır. static bir metod içerisinden, bir başka
metod ulaşılmak ya da çağırılmak istendiğinde ”Undefined variable:this” hatası verecektir.
31
32
Bölüm 3
static bir metod, non-static bir değişkene ulaşmak istediğinde hangi sınıfın değişkeni olduğunu
ya da metodu çalıştıran sınıfın hangisi olduğunu belirterek çağırmak zorundadır.
static bir metod non-static olarak override edilemez. Bu durumda “Static methods can’t be
overriden” hata mesajı verecektir.
transient
transient niteleyicisi sadece değişkenler için kullanılmaktadır. transient bir değişken kendi
objesinin sürekli bir parçası olarak tutulmaz.
synchronized
synchronized değişkenler multithread programlarda, kritik kodlara erişimi kontrol etmek
amacıyla kullanılır. Multithreading daha sonraki bölümlerde detaylı olarak incelenecektir.
volatile
volatile olarak belirlenen değişkenler asenkron olarak değiştirilebilen değişkenlerdir. volatile değişkenler çok işlemcili ortamların konusudur.
Niteleyiciler ile ilgili özeti aşağıdaki tabloda bulabilirsiniz.
Şekil 3:
Niteleyici
Sınıf
Değişken
Metod
Constructor
public




protected
–



(Default)*




private
–



final



–
abstract

–

–
static
–


–
transient
–

–
–
volatile
–

–
–
synchronized
–
–

–
* default bir niteleyici değil, niteleyici belirlenmediğinde varsayılan olarak kullanılan anahtar sözcüktür.
4
Casting ve
Conversion
4 Casting ve Conversion
• Basit Tiplerde Conversion
• Referans Tiplerde Conversion
Casting ve Conversion
Java’ da, C# ve tüm programlama dillerinde olduğu gibi kullanılan her değişkenin bir tipi vardır.
Bunlar int, long ve double gibi basit (primitive) değişkenler olduğu gibi, sınıf değişkenleri (Vector, Graphics vb) ya da arayüzler (LayoutManager ve Runnable vb) olabilir.
Bu bölümde, veri tipleri arasındaki dönüşümleri ele alacağım.
Veriler gerek açıkça (explicitly) ya da örtülü (implicitly) olarak dönüştürülebilir. Bir başka deyişle
kendi bilgi ve isteğimiz dahilinde ya da derleyici tarafından otomatik olarak yapılan veri tipi dönüşümleri mümkündür.
Açıkça gerçekleştirilen veri tipi dönüşümleri casting olarak adlandırılır. Bu durumda kodlama esnasında kendi isteğimizle bir değişkenin tipini değiştiririz.
Örnek Uygulama 4.1:
1ix = (int) mylix;
Örnek Uygulama 4.1’de, mylix değişkeni, int olarak ix değişkenine casting yapılarak atanmaktadır.
Örtülü olarak gerçekleşen veri tipi dönüşümleri ise, değişken atamaları sırasında derleyici tarafından otomatik olarak yapılmaktadır. Açık olmayan, örtülü dönüşümler conversion olarak adlandırılır.
Örnek Uygulama 4.2:
1int x, y;
2double d;
3x = 3; 4y = 5;
5d = x + y;
Örnek Uygulama 4.2’de double değişkenine atanan tam sayı değerlerin toplamı 8.000000... değerini alacaktır. Bu durumda gerçekleştirilen değişken tipi dönüşümü derleyici tarafından otomatik
olarak gerçekleştirilecektir.
Java programlama dilinde basit tipler ve referans tipleri olmak üzere iki veri tipi kategorisi bulunmaktadır.
Basit tipler olarak adlandırılan veri tipleri; boolean, char, byte, short, int, long, float,
double’dır. Referans tipleri ise; JDK tarafından sağlanan birçok sınıf, arayüzün yanısıra, Java
geliştiricileri tarafından geliştirilen sınıflardır.
Basit tipler ve referans tipleri olarak anılan tüm veri tipleri arasında, belirli kurallar dahilinde casting ve conversion mümkündür. Bu bağlamda, 4 çeşit veri tipi dönüşümü ortaya çıkmaktadır:

Basit veri tipleri arasında conversion

Basit veri tipleri arasında casting

Referans tipleri arasında conversion

Referans tipleri arasında casting
36
Bölüm 4
Basit Tiplerde Conversion
Basit veri tiplerinin dönüşümünde 3 tip conversion karşımıza çıkar, bunlar:

Atama

Metod çağırma

Aritmetik yükseltme (arithmetic promotion)
Basit Tiplerde Conversion: Atama
Atama dönüşümü, bir değişkene orijinal değerinden farklı bir değer ataması yapıldığında gerçekleşir.
Örnek Uygulama 4.3:
1int i;
2double d;
3i = 10;
4d = i;
Örnek Uygulama 4.3’de tanımlanan i int, d ise double değişkenlerdir. double bir değişken
tamsayı ifade saklayamayacağından, d = i ataması yapıldığında, d değişkeninin sakladığı değer 10.000000... olacaktır.
Ancak bazı atamalar yukarıda verdiğimiz örnekteki gibi geçerli ifadeler olmayacaktır.
Örnek Uygulama 4.4:
1double d;
2short s;
3d = 1.2345;
4s = d;
Örnek Uygulama 4.4’te yer alan atama, double bir ifadenin short veri tipine atanması şeklindedir. short veri tipi double değerini saklayamaz. Bu kod işlenmeyecek, “Incompitable type for=.”
hatasını verecektir.
Daha büyük değer saklayan değişkenlerden daha küçük değer taşıyan değişkenlere dönüşüm bir
şişedeki sıvıyı küçük bir bardağa taşımaya benzer ancak explicit casting kullanılmalıdır.
Basit tiplerde atamanın genel kuralları şu şeklidedir:

boolean bir veri tipi diğer veri tiplerine çevrilemez.

Genişletme dönüşümü (widening conversion) sözkonusu ise, boolean olmayan (non-boolean) bir veri tipi, boolean olmayan bir veri tipine dönüştürülebilir.

Daraltma dönüşümü (narrowing conversion) sözkonusu ise boolean olmayan bir veri tipi,
boolean olmayan bir veri tipine dönüştürülemez.
Genişletme dönüşümü, daha küçük değerler saklayan veri tiplerinden daha geniş değerler saklayan veri tiplerine gerçekleştirilebilir. Bu durumda herhangi bir veri kaybı olmayacaktır. Genişletme
Dönüşümü;

byte veri tipinden; short, int, long, float veya double veri tiplerine,

short veri tipinden; int, long, float veya double veri tiplerine,

char veri tipinden; int, long, float veya double veri tiplerine,
Casting ve Conversion

int veri tipinden; long, float veya double veri tiplerine,

long veri tipinden; float veya double veri tiplerine,

float veri tipinden; double veri tipine
gerçekleştirilebilir.
Şekil 4.1:
char
int
byte
long
float
double
short
Şekil 1’de belirtilen tüm dönüşümler veri kaybı yaşanmaksızın yapılan dönüşümlerdir. Yine şekilde belirtilen ok yönü dışında gerçekleştirilecek dönüşümler ise daraltma dönüşümü (narrowing
conversion) olarak tanımlanır. Bu tip conversionlarda veri kaybı olabilir. Daraltma dönüşümü ise;

byte veri tipinden; char veri tipine,

short veri tipinden; byte veya char veri tiplerine,

char veri tipinden; byte veya short veri tiplerine,

int veri tipinden; byte, short veya char veri tiplerine,

long veri tipinden; byte, short, char veya int veri tiplerine,

float veri tipinden; byte, short, char, int veya long veri tiplerine,

double veri tipinden; byte, short, char, int, long veya float veri tiplerine
gerçekleştirilebilir.
Java programlama dilinde ondalıklı sayısal değerler double, ondalıksız sayısal ifadeler integer veri tipindedir. Normal koşullarda, integer ve double değerlerin daha küçük değerler
tutan değişkenlere atanmasının derleyici hatasına sebep olacağını düşünebiliriz. Ancak Java bu
durumları kendi içinde esneterek ve atamayı hatasız olarak gerçekleştirir.
Örnek Uygulama 4.5:
1float f = 2.345;
2byte b = 3;
3short s = 5;
4char c = 7;
Örnek Uygulama 4.5’te belirtilen atamalar hatasız olarak gerçekleşecektir. Örnek Uygulama
4.6’de belirtilen kodun ikinci satırı ise sayısal ifade ataması yapılmadığından derlenmeyecektir.
Örnek Uygulama 4.6:
1int i = 15;
2byte b = i;
37
38
Bölüm 4
Basit Tiplerde Conversion: Metod Çağırma
Metod Çağırma dönüşümü, belirli bir veri tipinde argüman bekleyen bir metoda, farklı bir veri tipinde argüman sağlandığında derleyicinin otomatik olarak gerçekleştirdiği dönüşümdür.
Örnek Uygulama 4.7:
1float f;
2double d;
3f = 2.34567f;
4d = Math.cos(f);
Örnek Uygulama 4.7’de belirtilen Math sınıfına ait cos() metodu, veri tipi olarak double bir
argüman beklemektedir. f değişkeninin float değeri cos() metodunda işlenmeden önce otomatik olarak double veri tipine dönüştürülecektir.
Metod çağırma dönüşümlerinde de atama dönüşümlerini belirleyen kurallar geçerlidir. Derleyici
zamanında (compile time) genişletme dönüşümüne izin verilirken, daraltma dönüşümüne izin
verilmez.
Basit Tiplerde Conversion: Aritmetik Yükseltme
Aritmetik yükseltme, aritmetik ifadeler kullanılarak işlem yapıldığında gerçekleşen dönüşüm tipidir.
Örnek Uygulama 4.8:
1short s = 5;
2int i = 8;
3float f = 13.2f;
4double d = 13.2;
5if ( s – i <= f * d)
6
system.out.println( “İlk işlem küçük veya eşit”;
7else
8
system.out.println( “İlk işlem küçük veya eşit değil”;
Örnek Uygulama 4.8, if bloğunun içinde aritmetik ifadeler ile işlenen değişkenler farklı veri tiplerindedir. Derleyici, aritmetik işlemleri anlamlı bir biçimde gerçekleştirmek için gerekli dönüşümleri
otomatik olarak gerçekleştirecektir. Bu dönüşümlerin tamamı daha önce belirttiğimiz genişletme
dönüşümü olacaktır.
Aritmetik yükseltme dönüşümü kuralları tekli operatörler (unary operators) ve ikili operatörler (binary operators) için farklılaşmaktadır. Tekli operatörler tek bir işlenen (operand) üzerinde işlem
yaparken, ikili operatörler iki işlenen üzerinde işlem yapmaktadır.
Şekil 4.2:
Tekli
operators
Binary
operators
+
-
++
--
+
-
*
/
&
^
|
~
%
>>
>>>
<<
Casting ve Conversion
Tekli operatörler için uygulanan dönüşüm kuralları aşağıdaki gibidir;

Eğer kullanılan işlenenin veri tipi byte, short ya da char ise; int veri tipine dönüştürülür.
(Eğer kullanılan operatör ++ ya da -- ise dönüşüm yapılmayacaktır)

Yukarıda belirtilen dışındaki veri tiplerinde dönüşüm yapılmaz.

İkili operatörler için uygulanan kurallar ise aşağıdaki şekilde belirlenmiştir.

Eğer işlenenlerden birinin veri tipi double ise, diğer işlenen double veri tipine dönüştürülecektir.

Eğer işlenenlerden birinin veri tipi float ise, diğer işlenen float veri tipine dönüştürülecektir.

Eğer işlenenlerden birinin veri tipi long ise, diğer işlenen long veri tipine dönüştürülecektir.

Yukarıda belirtilen dışındaki veri tiplerinde int veri tipine dönüştürülecektir.
Basit Tiplerde Casting
Şimdiye kadar ele aldığımız dönüşüm tipleri örtülü olarak gerçekleştirilen, Java’nın otomatik olarak gerçekleştirdiği dönüşümlerdi. Bu dönüşümler, açıkça bir kod yazmamızı gerektirmeyen dönüşümlerdir.
Casting ise, Java’ya bir dönüşümü yapmasını söylemektir. Veri tipleri arasındaki dönüşümü belirleyen, yazacağımız kod olacaktır.
Genişletme dönüşümü olarak belirttiğimiz dönüşümlerde casting’e ihtiyaç duyulmamakta, derleyici otomatik olarak yapmaktadır. Casting daha çok daraltma dönüşümü olarak bilinen dönüşümlerde kullanılmaktadır. Bu dönüşümlerde veride kayıp riski bulunduğundan, derleyici otomatik olarak
yapmamakta, riskin alınarak dönüşümün sağlanması gerektiği yazılacak kod ile belirtilmelidir.
Örnek Uygulama 4.9:
1short s = 362;
2byte b = s;
3system.out.println(“s = ” + s + “, b = ” + b )
Örnek Uygulama 4.9’da belirtilen ifade derlendiğinde, 2. satırda derleyici hatası verecektir. Çünkü
short veri tipinden daha dar bir veri tipi olan byte veri tipine atama yapılmak istenmektedir. Bu
dönüşüm Şekil 4.3’ te belirtilmiştir.
Şekil 4.3:
0
0
0
0
0
0
0
1
0
1
1
0
1
0
1
0
b = (byte)s
Bu durumda derleyici açıkça dönüşüm yapılması gerektiğini bildiren; Explicit cast needed to convert short to byte uyarısı verecektir. Örtülü casting yaparsak aşağıdaki durum oluşacak ve veri
kaybı sözkonusu olacaktır.
39
Bölüm 4
Örnek Uygulama 4.10:
1short s = 362;
2byte b = (byte)s;
3system.out.println(“b = ” + b )
b = 106 olarak yazılacaktır.
Basit veri tiplerinin casting yapılmasında aşağıdaki kurallar geçerlidir.

Boolean olmayan herhangi bir veri tipi, boolean olmayan herhangi bir veri tipine dönüştürülebilir.

Boolean bir veri tipi herhangi bir veri tipine, herhangi bir veri tipi boolean veri tipine dönüştürülemez.
Referans Tiplerde Conversion
Referans tipli değişkenleri de basit veri tipleri gibi atama, metod çağırma ve casting ile dönüştürülebilmektedir. Ancak eski ve yeni tipler arasındaki dönüşümlerde daha çok kombinasyon olduğundan daha karmaşıktır.
Referans tiplerinde conversion da basit tiplerde conversion gibi derleyici zamanında gerçekleşmektedir. Daha sonra belirteceğimiz üzere object casting için ise bu geçerli değildir.
Referans Tiplerde Conversion: Atama
Referans tiplerde atama, bir nesne referans değerini farklı bir veri tipindeki değişkene atadığımızda gerçekleşir. Genel notasyon olarak aşağıdaki biçimde uygulanmaktadır:
EskiTip x = new EskiTip();
YeniTip y = x;
Referans tiplerde conversion’da, eskitip ve yenitip üyeler (member) arasındaki dönüşüm kombinasyonları Şekil 4.4’te belirtilmiştir.
Şekil 4.4:
Eski Tip
Yeni Tip
40
Sınıf (Class)
Arayüz (Interface)
Dizi (Array)
Sınıf
Eskitip, Yenitip’in
altsınıfı olmalıdır.
Yenitip nesne
olmalıdır.
Yenitip nesne olmalıdır.
Arayüz
(Interface)
Eskitip, yenitip’in
arayüzünü
implemente etmelidir.
Eskitip, Yenitip’in
alt-arayüz’ü
(subinterface)
olmalıdır.
Yenitip cloneable ya da
serializable olmalıdır.
Dizi (Array)
Derleyici hatası
oluşacaktır.
Derleyici hatası
oluşacaktır.
Eskitip, yenitip’in dizisine
dönüştürülebilecek bir dizi
olmalıdır.
Tüm dönüşüm kurallarına uygulanmasa da, genel bir bakış açısı olarak, izin verilen referans tipi
dönüşümleri, miras hiyerarşisinde (inheritance hierarchy) yukarı doğru olmaktadır. Yani, eskitip,
yenitip’ten miraslanmalıdır.
Casting ve Conversion
Genel kuralları aşağıdaki şekilde belirlenebilir:

Bir arayüz sadece yine bir arayüze ya da nesneye dönüştürülebilir. Eğer yenitip bir arayüz ise,
eskitip’in alt-arayüzü olmalıdır.

Bir sınıf yine bir sınıfa ya da arayüze dönüştürülebilir. Bir sınıfa dönüştürüldüğünde, yenitip
eskitip’in alt-sınıfı olmalıdır. Bir arayüze dönüştürüldüğünde, eski sınıf arayüzü implemente
etmelidir.

Bir dizi, sınıf nesnesine ya da cloneable veya serializable bir arayüze ya da diziye dönüştürülebilir. Sadece nesne referans tipinin dizisi bir diziye dönüştürülebilir ve eski eleman tipi yeni
eleman tipine çevrilebilir olmalıdır.
Referans Tiplerde Csonversion: Metod Çağırma
Genel olarak referans tiplerde atama dönüşümünde tanımlanan kurallar bu dönüşüm tipinde de
geçerlidir. Bir süpersınıfa dönüşüme izin verilirken, altsınıfa dönüşüme izin verilmez.
Genel kuralları aşağıda belirtilmiştir.

Bir arayüz sadece yine bir arayüze ya da nesneye dönüştürülebilir. Eğer yenitip bir arayüz ise,
eskitip’in alt-arayüzü olmalıdır.

Bir sınıf yine bir sınıfa ya da arayüze dönüştürülebilir. Bir sınıfa dönüştürüldüğünde, yenitip
eskitipin alt-sınıfı olmalıdır. Bir arayüze dönüştürüldüğünde, eski sınıf arayüzü implemente
etmelidir.

Bir dizi, sınıf nesnesine ya da klonlanabilir veya serileştirilebilir bir arayüze ya da diziye dönüştürülebilir. Sadece referans tipinin dizisi bir diziye dönüştürülebilir ve eski eleman tipi yeni
eleman tipine çevrilebilir olmalıdır.
Referans Tiplerin Çevrimi
Referans tiplerde çevrim daha önce ele aldığımız basit tiplerin çevrimine benzer. Atama ve metod
çağırma yöntemlerinde izin verilen tüm açık çevrimler (explicit casting) bu yöntemde de kullanılabilmektedir.
Referans tiplerin çevriminde derleyici zamanında olduğu gibi çalışma zamanında uygulanan kurallar da bulunmaktadır. Bunu sebebi, referans tipli değişkenlere ilişkin bazı bilgilerin derleyici
zamanında henüz bilinmemesidir.
Referans tiplerin çevrimi için derleyici zamanı kuralları Şekil 4.5’ te belirtilmiştir.
Şekil 4.5:
Yeni Tip
Eski Tip
Miras verebilir
sınıf (non-final
class)
Miras veremeyen
sınıf (final - sealed
class)
Arayüz
(interface)
Dizi (array)
Miras verebilir
sınıf (nonfinal class)
Eskitip, yenitip’i
genişletmelidir
Eskitip, yenitip’i
genişletmelidir
Herzaman
geçerlidir
Eskitip nesne
olmalıdır
Miras
veremeyen
sınıf (final sealed class)
Eskitip, yenitip’i
genişletmelidir
Eskitip ve Yenitip aynı
sınıf olmalıdır.
Yenitip arayüzü
implemente
etmelidir
Derleyici hatası
oluşacaktır
Arayüz
(interface)
Herzaman
geçerlidir
Eskitip, Yenitip’in
arayüzününü
implemente etmelidir
Herzaman
geçerlidir
Derleyici hatası
oluşacaktır
Dizi (array)
Yenitip nesne
olmalıdır
Derleyici hatası
oluşacaktır
Derleyici hatası
oluşacaktır
Eskitip, yenitip’in
dizisine
dönüştürülebilecek
bir dizi olmalıdır
41
42
Bölüm 4
Eskitip ve Yenitip arasındaki dönüşümlerde derleyici zamanında geçerli kurallar aşağıda belirtilmiştir.

Eskitip ve Yenitip dönüşümlerinde her ikisinin de sınıf olması halinde, bir sınıf diğerinin altsınıfı olmalıdır.

Eskitip ve Yenitip’lerin her ikisi de dizi ise, her iki dizi de referans tipi barındırmalı ve eskitipin
bir elemanının yenitipin bir elemanına çevrimi geçerli olmalıdır.

Bir arayüz ile Miras verebilir sınıf (non-final class) arasında herzaman çevrim yapılabilir.
Çalışma zamanında uygulanan kurallar ise;

Eğer Yenitip bir sınıf ise, dönüştürülen ifadenin sınıfı ya Yenitip olmalıdır, ya da Yenitip’ten
miras alınmalıdır.

Eğer Yenitip bir arayüz ise, dönüştürülen ifadenin sınıfı Yenitip’i implemente etmelidir.
olarak belirlenebilir.
5
Yapısal
Programlama
5 Yapısal Programlama
• Yapısal Programlama Nedir?
• Nesne Yönelimli Programlamanın Temel
Kavramları
Yapısal Programlama
Yapısal Programlama Nedir?
Yapısal programlamada uygulamanın akışı fonksiyonlara bölünerek her bir fonksiyonun belirli
bir işi gerçekleştirmesi sağlanır. Yazılımın amacı gerçek dünyadaki iş akışlarının bilgisayar ortamında yürütülmesi olduğu için, modellenmesi istenen kavramlar fonksiyonlar ve değişkenler kullanılarak modellenmeye çalışılmaktadır. Gerçek dünyada fonksiyon ve değişken gibi kavramlar
yerine nesnelerin bulunmasından dolayı modelleme tam anlamıyla gerçekleştirilememektedir.
Nesne Yönelimli Programlamanin Temel Bileşenleri
Sınıf ve Nesne
Modellememiz gereken iş akışlarını yazılım ortamında temsil etmek için kullandığımız temel bileşen sınıflardır. Sınıf sadece bir modeldir, uygulama çalışırken fiziksel olarak oluşturulmayan, kod
üzerinde kalan soyut bir yapıdır. Nesne ise uygulamanın çalışması aşamasında fiziksel olarak
bilgisayarın belleğinde oluşan ve başka nesnelerle iletişim kurarak iş akışlarının gerçekleşmesini
sağlayan bir bileşendir. C# .Net dilinde olduğu gibi Java dilinde de yeni bir nesne oluşturmak için
new anahtar kelimesi kullanılır, new anahtar kelimesini kullandığımız her kod parçası uygulamanın çalışması sırasında bellek üzerinde yeni bir nesne oluşturur.
Nesne yönelimli programlamaya yeni başlayan yazılım geliştiriciler sınıf ve nesne kavramları arasındaki farkı anlamakta zorluk çekebilir, bunun sebebi uygulamanın çalışma aşamasında sınıf
diye bir varlığın olmaması gibi gerçek hayatta da sınıf diye bir varlığın bulunmamasıdır.
Nitelikler (Attributes)
Bir sınıfın içinde bulunan ve o sınıftan oluşturulacak olan nesnelerin özelliklerini tutan yapılardır. Sınıfların kodlanması sırasında değişkenler şeklinde oluşturulurlar ve sınıftan nesne örneği
oluşturulduğu anda bellek üzerinde oluşurlar. Gerçek hayattaki nesnelerin çeşitli niteliklere sahip
olması gibi yazılım ortamında oluşan nesneler de çeşitli niteliklere sahiptir.
Örnek Uygulama 5.1:
1 public class Nokta
2 {
3 private int x;
4 private int y;
5 }
Örnekte, nokta kavramının yazılım ortamındaki modeli olan Nokta sınıfı oluşturulmuştur ve bu
sınıftan oluşturulacak olan nesnelerin x ve y koordinatlarını temsil etmek için x ve y nitelikleri olacaktır. x ve y nitelikleri sınıfın içinde yer alsa da değerlerini Nokta sınıfından bir nesne oluştuktan
sonra ve oluşan nesne üzerinden alacaktır.
Davranışlar
Yazılım ortamında bellek üzerinde oluşan nesnelerin sergileyeceği davranışlar da nitelikler gibi
bu nesnenin modeli olan sınıf üzerinde bulunur. Davranışlar, sınıfların kodlanması sırasında metodlar şeklinde oluşturulur ve bir sınıfın içinde bulunan metodlar bu sınıftan oluşturulacak olan bütün nesnelerin ortak davranışlarını belirler. Gerçek hayattaki nesnelerin çeşitli davranışlara sahip
olması gibi yazılım ortamındaki nesnelerin de çeşitli davranışları bulunur. Her bir nesnenin kendi
davranışını modelleyen metodlara örnek metodu(instance method) adı verilir.
Örnek Uygulama 5.2:
1 public class Nokta
2 {
46
Bölüm 5
3 private int x;
4 private int y;
5 public void YerDegistir(int yeniX, int yeniY)
6 {
7
x = yeniX;
8
y = yeniY;
9}
10}
Örnek Uygulama 5.1’de oluşturduğumuz Nokta sınıfımıza YerDegistir davranışını ekledik.
Bu metod sayesinde Nokta sınıfından oluşan bütün nesnelere iki boyutlu uzayda yer değiştirme
kabiliyeti vermiş olduk. YerDegistir metodumuz iki tane tam sayı cinsinden parametre alır ve
nesnemizin x ve y koordinat değerlerini yeni koordinat değerleriyle değiştirir.
Nesnelere ait metodlar parametre olarak int, string gibi yerleşik tiplerden değişkenler alabilecekleri gibi kendi sınıfı veya başka bir sınıf cinsinden nesneler de alabilir.
Örnek Uygulama 5.3:
1 public class Nokta
2 {
3 private int x;
4 private int y;
5 public void YerDegistir(int yeniX, int yeniY)
6 {
7
x = yeniX;
8
y = yeniY;
9}
10
public double UzaklikHesapla(Nokta ikinciNokta)
11
{
12
double uzaklik = Math.sqrt(Math.pow(x - ikinciNokta.
x, 2) + Math.pow(y - ikinciNokta.y, 2));
13
14
}
return uzaklik;
15}
Herhangi bir nokta nesnesinin başka bir nokta nesnesi ile arasında olan uzaklığı bulmak için bir
metod yazdık. UzaklikHesapla metodu parametre olarak bir Nokta nesnesi alıyor ve üzerinde
çalışmakta olduğu nesneyle parametreden gelen nesne arasındaki uzaklığı double cinsinden
hesaplayarak döndürüyor. Kare alma ve karekök hesaplama işlemleri için yerleşik Java sınflarından biri olan Math sınıfını kullandık. Metod içinde kullanılan x ve y, davranışın sahibi olan
nesneye ait x ve y değerleridir. Parametre olarak gelen ikinci nesneye ait x ve y nitelikleri ise
ikinciNokta.x ve ikinciNokta.y şeklinde kullanılmıştır.
Bir sınıfın içinde aynı isimli birden fazla metod tanımlanabilir. Bu durumda tek şart tanımlanacak
olan metodların parametre sayılarının veya parametre tiplerinin farklı olmasıdır, aynı tipten aynı
sayıda parametre içeren aynı isimli birden fazla metod tanımlanırsa derleme hatası alırız. Bu işleme metodların aşırı yüklenmesi (overloading) adı verilir. Bu mekanizma C# dilindekine benzer
bir mantıkla gerçekleştirilebilir.
Yapısal Programlama
Örnek Uygulama 5.4:
1 public class Nokta
2 {
3private int x;
4private int y;
5public void YerDegistir(int yeniX, int yeniY)
6{
7
x = yeniX;
8
y = yeniY;
9}
10
public double UzaklikHesapla(Nokta ikinciNokta)
11
{
12
x, 2)
double uzaklik = Math.sqrt(Math.pow(x - ikinciNokta.
13
return uzaklik;
14
}
+ Math.pow(y - ikinciNokta.y, 2));
15
public double UzaklikHesapla(int ikinciNoktaX, int
ikinciNoktaY)
16
{
17
double uzaklik = Math.sqrt(Math.pow(x ikinciNoktaX, 2)
+ Math.pow(y - ikinciNoktaY, 2));
18
return uzaklik;
19
}
20}
Son durumda, Nokta sınıfımızın içinde aynı işi yapan aynı isimli iki tane metod var. İlk yazdığımız
metod parametre olarak bir Nokta nesnesi ile çalışıyor, ikinci metod ise harici bir noktanın x ve y
koordinat değerlerinin parametre olarak verilmesini bekliyor.
Sınıfların içinde bulunan metodlar yine aynı sınıfın içinde bulunan başka metodları da kullanabilir.
Nokta sınıfında yazdığımız UzaklikHesapla metodları içinde aynı algoritmayı iki kere yazdık.
Bunun yerine UzaklikHesapla metodlarından birinin diğer UzaklikHesapla metodunu kullanarak hesaplama yapmasını aşağıdaki gibi sağlayabiliriz. Böylece gerçeklememiz gereken bir
algoritmayı veya iş mantığını bir kere gerçekleyerek koddan tasarruf ettiğimiz gibi uygulamamızı
olası değişimler için daha uygun hale getiririz.
Örnek Uygulama 5.5:
1 public class Nokta
2 {
3 private int x;
4 private int y;
5 public void YerDegistir(int yeniX, int yeniY)
6 {
7
x = yeniX;
47
48
Bölüm 5
8
9 }
10 y = yeniY;
public double UzaklikHesapla(Nokta ikinciNokta)
11
{
12
13
}
return UzaklikHesapla(ikinciNokta.x, ikinciNokta.y);
14
public double UzaklikHesapla(int ikinciNoktaX, int
ikinciNoktaY)
15
{
16
double uzaklik = Math.sqrt(Math.pow(x ikinciNoktaX, 2)
+ Math.pow(y - ikinciNoktaY, 2));
17
return uzaklik;
18
}
19}
Yapıcı Metod (Constructor)
Uygulama içinde nesnelerin oluşturulması aşamasında otomatik olarak çalışan metodlara kurucu
veya yapıcı metodlar denir. Genelde nesnelerimizin içinde bulunan niteliklere ilk değerler atamak
için kullanılır. Yapıcı metodlarla ilgili sınırlamalar aşağıdaki gibidir:
1� Yapıcı metodlar yeni nesne oluşturulmasını sağlamaz, bir nesnenin oluşma aşamasında çalışır.
2. Yapıcı metodların isimleri sınıfın ismiyle aynı olmak zorundadır.
3� Yapıcı metodların geri dönüş değeri olamaz, geri dönüş değeri olan bir yapıcı metod tanımı
yaparsak derleme hatası alırız.
4. Bir sınıf içinde birden fazla yapıcı metod bulunabilir. Parametre tiplerinin veya sayılarının
farklı olması birden fazla yapıcı metod tanımlanabilmesi için yeterlidir.
5. Java dilinde de .Net ortamında olduğu gibi varsayılan, parametresiz bir yapıcı metod vardır.
Sınıfımızın içinde parametreli veya parametresiz bir tane yapıcı metod oluşturduğumuzda
varsayılan yapıcı metod geçersiz hale gelir.
6. New anahtar kelimesi ile sınıftan nesne oluşturulmasına izin vermek istiyorsak yapıcı metodları public olarak tanımlamamız gerekir. Sınıfın içinde bir tane yapıcı metod varsa ve bu
metodun erişim tipi private ise, bu sınıftan nesne oluşturulamaz.
Örnek Uygulama 5.6:
1 public class Nokta
2 {
3private int x;
4private int y;
5public Nokta()
6{
7
x = 0;
8
y = 0;
9}
10}
Yapısal Programlama
Nokta sınıfımıza parametresiz bir yapıcı metod ekleyerek yeni oluşan her nesnenin x ve y koordinatlarının sıfır değerine sahip olmasını yapıcı metod aracılığıyla sağladık. Sınıfımıza bir tane de
parametreli yapıcı metod ekleyelim.
Örnek Uygulama 5.7:
1 public class Nokta
2 {
3private int x;
4private int y;
5public Nokta()
6{
7
x = 0;
8
y = 0;
9}
10
public Nokta(int x, int y)
11
{
12
this.x = x;
13
this.y = y;
14
}
15}
Son durumda iki tane yapıcı metodumuz oldu. Parametresiz yapıcı metod kullanılarak oluşan
bütün nesnelerin x ve y koordinatları sıfır değerini alıyor, parametreli yapıcı metodumuz ise nesnenin oluşması sırasında noktanın farklı koordinat değerlerine sahip olmasını sağlıyor.
Parametreli yapıcı metodumuzun gövdesinde yer alan this anahtar kelimesi, üzerinde çalışmakta olduğumuz nesneyi temsil eder. Nesne özelinde değerlendirilebilen nitelik ve metodlara this
anahtar kelimesi ile ulaşabiliriz. Daha önceki örneklerde this anahtar kelimesini kullanmamıza
gerek kalmamıştı, çünkü x ve y isimli birer tane değişken bulunuyordu. Son yazdığımız metodda
ise biri parametreden gelen, diğeri nesnenin sahip olduğu niteliği temsil eden iki tane x değişkeni
olduğundan bu değişkenleri biribirinden ayırabilmek için nesneden gelen x değişkeninin başına
this anahtar kelimesini ekliyoruz.
Yapıcı metodun parametrelerinden biri olan x değişkeni ile nesne üzerindeki niteliği temsil eden
x değişkeni arasında hiçbir organik bağ yoktur, farklı isimlere sahip olsalar da uygulama istendiği
şekilde çalışır. Aralarındaki ilişki yapıcı metodumuzun içinde yaptığımız değer ataması ile sınırlıdır. Parametreli yapıcı metodumuz Şekil 5.8’de belirtilen iki şekilde de yazılabilirdi:
Örnek Uygulama 5.8:
1 public Nokta(int yeniX, int yeniY)
2 {
3this.x = yeniX;
4this.y = yeniY;
5 }
6 public Nokta(int yeniX, int yeniY)
7 {
8x = yeniX;
9 10}
y = yeniY;
49
50
Bölüm 5
Nokta sınıfının son halini ve bu sınıftan birkaç tane nesne oluşturan ana programı Şekil 5.9’daki
gibi yazabiliriz:
Örnek Uygulama 5.9:
1 public class Nokta
2 {
3private int x;
4private int y;
5public Nokta()
6{
7
x = 0;
8
y = 0;
9}
10
public Nokta(int x, int y)
11
{
12
this.x = x;
13
this.y = y;
14
}
15
public void YerDegistir(int yeniX, int yeniY)
16
{
17
x = yeniX;
18
y = yeniY;
19
}
20
public double UzaklikHesapla(Nokta ikinciNokta)
21
{
22
23
}
return UzaklikHesapla(ikinciNokta.x, ikinciNokta.y);
24
public double UzaklikHesapla(int ikinciNoktaX, int
ikinciNoktaY)
25
{
26
double uzaklik = Math.sqrt(Math.pow(x ikinciNoktaX, 2)
+ Math.pow(y - ikinciNoktaY, 2));
27
return uzaklik;
28
}
29}
30 public class AnaProgram
31{
32
public static void main(String[] args)
33
{
// Parametresiz yapıcı metodla bir Nokta nesnesi
oluşturuldu
34
Nokta nokta1 = new Nokta();
35
nokta1.YerDegistir(3, 5);
Yapısal Programlama
// Parametreli yapıcı metodla bir Nokta nesnesi oluşturuldu
36
Nokta nokta2 = new Nokta(5, 5);
// nokta1 ve nokta2 nesneleri arasındaki uzaklık nokta1
nesnesi
// üzerinden hesaplandı
37
38
basıldı
double uzaklik = nokta1.UzaklikHesapla(nokta2);
System.out.println(uzaklik); // Ekrana 2.0 değeri
// nokta1 ve nokta2 nesneleri arasındaki uzaklık nokta2
nesnesi
// üzerinden hesaplandı
39
40
basıldı
uzaklik = nokta2.UzaklikHesapla(nokta1);
System.out.println(uzaklik); // Ekrana 2.0 değeri
aldı
// nokta1 nesnesinin yeni koordinatları (4, 6) değerini
41
nokta1.YerDegistir(4, 6);
// nokta1 nesnesinin (5, 7) koordinatlarında bulunan
noktaya uzaklığı
// hesaplandı
42
43
basıldı
44
uzaklik = nokta1.UzaklikHesapla(5, 7);
System.out.println(uzaklik); // Ekrana 1.414 değeri
}
45}
Nesne Yönelimli Programlamanın Temel Kavramları
Kapsülleme (Encapsulation)
Bir nesnenin içinde yer alan niteliklerin ve iş mantığının nesneyi kullanan kişiler tarafından görülmesinin veya değiştirilmesinin engellenmesine kapsülleme denir. Kapsüllemede temel amaç
nesneyi kullanacak kişilerin iş akışıyla ilgili gereksiz detaylarla uğraşmamasını sağlamak ve nesnelerin içinde bulunan hassas verilerin değiştirilmesini engellemektir.
Günlük hayatta düzenli olarak kullandığımız bir mönitör nesnesi üzerinden örnek verelim: Monitörümüzün içinde birçok elektronik devre elemanı olduğunu bilsek de bu devrelerin nasıl çalıştığı
hakkında çoğumuzun bir fikri bulunmamaktadır. Monitörün içinde bulunan elektronik elemanlar
ve bunların çalışma mantıkları son kullanıcıdan soyutlanmış durumdadır. Monitörün dışında yer
alan kılıfın bulunmadığını ve monitör üzerinde herhangi bir işlem yapmak için çeşitli devre elemanlarının değerlerini değiştirmek zorunda kaldığımızı düşünecek olursak bahsettiğimiz gereksiz
karmaşıklığın ne anlama geldiğini daha iyi anlayabiliriz. Bahsedilen durumda monitör gibi basit
bir nesneyi kullanmak için yoğun çaba harcamamız gerekeceği gibi yanlış bir hareketle içerideki
yapılara zarar vermemiz de ihtimal dahilinde olacaktır.
Monitörün kullanıcıyla etkileşim kurmak için düğmelerden oluşan bir iletişim arayüzüne sahip
olması gibi, yazılımsal olarak gerçeklediğimiz nesnelerimizin de kendilerini kullanacak yazılımcılarla aralarında bir iletişim arayüzü bulundurmaları kullanımı kolaylaştıracaktır. Sınıflarımızın
içinde bulunan niteliklerin ve metodların sadece ihtiyaç duyulduğu kadarının kullanıcıya açılması
kapsülleme mantığı çerçevesinde gerçeklenebilir.
Daha önce anlatıldığı gibi nitelikler ve metodların erişimi aşağıdaki gibi kısıtlanabilir:
51
52
Bölüm 5
Şekil 5.1:
Erişim tipi
Anlamı
public
Sınıfın içinden, dışından ve türetilmiş sınıflardan.
protected
Sınıfın ve türetilmiş sınıfların içinden.
private
Sadece sınıfın içinden.
Genel olarak sınıf içindeki bütün niteliklerin private veya protected olarak tanımlanması tavsiye edilmektedir. Sınıfı kullanacak olan yazılımcıların sınıf içinde bulunan niteliklere kendilerine
sağlanan bağlantı noktaları üzerinden erişmesi get ve set metodları yardımıyla sağlanabilir.
Örnek Uygulama 5.10:
1 public class BankaHesabi
2 {
3public int hesapNumarasi;
4public double bakiye;
5public boolean ParaCek(double miktar)
6{
7
if (miktar <= this.bakiye)
8
{
9
this.bakiye -= miktar;
10
11
}
12
else
13
{
14
15
}
16
}
17
public void ParaYatir(double miktar)
18
{
19
20
}
return true;
return false;
this.bakiye += miktar;
21}
22public class AnaProgram
23{
24
public static void main(String[] args)
25
{
26
BankaHesabi hesap = new BankaHesabi();
27
hesap.hesapNumarasi = 12003345;
28
hesap.ParaYatir(1500);
29
hesap.ParaCek(500);
30
31
hesap.bakiye -= 1500;
// iş akışının dışına çıkıldı
}
32}
Kodun açıklaması: BankaHesabi, hesap numarası ve bakiye verilerini tutan basit bir sınıftır. Para çekmek için ParaCek metodunun, para yatirmak içinse ParaYatir metodunun kullanılması öngörülmüştür. BankaHesabi sınıfı içindeki hesapNumarasi ve bakiye niteliklerinin
Yapısal Programlama
public olmasından dolayı, Main metodunda oluşturulan bir BankaHesabi nesnesinin bakiye
değeri ParaCek veya ParaYatir metodları kullanılmadan da değiştirilebilir. Bakiyenin yetersiz
olması durumunda bile istenen miktar hesaptan çekilebilmekte, bu nedenle iş akışının doğru olarak gerçekleştirilmesi Main metodunu yazan kişiye bağlı olmaktadır.
Sınıfın aşağıdaki şekilde tasarlanması banka hesabıyla ilgili iş akışının tamamen BankaHesabi
sınıfı içinde yer almasını sağlamaktadır:
Örnek Uygulama 5.11:
1 public class BankaHesabi
2 {
3private int hesapNumarasi;
4private double bakiye;
5public boolean ParaCek(double miktar)
6{
7
if (miktar <= this.bakiye)
8
{
9
this.bakiye -= miktar;
10
11
}
12
else
13
{
14
15
}
16
}
17
public void ParaYatir(double miktar)
18
{
19
20
}
21
public int getHesapNumarasi()
22
{
23
24
}
25
public void setHesapNumarasi(int hesapNo)
26
{
27
28
}
29
public double getBakiye()
30
{
31
32
}
return true;
return false;
this.bakiye += miktar;
return this.hesapNumarasi;
this.hesapNumarasi = hesapNo;
return this.bakiye;
33}
34public class AnaProgram
35{
36
public static void main(String[] args)
53
54
Bölüm 5
37
{
38
BankaHesabi hesap = new BankaHesabi();
39
hesap.setHesapNumarasi(12003345);
40
hesap.ParaYatir(1500);
41
hesap.ParaCek(500);
42
// hesap.bakiye -= 1500;
43 }
44}
Kodun açıklaması: BankaHesabi sınıfındaki hesapNumarasi ve bakiye niteliklerinin erişim kısıtları private olarak değiştirilmiştir. Böylece bu alanlara dışarıdan erişim engellenmiştir.
hesapNumarasi niteliğinin değeri getHesapNumarasi metodu üzerinden, bakiye niteliğinin
değeri getBakiye metodu üzerinden okunabilmektedir. hesapNumarasi niteliğine setHesapNumarasi metodu aracılığıyla yeni bir değer atanabilmesine rağmen bakiye değeri sadece ParaCek ve ParaYatir metodları kullanılarak değiştirilebilmektedir. Böylece bakiye değişikliği işleminin arkasındaki iş mantığı sadece ilgili metodlar yardımıyla belirlenmekte ve sınıfı kullanacak
olan yazılımcının bu konu üzerinde çalışmasına gerek kalmamaktadır. Ana programdaki yorum
satırı haline getirilmiş olan kod parçası derleme hatası vermektedir. Bu derleme hatasının sebebi
bakiye alanının private olarak tanımlanmış olmasıdır.
.Net Platformu üzerinde bulunan Property kavramının Java Platformunda doğrudan bir karşılığı
bulunmamaktadır. Bunun yerine niteliğin adının başına get veya set sözcüklerinin eklenmesiyle
oluşturulan metodların kullanılması gelenekselleşmiştir.
Kodun Tekrar Kullanımı
Kodun tekrar kullanımı, daha önce yazılmış olan ve belirli bir işlemi gerçekleştiren kod bloklarının
aynı projenin farklı bir yerinde veya başka bir projede kullanılmasıdır. Bu işlem yazılımın gerçeklenmesi aşamasındaki kodlama maliyetlerini düşürdüğü gibi sistemde yapılacak değişikliklerin
de daha düşük maliyetle gerçekleştirilmesini sağlar. Yapısal programlama teknolojilerinde kodun
yeniden kullanımı kavramı bulunsa da, gerçeklenen işlevler fonksiyon bazında olduğundan iki
farklı proje arasında kod aktarımı sınırlı kalır, genelde kodun önemli bir kısmının veya hepsinin
yeniden yazılması gerekir. Nesne yönelimli programlama teknolojilerinde ise temel amaçlardan
biri kodun yeniden kullanımını sağlayarak projelerin zaman ve iş gücü maliyetlerini mümkün
olduğu kadar düşürmektir. Nesne yönelimli yaklaşımda kodun tekrar kullanımı sınıf bazında gerçeklenir ve daha önce oluşturulmuş olan sınıflar aynı proje içinde veya farklı projelerde esnek
olarak kullanılır.
Nesne yönelimli dillerde kodun tekrar kullanımı birkaç farklı şekilde sağlanabilir:
1� Daha önce oluşturulmuş sınıflardan oluşturulan nesneler uygulama içinde kullanılabilir.
2. Daha önce oluşturulmuş sınıflardan oluşturulan nesneler yeni oluşturulan sınıfların içinde bulunabilir ve bir sınıf değişik tiplerde ve sayılarda nesne içerebilir. Bu ilişkiye composition adı
verilir ve genel olarak “sahip olma” (has-a) ilişkisi olarak tanımlanır.
3� Daha önce oluşturulmuş sınıflardan yeni sınıfların türetilmesi ile ile uygulamanın genişletilmesi
sağlanır. Bu kavram kalıtım adını alır ve genel olarak “olma” (is-a) ilişkisi olarak tanımlanır.
Kalıtım
Kalıtım; bir sınıfın daha önce oluşturulmuş başka bir sınıftan türetilmesidir. Kalıtım sayesinde önceden gerçeklenmiş özelliklerin ve davranışların yeniden gerçeklenmesine gerek kalmaz, kodun
tekrar kullanımı sağlanmış olur. İki farklı iş kavramının modellenmesi sırasında aralarında kalıtım
ilişkisi olduğuna karar vermek için türetilecek olan sınıfın, temel sınıfın sahip olduğu bütün özelliklere sahip olduğundan emin olmak gerekir. En basit yaklaşımla, iki farklı kavram arasında olma
(is-a) ilişkisi kurulabiliyorsa iki sınıf arasında kalıtım ilişkisi vardır. Kalıtım ilişkisi uygulamanın
Yapısal Programlama
ihtiyaçlarına göre iki veya daha fazla sınıf arasında olmak üzere tasarlanabilir. .Net Platformunda
olduğu gibi Java Platformunda da çoklu kalıtım desteklenmez, bir sınıf sadece bir sınıftan türetilebilir.
Örnek: Bir şirketteki çalışanları modellemek için bir yazılım tasarladığımızı varsayalım.
İlk aşamada bütün çalışanlarımızı Calisan adlı bir sınıf ile temsil edelim. Bu durumda bütün
çalışan nesnelerimiz aynı sınıftan oluşturulacaği için farklı çalışan tiplerine özel bilgilerin ve davranışların Calisan sınıfından oluşturulan nesnelerde saklanması mümkün olmaz.
Örnek Uygulama 5.12: Çalışan sınıfının ilk hali
1 public class Calisan
2 {
3private String ad;
4private String soyad;
5public Calisan(String ad, String soyad)
6{
7
this.ad = ad;
8
this.soyad = soyad;
9}
10}
Tasarladığımız uygulamayı biraz daha geliştirerek farklı çalışan tiplerini temsil etmek üzere özelleşmiş çalışan sınıfları oluşturabiliriz. private erişim tipine sahip alanların erişim tipini protected olarak değiştirirsek bu niteliklere türetilmiş sınıflardan ulaşılmasını da sağlarız.
Örnek Uygulama 5.13:
1 public class Calisan
2 {
3protected String ad;
4protected String soyad;
5
6public Calisan(String ad, String soyad)
7{
8
this.ad = ad;
9
this.soyad = soyad;
10
}
11}
12public class Muhendis extends Calisan
13{
14
protected String[] projeler;
15
protected String departman;
16
protected int projeSayisi;
17
public Muhendis(String ad, String soyad, String departman)
18
{
19
super(ad, soyad);
20
this.departman = departman;
55
56
Bölüm 5
21
this.projeler = new String[5];
22
this.projeSayisi = 0;
23
}
24
public void ProjeEkle(String proje)
25
{
26
projeler[projeSayisi] = proje;
27
projeSayisi++;
28
}
29}
Calisan sınıfında sadece niteliklerin erişim tipini protected olarak değiştirdik ve yeni eklenen Muhendis sınıfının Calisan sınıfından türemesini “extends” anahtar kelimesi ile sağladık.
“extends” anahtar kelimesi, C# dilindeki “:” operatörünün karşılığıdır. Muhendis sınıfının içinde
bulunan projeler adındaki string dizisi ile belirli bir mühendisin üzerinde çalıştığı projeleri tutuyoruz ve ProjeEkle metodu yardımıyla belirli bir mühendisin projelerine ekleme yapabiliyoruz.
Muhendis sınıfımızın yapıcı metodu ad, soyad ve departman olmak üzere üç tane parametre
alır. Departman parametresi Muhendis sınıfı içindeki departman niteliğine ilk değer vermek için
kullanılırken ad ve soyad parametreleri “super” anahtar kelimesi yardımıyla temel sınıf olan
Calisan sınıfının yapıcı metodunu çalıştırmak için kullanılır. Muhendis sınıfında super(ad,
soyad) komutuyla Calisan sınıfının yapıcı metodunu çağırmazsak derleme hatası alırız. Bunun sebebi türetilmiş sınıflardan nesne oluşturulurken sırasıyla temel ve türetilmiş sınıfların yapıcı
metodlarının çağrılmasıdır. Örnek Uygulama 5.14, temel ve türetilmiş sınıflarda yapıcı metodların
çalışmasını göstermektedir:
Örnek Uygulama 5.14:
1 public class TemelSinif
2 {
3public TemelSinif()
4{
5
System.out.println(“Temel sınıfın yapıcı metodu çalıştı”);
6}
7 }
8 public class TuretilmisSinif extends TemelSinif
9 {
10
public TuretilmisSinif()
11
{
12
çalıştı”);
13
System.out.println(“Türetilmiş sınıfın yapıcı metodu
}
14}
15public class AnaProgram
16{
17
public static void main(String[] args)
18
{
Yapısal Programlama
19
TuretilmisSinif turetilmisNesne = new
TuretilmisSinif();
20
}
21}
Program çalıştırıldığında ekranda çıkan mesajlar şu şekildedir:
Temel sınıfın yapıcı metodu çalıştı
Türetilmiş sınıfın yapıcı metodu çalıştı
Çalışan modelimizi biraz daha genişleterek mühendisleri branşlarına göre farklı sınıflara ayırırsak
ve bir Muhasebeci sınıfı eklersek sınıfların son hali aşağıdaki gibi olur.
Örnek Uygulama 5.15:
1 public class Calisan
2 {
3protected String ad;
4protected String soyad;
5public Calisan(String ad, String soyad)
6{
7
this.ad = ad;
8
this.soyad = soyad;
9}
10}
11public class Muhendis extends Calisan
12{
13
protected String[] projeler;
14
protected String departman;
15
protected int projeSayisi;
16
public Muhendis(String ad, String soyad, String departman)
17
{
18
super(ad, soyad);
19
this.departman = departman;
20
this.projeler = new String[5];
21
this.projeSayisi = 0;
22
}
23
public void ProjeEkle(String proje)
24
{
25
projeler[projeSayisi] = proje;
26
projeSayisi++;
27
}
28}
29public class BilgisayarMuhendisi extends Muhendis
30{
31
protected String[] programlamaDilleri;
57
58
Bölüm 5
32
protected int programlamaDiliSayisi;
33
public BilgisayarMuhendisi(String ad, String soyad, String
departman)
34
{
35
super(ad, soyad, departman);
36
this.programlamaDilleri = new String[5];
37
this.programlamaDiliSayisi = 0;
38
}
39
public void ProgramlamaDiliEkle(String programlamaDili)
40
{
41
programlamaDilleri[programlamaDiliSayisi] =
programlamaDili;
42
programlamaDiliSayisi++;
43 }
44}
45public class MakinaMuhendisi extends Muhendis
46{
47
private String[] modellemeProgramlari;
48
private int modellemeProgramiSayisi;
49
public MakinaMuhendisi(String ad, String soyad, String
departman)
50
{
51
super(ad, soyad, departman);
52
this.modellemeProgramlari = new String[5];
53
this.modellemeProgramiSayisi = 0;
54
}
55
public void ModellemeProgramiEkle(String
modellemeProgrami)
56
{
57
modellemeProgramlari[modellemeProgramiSayisi] =
modellemeProgrami;
58
59
}
modellemeProgramiSayisi++;
60}
61public class Muhasebeci extends Calisan
62{
63
private String[] muhasebeProgramlari;
64
private int muhasebeProgramiSayisi;
65
public Muhasebeci(String ad, String soyad)
66
{
67
super(ad, soyad);
68
this.muhasebeProgramlari = new String[5];
69
this.muhasebeProgramiSayisi = 0;
Yapısal Programlama
70
}
71
public void MuhasebeProgramiEkle(String muhasebeProgrami)
72
{
73
muhasebeProgramlari[muhasebeProgramiSayisi] =
muhasebeProgrami;
74
muhasebeProgramiSayisi++;
75
}
76
public void MuhasebeProgramiEkle(String muhasebeProgrami)
77
{
78
if (!muhasebeProgramlari.contains(muhasebeProgrami))
79
80
}
muhasebeProgramlari.add(muhasebeProgrami);
81}
Çok Şekillilik (Polymorphism)
Çok şekillilik, bir nesnenin çalışma aşamasında hangi tipten olduğunu bilmesi ve kendi tipine
göre davranış sergilemesidir. Oluşturduğumuz iş modeli çerçevesinde bir müdür ve bu müdüre
bağlı çalışanlar bulunduğunu ve bütün çalışanların rapor verme kabiliyetine sahip olduğunu varsayalım. Müdür aynı anda bütün çalışanlardan kendisine haftalık rapor vermelerini istediğinde
aşağıdaki iki yöntemle istekte bulunabilir:
1� Yalçın Bey Bilgisayar Mühendisliği ile ilgili rapor göndersin, Erkut Bey muhasebecilikle ilgili
rapor göndersin.
2. Bütün çalışanlar rapor göndersin.
3� Rapor isteme-gönderme mekanizmasının işlevsel olması için ikinci senaryonun kullanılmasının daha mantıklı olduğunu söyleyebiliriz. Şirket müdürü bütün çalışanlarından rapor isterken
tek tek yaptıkları işe göre rapor isteyecek olursa bunun gereksiz zaman kaybına yol açacağı
rahatlıkla gözlenebiliyor.
Çok şekillilik, ikinci senaryomuzu gerçekleyen yapıdır. Gerçek hayattaki mühendislerin ve muhasebecilerin hangi işi yaptıklarını bilmeleri gibi, nesne yönelimli yazılımda da nesneler çalışma
aşamasında hangi işi nasıl yaptıklarını bilirler ve ona göre davranırlar. Bu durumda rapor verme
davranışı farklı nesne tiplerine göre farklı şekillerde çalışabildiğinden çok şekilli bir davranıştır.
.Net ortamında metodların çok şekilliliği desteklemesi için “virtual” olarak tanımlanması gerekir,
Java ortamında ise metodlar varsayılan olarak çok şekilliliği destekler. Çok şekillilik yapısı sadece
kalıtım ilişkisi içinde olan sınıflar arasında kullanılabilir.
Örneğimizin çok şekilliliği destekleyen hali Örnek Uygulama 5.16’daki gibi olacaktır:
Örnek Uygulama 5.16:
1 public class Calisan
2 {
3protected String ad;
4protected String soyad;
5public Calisan(String ad, String soyad)
6{
7
this.ad = ad;
8
this.soyad = soyad;
9}
59
60
Bölüm 5
10
public void RaporVer()
11
{
12
soyad);
13
System.out.println(“Ad: “ + ad + “ Soyad: “ +
}
14}
15public class Muhendis extends Calisan
16{
17
protected String[] projeler;
18
protected String departman;
19
protected int projeSayisi;
20
public Muhendis(String ad, String soyad, String departman)
21
{
22
super(ad, soyad);
23
this.departman = departman;
24
this.projeler = new String[5];
25
this.projeSayisi = 0;
26
}
27
public void ProjeEkle(String proje)
28
{
29
projeler[projeSayisi] = proje;
30
projeSayisi++;
31
}
32
public void RaporVer()
33
{
34
super.RaporVer();
35
System.out.println(“Departman: “ + departman);
36
System.out.println(“Projeler: “);
37
for (int i = 0; i < projeSayisi; i++)
38
{
39
40
}
41
}
System.out.println(“\t” + projeler[i]);
42}
43public class BilgisayarMuhendisi extends Muhendis
44{
45
protected String[] programlamaDilleri;
46
protected int programlamaDiliSayisi;
47
public BilgisayarMuhendisi(String ad, String soyad, String
departman)
48
{
49
super(ad, soyad, departman);
50
this.programlamaDilleri = new String[5];
Yapısal Programlama
51
this.programlamaDiliSayisi = 0;
52
}
53
public void ProgramlamaDiliEkle(String programlamaDili)
54
{
55
programlamaDilleri[programlamaDiliSayisi] =
programlamaDili;
56
programlamaDiliSayisi++;
57
}
58
public void RaporVer()
59
{
60
super.RaporVer();
61
System.out.println(“Görev: Bilgisayar Mühendisi”);
62
System.out.println(“Programlama Dilleri: “);
63
for (int i = 0; i < this.programlamaDiliSayisi; i++)
64
{
65
System.out.println(“\t” +
programlamaDilleri[i] + “ “);
66
67
}
}
68}
69public class MakinaMuhendisi extends Muhendis
70{
71
private String[] modellemeProgramlari;
72
private int modellemeProgramiSayisi;
73
public MakinaMuhendisi(String ad, String soyad, String
departman)
74
{
75
super(ad, soyad, departman);
76
this.modellemeProgramlari = new String[5];
77
this.modellemeProgramiSayisi = 0;
78
}
79
public void ModellemeProgramiEkle(String
modellemeProgrami)
80
{
81
modellemeProgramlari[modellemeProgramiSayisi] =
modellemeProgrami;
82
83
}
84
public void RaporVer()
85
{
86
super.RaporVer();
87
System.out.println(“Görev: Makina Mühendisi”);
88
System.out.println(“Modelleme Programları: “);
89
for (int i = 0; i < modellemeProgramiSayisi; i++)
modellemeProgramiSayisi++;
61
62
Bölüm 5
90
{
91
System.out.println(“\t” +
modellemeProgramlari[i] + “ “);
92
93
}
}
94}
95public class Muhasebeci extends Calisan
96{
97
private String[] muhasebeProgramlari;
98
private int muhasebeProgramiSayisi;
99
public Muhasebeci(String ad, String soyad)
100
{
101
super(ad, soyad);
102
this.muhasebeProgramlari = new String[5];
103
this.muhasebeProgramiSayisi = 0;
104
}
105
public void MuhasebeProgramiEkle(String muhasebeProgrami)
{
106
muhasebeProgramlari[muhasebeProgramiSayisi] =
muhasebeProgrami;
107
108
}
muhasebeProgramiSayisi++;
109
public void RaporVer()
110
{
111
super.RaporVer();
112
System.out.println(“Görev: Muhasebeci”);
113
System.out.println(“Muhasebe Programları: “);
114
for (int i = 0; i < muhasebeProgramiSayisi; i++)
115
{
116
System.out.println(“\t” +
muhasebeProgramlari[i]);
117
118
}
}
119}
120public class Mudur
121{
122
private Calisan[] calisanlar;
123
private int calisanSayisi;
124
public Mudur()
125
{
126
this.calisanlar = new Calisan[5];
127
this.calisanSayisi = 0;
128
}
Yapısal Programlama
129
public void CalisanEkle(Calisan calisan)
130
{
131
calisanlar[calisanSayisi] = calisan;
132
calisanSayisi++;
133
}
134
public void RaporIste()
135
{
136
for (int i = 0; i < calisanSayisi; i++)
137
{
138
calisanlar[i].RaporVer();
139
System.out.println();
140
}
141
}
142}
143public class AnaProgram
144{
145
public static void main(String[] args)
146
{
147
BilgisayarMuhendisi blgMuh = new BilgisayarMuhendisi
(“Yalçın”, “Kaya”, “IT”);
148
blgMuh.ProgramlamaDiliEkle(“Java”);
149
blgMuh.ProgramlamaDiliEkle(“C#”);
150
MakinaMuhendisi mknMuh = new
MakinaMuhendisi(“Hasan”, “Polat”, “Bakım”);
151
mknMuh.ModellemeProgramiEkle(“Katia”);
152
“Kutlar”);
Muhasebeci muhasebeci = new Muhasebeci(“Erkut”,
153
Mudur genelMudur = new Mudur();
154
genelMudur.CalisanEkle(blgMuh);
155
genelMudur.CalisanEkle(mknMuh);
156
genelMudur.CalisanEkle(muhasebeci);
157
genelMudur.RaporIste();
158
}
159}
Program çalıştırıldığında aşağıdaki gibi bir çıktı üretir:
Ad: Yalçın Soyad: Kaya
Departman: IT
Projeler:
Görev: Bilgisayar Mühendisi
Programlama Dilleri:
Java
C#
63
64
Bölüm 5
Ad: Hasan Soyad: Polat
Departman: Bakım
Projeler:
Görev: Makina Mühendisi
Modelleme Programları:
Katia
Ad: Erkut Soyad: Kutlar
Görev: Muhasebeci
Muhasebe Programları:
Mudur sınıfının içinde, çalışanları tutmak için Calisan sınıfı cinsinden bir dizi kullandık. Ana
programda oluşturduğumuz üç tane farklı tipte çalışanı (bilgisayar mühendisi, makina mühendisi, muhasebeci) müdür nesnemizin çalışanlarına ekledik. Mudur sınıfının RaporIste metodu
butun çalışanlardan rapor istemek amacıyla yazıldı. Müdür nesnesinin RaporIste metodunu
çalıştırdığımızda bütün çalışan nesnelerinin kendi tiplerine ait raporları oluşturduğunu görüyoruz.
Raporların doğru bir şekilde oluşması RaporVer metodunun çok şekilli olduğunu gösterir. Müdür
sınıfında bütün çalışan bilgilerinin Calisan sınıfından oluşan bir dizide tutulmasından dolayı
derleme aşamasında çalışanların tipi belli değildir. Eğer RaporVer metodu çok şekilli olmasaydı,
müdür nesnesinin RaporIste metodu çağrıldığında çalışanların hepsi derleme aşamasında olduğu gibi çalışma aşamasında da temel Calisan sınıfının raporunu oluşturacaktı.
6
Swing
6 Swing
• Swing’e Giriş
• Klavye Event’lerinin Yönetilmesi
Swing
Java platformunun 1.0 versiyonunda görsel kullanıcı arayüzleri oluşturmak için AWT (Abstract
Windowing Toolkit) teknolojisi kullanılıyordu. AWT’nin temel amacı Java programlarının arayüzlerini işletim sisteminden bağımsız hale getirmek olsa da bu amaca ulaşılamadı. AWT paketinin
içinde bulunan bileşenler işletim sistemine bağımlı olduğundan farklı işletim sistemleri üzerinde
faklı görünümlere sahip olan programlar ortaya çıktı. Java platformunun 2.0 versiyonuyla birlikte
AWT paketinin üzerine Swing adı verilen yeni görsel programlama modeli de eklendi. Swing paketi Java ile yazılmış olmasının da etkisiyle İşletim sisteminden bağımsız bir görsel programlama
modeli sunar. Yeni geliştirilen Java uygulamalarında Swing paketinin kullanılması uygulamanın
görsel arayüzünün güçlü olması için şarttır.
Bu bölümde Java platformunda bulunan Swing paketinin genel özellikleri ve bu paketin içinde
bulunan temel arayüz kontrolleri anlatılacaktır. Swing bu bölümde anlatılanlarla sınırlı değildir,
özellikle karmaşık kullanıcı etkileşimi gerektiren Java uygulamalarının geliştirebilmesi için Swing
teknolojisinin detaylı olarak incelenmesi gerekir.
Swing’e Giriş
.Net platformunda Windows uygulamaları geliştirirken kullandığımız kontrollerin benzerleri Java
platformunda da vardır. Swing kontrolleri çeşitli olayları (event) tetikleyerek uygulama arayüzüyle kullanıcının etkileşim halinde olmasına olanak tanır. Uygulamada kullanılan kontroller çeşitli
container’lar (saklayıcı) yardimiyla gruplanabilir. Java platformuyla işletim sistemi üzerinde çalışan uygulamalar oluşturmak için uygulamanın görsel arayüzünü temsil edecek sınıfın JFrame
sınıfından türetilmesi gerekir. JFrame sınıfının içinde bulunan ve yeni oluşturulan sınıflara kalıtımla aktarılan getContentPane metodu kullanılarak uygulamada bulunan kontrolleri içeren
Container nesnesine erişilir. Menü kontrolleri dışındaki bütün kontroller Container nesnesi
içinde bulunur ve Container nesnesi hiçbir zaman null (boş) değer almaz.
Container nesnesinin setLayout metodu uygulama arayüzünde kullanılacak yerleşim
düzenini(layout) belirlemek için kullanılır. Layout seçenekleri ilerleyen sayfalarda anlatılacaktır.
Boş bir arayüz oluşturan Java kodu Örnek Uygulama 6.1’de verilmiştir:
Örnek Uygulama 6.1:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import javax.swing.JFrame;
4 public class IlkOrnek extends JFrame
5 {
6public IlkOrnek()
7{
8
super(“İlk Örnek”);
9
Container container = getContentPane();
10
container.setLayout(new FlowLayout());
11
setSize(200, 200);
12
setVisible(true);
13}
14public static void main(String[] args)
15{
16
IlkOrnek test = new IlkOrnek();
17
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
68
Bölüm 6
18}
19}
Kodun açıklaması: IlkOrnek isimli sınıfımız JFrame sınıfından türetilmiştir. Yapıcı metod içinde JFrame sınıfının yapıcı metodu super(“İlk Örnek”) kod bloğuyla çalıştırılır, oluşan ekranın
başlığında “İlk Örnek” metni bulunur. Container nesnesi getContentPane metodu ile yukarıda açıklandığı gibi alınır. Forma başka kontroller de ekleyecek olursak bu kontrolleri Container
nesnesinin içine veya Container nesnesinin içinde bulunan bir nesneye eklememiz gerekir. Uygulamanın çalışması sırasında formun görünür hale gelmesi için boyutunu vermemiz ve setVisible metodunu kullanarak formu görünür hale getirmemiz
gereklidir. Main metodunun içinde, yazdığımız sınıftan bir
nesne oluşturarak formun oluşmasını sağlarız. JFrame sınıfından türetilmiş olan arayüzün kullanıcı tarafından kapatılması durumunda uygulamanın sonlandırılmasının sağlanması için test.setDefaultCloseOperation(JFrame.
EXIT_ON_CLOSE); kod bloğunu Main metoduna ekleriz.
Bu satırı eklemezsek, uygulama kapatıldığında varsayılan
işlem olarak form görünmez hale gelindiği halde uygulama
kapanmaz. Swing ile ilgili bütün örneklerde yukarıda verilen
kodu kullanacağız.
Uygulama çalıştırıldığında oluşan arayüz Şekil 1’deki gibidir.
Şekil 1
JButton
.Net platformundaki Button kontrolünün karşılığı Java platformundaki JButton kontrolüdür. Temel olarak üzerinde bir metin yazılı olabilen ve kullanıcı tarafından üzerine tıklandığında event
oluşturan bir yapıya sahiptir. Form üzerinde bir buton oluşturmak için JButton sınıfından bir
nesne yaratılır ve Container nesnesine eklenir. JButton sınıfının yapıcı metodu butonun üzerinde görüntülenecek metni parametre olarak alır. JButton nesnesi oluşturan ve formun üzerine
ekleyen kod Örnek Uygulama 6.2’de gösterilmiştir.
Örnek Uygulama 6.2:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import javax.swing.JButton;
4import javax.swing.JFrame;
5 public class JButtonTest extends JFrame
6 {
7private JButton btnTest;
8public JButtonTest()
9{
10
super(“JButton Örneği”);
11
Container container = getContentPane();
12
container.setLayout(new FlowLayout());
13
btnTest = new JButton(“Örnek Buton”);
14
container.add(btnTest);
15
setSize(200, 200);
16
setVisible(true);
17
}
Swing
18
public static void main(String[] args)
19
{
20
JButtonTest test = new JButtonTest();
21
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
22
}
23}
Kodun açıklaması: Formu oluşturan kod bloklarından farklı olarak bir adet JButton nesnesi
oluşturan ve Container nesnesine ekleyen kod satırları yukarıdadır. JButton sınıfının yapıcı
metoduna parametre olarak butonun üzerinde bulunmasını
istediğimiz metni veririz. Container nesnesinin add metodu herhangi bir kontrolün Container içine eklenmesini
sağlar. Uygulama çalıştırıldığında Şekil 2’deki gibi bir arayüz
oluşur.
Oluşturduğumuz butona henüz bir event eklemediğimiz için
butonun herhangi bir işlevi yoktur.
JLabel
JLabel kontrolü, .Net ortamındaki Label kontrolünün karşılığıdır. Uygulama üzerinde metin görüntülemek istediğimiz
noktalarda kullanılır. Bir JLabel kontrolünün uygulama üzerinde görünür hale gelmesi için bir JLabel nesnesi oluşturup Container nesnesine eklememiz yeterlidir. Örnek kod
Örnek Uygulama 6.3’de verilmiştir.
Şekil 2
Örnek Uygulama 6.3:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import javax.swing.JFrame;
4 import javax.swing.JLabel;
5 public class JLabelTest extends JFrame
6 {
7private JLabel lblTest;
8public JLabelTest()
9{
10
11
12
super(“JLabel Kullanımı”);
Container container = getContentPane();
container.setLayout(new FlowLayout());
13
lblTest = new JLabel(“JLabel Örneği”);
14
container.add(lblTest);
15
setSize(200, 200);
16
setVisible(true);
17
}
18
public static void main(String[] args)
19
20
21
22
23}
{
}
JLabelTest test = new JLabelTest();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
69
70
Bölüm 6
Kodun açıklaması: lblTest adındaki JLabel nesnesin yapıcı metoduna parametre olarak
üzerinde görüntülenecek metin verilmiştir. Container nesnesinin add metodu kullanılarak JLabel nesnesinin form üzerinde görüntülenmesi sağlanmıştır. Label üzerindeki metni uygulamanın çalışma aşamasında değiştirmek için setText metodu,
label üzerindeki metni almak için getText metodu kullanılır. Bu iki metodun kullanımıyla ilgili örneği daha sonra
vereceğiz. Uygulama çalıştırıldığı zaman Şekil 3’de olduğu
gibi görünür.
JTextField
JTextField kontrolü, .Net ortamındaki TextBox kontrolülün Java ortamındaki karşılığıdır. Kullanıcı tarafından girilecek metin türünden bilgileri uygulamaya aktarmak amacıyla
kullanılır. Bir JTextField kontrolünün uygulama üzerinde
görünür hale gelmesi için bir JTextField nesnesi oluşturup Container nesnesine eklememiz yeterlidir. Örnek kod,
Örnek Uygulama 6.4’te verilmiştir.
Şekil 3
Örnek Uygulama 6.4:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import javax.swing.JFrame;
4 import javax.swing.JLabel;
5 import javax.swing.JTextField;
6 public class JTextFieldTest extends JFrame
7 {
8private JTextField txtTest;
9public JTextFieldTest()
10
{
11
super(“JTextField Kullanımı”);
12
Container container = getContentPane();
13
container.setLayout(new FlowLayout());
14
txtTest = new JTextField(“JTextField Örneği”);
15
container.add(txtTest);
16
setSize(200, 200);
17
setVisible(true);
18
}
19
public static void main(String[] args)
20
{
21
JTextFieldTest test = new JTextFieldTest();
22
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
23
}
24}
Kodun açıklaması: txtTest adındaki JTextField nesnesin yapıcı metoduna parametre olarak üzerinde görüntülenecek metin verilmiştir. Container nesnesinin add metodu kullanılarak
JTextField nesnesinin form üzerinde görüntülenmesi sağlanmıştır. JTextField üzerindeki
metni uygulamanın çalışma aşamasında değiştirmek için setText metodu, label üzerindeki
Swing
metni almak için getText metodu kullanılır. Bu iki metodun kullanımıyla ilgili örneği daha sonra
vereceğiz. Uygulama çalıştırıldığı zaman Şekil 4’teki gibi görünür.
Şekil 4
Event Handling Mekanizması
Kullanıcıların Swing kontrolleri aracılığıyla uygulamayla iletişim kurması sonucunda çeşitli
event’ler (olaylar) oluşur. Bu event’leri kontrol etmek (handle) için .Net ortamından farklı olarak
event sınıfları kullanmamız gerekir. Java ortamında herşeyi sınıflar halinde kullanmak gibi bir
amaç olduğundan event handling mekanizması .Net ortamındakinden farklıdır. Net uygulamalarında herhangi bir event için bir tane metod yazmak yeterli olurken Java’da bu işlem için harici
veya dahili (inner class) bir sınıf yazarak çeşitli event tipleri için özelleşmiş event interface’lerini
implemente etmemiz gerekir. Herhangi bir event birden fazla Swing kontrolü tarafından kullanılabilir, boyle bir kullanımda event’in hangi kontrol üzerinden oluştuğunu öğrenmek için event
parametreleri kullanılır. JLabel, JTextField ve JButton kontrolleriyle birlikte event mekanizmasini örnek kodu, Örnek Uygulama 6.5 üzerinden inceleyelim:
Örnek Uygulama 6.5:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JButton;
6 import javax.swing.JFrame;
7 import javax.swing.JLabel;
8 import javax.swing.JTextField;
9 public class EventMekanizmasi extends JFrame
10{
11
private JLabel lblGoruntule;
12
private JTextField txtGiris;
13
private JButton btnGoruntule;
14
public EventMekanizmasi()
15
{
16
super(“Event Mekanizması”);
17
Container container = getContentPane();
18
container.setLayout(new FlowLayout());
19
txtGiris = new JTextField(“JTextField”);
71
72
Bölüm 6
20
container.add(txtGiris);
21
btnGoruntule = new JButton(“Görüntüle”);
22
container.add(btnGoruntule);
23
btnGoruntule.addActionListener(new ButtonHandler());
24
lblGoruntule = new JLabel(“JLabel”);
25
container.add(lblGoruntule); 26
setSize(400, 200);
27
setVisible(true);
28
}
29
private class ButtonHandler implements ActionListener
30
{
31
public void actionPerformed(ActionEvent e)
32
{
33
34
}
35
}
36
public static void main(String[] args)
37
{
38
EventMekanizmasi test = new EventMekanizmasi();
39
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
40
}
lblGoruntule.setText(txtGiris.getText());
41}
Kodun açıklaması: EventMekanizmasi sınıfının yapıcı metodunda daha önce yaptığımız gibi
JLabel, JTextField ve JButton nesnelerini oluşturduk ve Container nesnesine ekledik.
EventMekanizmasi sınıfının içindeki private erişim tipine sahip ButtonHandler sınıfının
ActionListener interface’ini implemente etmesi, bu sınıfın içinde actionPerformed metodunun yazılmasını zorunlu kılar. Bu metod, Action cinsinden bir event oluştuğunda çalışır.
JButton nesnesi üzerinde çalıştırdığımız addActionListener metodunu buton ile event’i
ilişkilendirmek için kullandık, bu durumda buton kullanıcı tarafından tıklandığında ButtonHandler sınıfındaki actionPerformed metodu çalışacaktır. actionPerformed metodunun içinde
txtGiris nesnesinin getText metodunu kullanarak kullanıcı tarafından girilen metni alıp lblGoruntule nesnesinin setText metodu ile JLabel kontrolünün metnine atıyoruz.
Aynı işlevi, event handler sınıfını dahili olarak tanımlayarak da gerçekleyebiliriz. Event handler
sınıfının dahili olarak gerçeklenmesini gösteren kod bloğu Örnek Uygulama 6.6’daki gibidir.
Örnek Uygulama 6.6:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JButton;
6 import javax.swing.JFrame;
7 import javax.swing.JLabel;
8 import javax.swing.JTextField;
9 public class EventMekanizmasi extends JFrame
Swing
10{
11
private JLabel lblGoruntule;
12
private JTextField txtGiris;
13
private JButton btnGoruntule;
14
public EventMekanizmasi()
15
{
16
super(“Event Mekanizması”);
17
Container container = getContentPane();
18
container.setLayout(new FlowLayout());
19
txtGiris = new JTextField(“JTextField”);
20
container.add(txtGiris);
21
btnGoruntule = new JButton(“Görüntüle”);
22
container.add(btnGoruntule);
23
btnGoruntule.addActionListener
24
(
25
new ActionListener()
26
{
27
event)
public void actionPerformed(ActionEvent
28
{
29
lblGoruntule.setText(txtGiris.getText());
30
31
}
32
);
33
lblGoruntule = new JLabel(“JLabel”);
34
container.add(lblGoruntule);
35 setSize(400, 200);
36 setVisible(true);
}
37 }
38 public static void main(String[] args)
39 {
40 EventMekanizmasi test = new EventMekanizmasi();
41 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
42 }
43}
Her iki kod bloğu da aynı şekilde çalışır. Kullanıcının metin kutusuna yazdığı metin butona tıklandıktan sonra label üzerinde görüntülenir. Uygulama çalıştırıldığında butona tıklamadan önce ve
sonraki görünümler Şekil 5 ve Şekil 6’daki gibidir.
73
74
Bölüm 6
Şekil 6
Şekil 5
JTextArea
JTextArea kontrolü, .Net ortamındaki RichTextBox kontrolünün karşılığıdır. JTextField
kontrolünden daha geniş kullanım kabiliyetlerine sahiptir ve birden fazla satırdan oluşan metinlerin girilmesine olanak verir. Append metodu yardımıyla üzerine metin eklemesi yapılabilir. Girilen
metnin kontrolün boyutlarından büyük olması durumunda bir alt satıra geçmek için setLineWrap
metodu kullanılır. JTextArea kontrolünün örnek kullanımı Örnek Uygulama 6.7’de verilmiştir.
Örnek Uygulama 6.7:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import javax.swing.JFrame;
4 import javax.swing.JTextArea;
5 public class JTextAreaTest extends JFrame
6 {
7private JTextArea txtArea;
8public JTextAreaTest()
9{
10
super(“JTextArea Kullanımı”);
11
Container container = getContentPane();
12
container.setLayout(new FlowLayout());
13
txtArea = new JTextArea(“JTextArea
fazla satirdan oluşan metin girilebilir.”);
alanına birden
14
txtArea.append(“\nYeni metin eklenebilir”);
15
txtArea.setLineWrap(true);
16
txtArea.setSize(150, 150);
17
container.add(txtArea);
18
setSize(200, 200);
19
setVisible(true);
20
}
21
public static void main(String[] args)
22
{
23
JTextAreaTest test = new JTextAreaTest();
24
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
25
}
26}
Swing
Kodun açıklaması: JTextArea nesnesini oluşturulup Container nesnesine ekledikten sonra
append metodu ile üzerine yeni metin ekledik. Append metodunun içinde kullandığımız “\n” karakteri metnin bir alt satıra geçmesini sağlar. setLineWrap(true) komutuyla metnin kontrolün
genişliğinden fazla yer kaplaması durumunda otomatik olarak bir alt satıra geçmesi sağlanmıştır.
setSize metodu ile kontrolün x ve y boyutu 150 olarak atanmıştır. Uygulama çalıştırıldığında
Şekil 7’deki gibi bir arayüz oluşur.
JOptionPane
JOptionPane sınıfı, .Net ortamında bulunan MessageBox
sınıfının Java karşılığıdır. MessageBox.Show() metoduna
benzer bir şekilde çalışan birçok statik metod içerir. Arayüzün çalışma mantığı içinde çeşitli mesajları kullanıcıya göstermek ve onay almak amacıyla kullanılır. Gösterilen onay
kutusu uygulamayı oluşturan formun dışında ayrı bir pencere içinde oluşur. Bir JOptionPane onay kutusunu kullanıcının karşısına çıkartan ve kullanıcının onay durumuna göre
bir tane JOptionPane mesaj diyaloğu gösteren kod Örnek
Uygulama 6.8’de verilmiştir.
Şekil 7
Örnek Uygulama 6.8:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JButton;
6 import javax.swing.JFrame;
7 import javax.swing.JOptionPane;
8 public class JOptionPaneTest extends JFrame
9 {
10
11
private JButton btnOnay;
public JOptionPaneTest()
12
13
{
Super(“JOptionPane”);
14
Container container = getContentPane();
15
container.setLayout(new FlowLayout());
16
btnOnay = new JButton(“Onay al”);
17
btnOnay.addActionListener(new ButtonHandler());
18
container.add(btnOnay);
19
setSize(200, 200);
20
setVisible(true);
21
}
22
private class ButtonHandler implements ActionListener
23
24
{
public void actionPerformed(ActionEvent event)
25
{
26
int secim = JOptionPane.
showConfirmDialog(null, “Seçiminizi onaylıyor musunuz?”, “Onay
ekranı”, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_
MESSAGE);
75
76
Bölüm 6
27
if(secim == JOptionPane.YES_OPTION)
28
JOptionPane.showMessageDialog(null,
“Onaylandı”, “Onay”, JOptionPane.INFORMATION_MESSAGE);
29
else if(secim == JOptionPane.NO_OPTION)
30
JOptionPane.showMessageDialog(null,
“Onaylanmadı”, “Red”, JOptionPane.ERROR_MESSAGE);
31
else
32
JOptionPane.showMessageDialog(null,
“Onaylanmadı”, “İptal”, JOptionPane.WARNING_MESSAGE);
33
}
34
}
35
public static void main(String[] args)
36
{
37
JOptionPaneTest test = new JOptionPaneTest();
38
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
39
}
40}
Kodun açıklaması: Formun üzerine bir tane buton ekledik ve bu buton için ActionListener interface’ini implemente eden ButtonHandler adında bir event sınıfı yazdık. Kullanıcı tarafından butona tıklanması durumunda actionPerformed metodu çalışır ve kullanıcıya JOptionPane.showConfirmDialog metodu yardımıyla onay verip vermediği sorulur. Bu statik
metodun ikinci parametresi onay kutusunda görüntülenmesini istediğimiz metin, üçüncü parametresi ise onay kutusunun başlığını oluşturan metindir. Dördüncü parametrede onay kutusunda
hangi butonların görüntülenmesini istediğimizi belirttik. Yaptığımız örnekte Yes, No ve Cancel
butonlarının görüntülenmesini istedik. Kullanıcının herhangi birşeyi onaylamasını istediğimiz için
soru işareti şeklinde bir resim kullanmak duruma uygun olduğundan beşinci parametrede soru
mesajı seçeneğini seçtik. Java’daki birçok metod parametresinde olduğu gibi JOptionPane.
showConfirmDialog metodunun parametrelerinde de sınıfın üzerinde bulunan değerleri kullanabildiğimiz gibi istersek bu değerlerin tam sayı karşılıklarını da kullanabiliriz. Metodun geri dönüş
değerinin tam sayı(int) olduğuna dikkat edelim. Bu geri dönüş değerini secim isimli bir tam sayı
değişkenine atarak bir sonraki aşamada seçime göre bir işlem yapılmasını sağlayabiliriz.
Sonraki aşamada, onay durumuna göre değişen bir simgeye, başlık metnine ve mesaj kutusu
metnine sahip bir mesaj kutusunu kullanıcıya gösteriyoruz.
Uygulama çalıştırıldığında görünen arayüz, butona tıklandığı zaman görüntülenen onay kutusu
ve çeşitli seçimlere göre görüntülenen mesaj kutuları Şekil 8, Şekil 9, Şekil 10, Şekil 11 ve Şekil
12’de gösterildiği gibidir.
Şekil 8: Programın ilk çalışması.
Şekil 9: Onay ekranı.
Swing
Şekil 10: Yes butonuna tıklandı.
Şekil 11: No butonuna tıklandı.
Şekil 12: İptal butonuna tıklandı.
JCheckBox
JCheckBox sınıfı, .Net platformunda bulunan CheckBox sınıfının Java ortamındaki karşılığıdır.
Seçili durumda olabilen küçük bir kutudan ve yanında bulunan bir Label’dan oluşan JCheckBox, kullanıcının temel açık/kapalı seçimi yapmasını sağlayan basit bir arayüz kontrolüdür. Belirli bir zamanda nesnenin seçili olup olmadığı kontrol edilebilir, seçim değiştiğinde bir event’in
tetiklenmesi sağlanabilir, seçili olma durumu değiştirilebilir. JCheckBox kontrolünün kullanımını
gösteren kod bloğu Örnek Uygulama 6.9’da verilmiştir.
Örnek Uygulama 6.9:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.GridLayout;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.ItemEvent;
7 import java.awt.event.ItemListener;
8 import javax.swing.JButton;
9 import javax.swing.JCheckBox;
10 import javax.swing.JFrame;
11 import javax.swing.JLabel;
12 import javax.swing.JOptionPane;
13 import javax.swing.JTextField;
14 public class JCheckBoxTest extends JFrame
15 {
16 private JCheckBox chkKabul;
17 private JLabel lblAd;
18 private JLabel lblSoyad;
19 private JTextField txtAd;
20 private JTextField txtSoyad;
21 private JButton btnKaydet;
22 public JCheckBoxTest()
23 {
24 super(“Kullanıcı kayıt formu”);
25 Container container = getContentPane();
77
78
Bölüm 6
26 container.setLayout(new FlowLayout());
27 lblAd = new JLabel(“Ad: “);
28 container.add(lblAd);
29 txtAd = new JTextField(10);
30 container.add(txtAd);
31 lblSoyad = new JLabel(“Soyad: “);
32 container.add(lblSoyad);
33 txtSoyad = new JTextField(10);
34 container.add(txtSoyad);
35 btnKaydet = new JButton(“Kaydet”);
36 btnKaydet.setEnabled(false);
37 btnKaydet.addActionListener
38 (
39 new ActionListener()
40 {
41 event)
public void actionPerformed(ActionEvent
42 {
43 JOptionPane.
showMessageDialog(null, “Ad: “ + txtAd.getText() + “\nSoyad: “ +
txtSoyad.getText());
44 45 }
46 );
47 }
container.add(btnKaydet);
48 ediyorum”);
chkKabul = new JCheckBox(“Sözleşmeyi kabul
49 chkKabul.addItemListener
50 (
51 new ItemListener()
52 {
53 event)
public void itemStateChanged(ItemEvent
54 {
55 if(chkKabul.isSelected() == true)
56 57 else
58 59 }
60 }
61 );
62 container.add(chkKabul);
63 setSize(200, 150);
64 setVisible(true);
65 }
btnKaydet.setEnabled(true);
btnKaydet.setEnabled(false);
Swing
66 public static void main(String[] args)
67 {
68 JCheckBoxTest test = new JCheckBoxTest();
69 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
70 }
71 }
Kodun açıklaması: İki tane JLabel, iki tane JTextField, bir tane JButton ve bir tane JCheckBox nesnesi oluşturularak Container nesnesine eklendi. JCheckBox nesnesi üzerinde
çalıştırılan addItemListener metodu ile, bu nesnenin durumunun değişmesi halinde tetiklenecek olan event handler’i oluşturuldu. Yazdığımız koda göre, uygulama ilk çalıştırıldığında buton aktif değildir. Kullanıcı ad ve soyad bilgilerini girdikten sonra sözleşmeyi kabul ettiğini belirten JCheckBox’ı işaretlediğinde (checkbox’ı seçili hale getirdiğinde) JCheckBox nesnesinin
uzerindeki ItemListener metodu çalışır ve buton aktif hale gelir. Benzer bir şekilde kullanıcı
CheckBox üzerindeki seçimi iptal ederse buton aktiflik özelliğini yitirir. Kullanıcı gereken bilgileri
girdikten sonra Kaydet butonuna tıkladığında ad ve soyad bilgileri bir mesaj kutusu (JOptionPane) yardımıyla ekranda görüntülenir. Uygulama çalıştırıldığında görünen arayüz Şekil 13, Şekil
14 ve Şekil 15’teki gibidir:
Şekil 13: Buton aktif değil.
Şekil 14: Buton aktif.
Şekil 15: Kaydet butonuna tıklandı.
JRadioButton
JRadioButton bileşeni, .Net ortamındaki RadioButton kontrolünün Java platformundaki karşılığıdır. Birden fazla seçeneğe sahip bir veri kümesi arasından birinin seçilmesi gereken durumlarda kullanılır. .Net ortamındaki RadioButton kontrolünden farklı olarak arayüz üzerinde aynı
anda birden fazla JRadioButton kontrolü seçili durumda bulunabilir. Bu durumu önlemek için,
arayüz üzerindeki ilişkili JRadioButton kontrolleri bir tane ButtonGroup nesnesi kullanılarak gruplandırılır. JRadioButton kontrolü üzerindeki seçim durumundaki değişiklik JCheckBox
kontrolü gibi ItemListener interface’i ile kontrol edilebilir. İki tane JRadioButton kontrolü ile
bir tane ButtonGroup kontrolü içeren ve JRadioButton nesneleri üzerindeki seçim durumunun değişikliğini takip eden kod bloğu Örnek Uygulama 6.10’da gösterilmiştir.
Örnek Uygulama 6.10:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
79
80
Bölüm 6
3 import java.awt.event.ItemEvent;
4 import java.awt.event.ItemListener;
5 import javax.swing.ButtonGroup;
6 import javax.swing.JFrame;
7 import javax.swing.JOptionPane;
8 import javax.swing.JRadioButton;
9 import javax.swing.plaf.basic.BasicComboBoxUI.ItemHandler;
10 public class JRadioButtonTest extends JFrame
11 {
12 private JRadioButton rbErkek;
13 private JRadioButton rbKadin;
14 private ButtonGroup grpRadio;
15 public JRadioButtonTest()
16 {
17 super(“JRadioButton örneği”);
18 Container container = getContentPane();
19 container.setLayout(new FlowLayout());
20 rbErkek = new JRadioButton(“Erkek”, true);
21 rbErkek.addItemListener(new RadioButtonHandler());
22 container.add(rbErkek);
23 rbKadin = new JRadioButton(“Kadın”, false);
24 rbKadin.addItemListener(new RadioButtonHandler());
25 container.add(rbKadin);
26 ButtonGroup
// JRadioButton nesnelerini gruplandırmak için
kullanılır
27 grpRadio = new ButtonGroup();
28 grpRadio.add(rbErkek);
29 grpRadio.add(rbKadin);
30 setSize(200, 100);
31 setVisible(true);
32 }
33 private class RadioButtonHandler implements ItemListener
34 {
35 public void itemStateChanged(ItemEvent event)
36 {
37 SELECTED)
if(event.getStateChange() == ItemEvent.
38 {
39 JOptionPane.showMessageDialog(null,
((JRadioButton)event.getSource()).getText());
40 }
41 }
42 }
43 public static void main(String[] args)
44 {
Swing
45 JRadioButtonTest test = new JRadioButtonTest();
46 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
47 }
48 }
Kodun açıklaması: JRadioButtonTest sınıfının yapıcı metodunda iki tane JRadioButton,
bir tane ButtonGroup nesnesi oluşturduk. JRadioButton nesnelerini oluştururken kullandığımız yapıcı metodun ikinci parametresi mantıksal değer alır ve uygulama ilk çalıştığında JRadioButton nesnesinin seçili durumda olup olmayacağını belirtir. Uygulama ilk çalıştığında Erkek
değerine sahip JRadioButton nesnesi seçili durumdadır. İki JRadioButton nesnesi için de
aynı event handler sınıfını kullanacağımız için private bir iç sınıf oluşturduk. ItemStateChanged event handler metodu JRadioButton nesnelerinden birinin seçili olma durumu değiştiğinde
çalışır. Metodun başında kullandığımız if mekanizmasıyla sadece seçili hale gelen nesnelerle
ilgilendiğimizi belirttik ve JRadioButton kontrollerinden biri seçili hale geçtiğinde bu nesnenin text özelliğini mesaj kutusu kullanarak kullanıcıya gösterdik. Eğer ButtonGroup nesnesini
kullanmasaydık aynı anda birden fazla JRadioButton kontrolü seçili durumda bulunabilecekti.
ButtonGroup nesnesinin olması ve olmaması durumlarında uygulamanın davranışı Şekil 16,
Şekil 17 ve Şekil 18’de gösterilmiştir.
Şekil 16: ButtonGroup nesnesi kullanılmadığında
herhangi bir zamanda iki JRadioButton bir arada
seçilebilir.
Şekil 17: ButtonGroup nesnesi kullanıldı.
Şekil 18: rbErkek seçili durumda.
JComboBox
JComboBox kontrolü, .Net ortamındaki ComboBox kontrolü gibi bir veri kümesi üzerinden bir tane
eleman seçmek amacıyla kullanılır. .Net ortamındaki ComboBox kontrolü seçme, metin cinsinden
veri girişi, otomatik tamamlama gibi amaçlar için kullanılabildiği halde JComboBox kontrolü sadece veri seçmek amacıyla kullanılabilir, aynı anda birden fazla elemanın seçilmesine izin verilmez.
Temel amacı gereği bir arada kullanılan JRadioButton nesnelerine benzese de çalışma zamanında dinamik veri bağlama kolaylığından dolayı bu kontrolden ayrılır. JComboBox kontrolüne
veri bağlanması ve seçili elemanın değişmesi durumunda oluşan event’in kullanılması aşağıdaki
kod üzerinde gösterilmiştir.
Örnek Uygulama 6.11:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JComboBox;
81
82
Bölüm 6
6 import javax.swing.JFrame;
7 import javax.swing.JLabel;
8 import javax.swing.JOptionPane;
9 public class JComboBoxTest extends JFrame
10 {
11
private JLabel lblOgrenimDurumu;
12
private JComboBox cmbOgrenimDurumu;
13
public JComboBoxTest()
14
{
15 super(“JComboBox örneği”);
16 Container container = getContentPane();
17 container.setLayout(new FlowLayout());
18 seçin”);
lblOgrenimDurumu = new JLabel(“Öğrenim durumunuzu
19 container.add(lblOgrenimDurumu);
20 String[] ogrenimDurumlari = {“İlkokul”, “Ortaokul”,
“Lise”, “Üniversite”, “Yüksek lisans”, “Doktora”};
21 cmbOgrenimDurumu = new JComboBox(ogrenimDurumlari);
22 cmbOgrenimDurumu.addActionListener
23 (
24 new ActionListener()
25 {
26 Event event)
public void actionPerformed(Action
27 {
28 JOptionPane.
showMessageDialog(null, cmbOgrenimDurumu.getSelectedItem().
toString());
29 }
30 }
31 );
32 container.add(cmbOgrenimDurumu);
33 setSize(200, 100);
34 setVisible(true);
35 }
36 public static void main(String[] args)
37 {
38 JComboBoxTest test = new JComboBoxTest();
39 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
40 }
41 }
Kodun açıklaması: Uygulama içinde bir tane JLabel ve bir tane JComboBox nesnesi tanımladık. Öğrenim durumlarını tutan bir string dizisi oluşturarak JComboBox nesnesinin yapıcı metoduna parametre olarak verdik. JComboBox nesnesi oluşurken yapıcı metoduna parametre olarak
verdiğimiz string dizisini veri kaynağı olarak kullanır. JComboBox nesnesinin seçili elemanı de-
Swing
ğiştiğinde çalışmak üzere bir ActionListener event handler metodu tanımladık. Uygulama ilk
çalıştığında ilk elemanın seçili durumda olduğu ve event handler metodunun uygulamanın ilk çalışması sırasında tetiklenmediği gözlenebilir. Bu aşamadan sonra seçili eleman değiştiği zaman
event handler metodu tetiklenir ve seçilmiş olan elemanın sahip olduğu metni bir JOptionPane
mesaj kutusu aracılığıyla kullanıcıya gösterir. Uygulamanın ihtiyacına göre birden fazla JComboBox nesnesinin aynı event handler metodunu kullanması sağlanabilir, bu durumda ActionListener interface’ini implement eden bir sınıf oluşturmak gerekir. Ayrıca bir JComboBox nesnesinin seçili elemanının değişmesiyle başka bir JComboBox nesnesinin veri kümesinin değişmesi de
sağlanabilir. İlerleyen kısımlarda bu durumla ilgili bir örnek yapacağız.
Uygulama ilk çalıştığında ve seçili eleman değiştiğinde Şekil 19 ve Şekil 20’deki gibi bir görünüm
oluşur:
Şekil 19
Şekil 20: Seçili eleman değişti.
JList
.Net ortamındaki ListBox kontrolünün Java platformundaki karşılığıdır. Belirli bir veri kümesi
üzerinden bir veya daha çok sayıda eleman seçmek amacıyla kullanılır. JComboBox kontrolünde
olduğu gibi sahip olduğu veri kümesi uygulamanın çalışması sırasında değiştirilebilir. Uygulamanın gereksinimlerine bağlı olarak bir tane, belirli bir aralıkta olmak üzere birden fazla veya belirli
bir aralıkta bulunma şartı bulunmadan birden fazla elemanın seçili olmasına izin verilebilir. Belirli
bir aralıkta olmak üzere birden fazla elemanın seçilmesi sağlanırsa kullanıcı, klavyedeki shift
tuşuyla birlikte mouse imlecini kullanarak aralık şeklinde seçim yapabilir. Belirli bir aralıkta bulunma şartı olmadan seçim yapılabilecekse kullanıcı, klavyedeki ctrl tuşuyla birlikte mouse imlecini
kullanabilir. Gereksinime göre JComboBox nesnesinde olduğu gibi ActionListener interface’i
kullanılarak seçili elemanların değişmesi izlenebilir ve kontrol edilebilir.
JList nesnesinin oluşturulması ve kullanımı aşağıdaki Örnek Uygulama 6.12’de gösterilmiştir.
Örnek Uygulama 6.12:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JButton;
6 import javax.swing.JFrame;
7 import javax.swing.JLabel;
8 import javax.swing.JList;
8 import javax.swing.JScrollPane;
10 import javax.swing.JTextArea;
11 import javax.swing.ListSelectionModel;
12 public class JListTest extends JFrame
13 {
14 private JLabel lblIlgiAlanlari;
15 private JList lstIlgiAlanlari;
83
84
Bölüm 6
16 private JScrollPane scrIlgiAlanlari;
17 private JTextArea txtSonuc;
18 private JButton btnGoster;
19 public JListTest()
20 {
21 super(“JListBox örneği”);
22 Container container = getContentPane();
23 container.setLayout(new FlowLayout());
24 seçin”);
lblIlgiAlanlari = new JLabel(“İlgi alanlarınızı
25 container.add(lblIlgiAlanlari);
26 String[] ilgiAlanlari = new String[]{“Spor”,
“Müzik”, “Edebiyat”, “Tiyatro”, “Resim”, “Sinema”};
27 lstIlgiAlanlari = new JList(ilgiAlanlari);
28 //lstIlgiAlanlari.setSelectionMode(ListSelectionModel.
SINGLE_
SELECTION);
29 //lstIlgiAlanlari.setSelectionMode(ListSelectionModel.
SINGLE_
INTERVAL_SELECTION);
30
Model.MULTIPLE_
lstIlgiAlanlari.setSelectionMode(ListSelection
INTERVAL_SELECTION);
31 lstIlgiAlanlari.setVisibleRowCount(4);
32 scrIlgiAlanlari = new JScrollPane(lstIlgiAlanlari);
33 container.add(scrIlgiAlanlari);
34 btnGoster = new JButton(“Göster”);
35 btnGoster.addActionListener
36 (
37 new ActionListener()
38 {
39 event)
public void actionPerformed(ActionEvent
40 {
41 txtSonuc.setText(“”);
42 Object[] seciliElemanlar =
lstIlgiAlanlari.getSelectedValues();
43 seciliElemanlar)
for (Object eleman :
44 {
45 toString() + “\n”);
46 }
47 }
48 }
49 );
txtSonuc.append(eleman.
Swing
50 container.add(btnGoster);
51 txtSonuc = new JTextArea();
52 container.add(txtSonuc);
53 setSize(200, 200);
54 setVisible(true);
55 }
56 public static void main(String[] args)
57 {
58 JListTest test = new JListTest();
59 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
60 }
61 }
Kodun açıklaması: Uygulamada ilgi alanlarını görüntülemek için bir tane JList nesnesi ve
bu nesneye scroll özelliği vermek için bir tane JScrollPane nesnesi kullandık. Kullanıcının bir
veya birkaç tane seçebileceği ilgi alanı veri kümesini tutmak için kullanılan string dizisi JList
nesnesinin yapıcı metoduna parametre olarak verildi. Jlist nesnesinin sahip olduğu setSelectionMode metodu, JList üzerinde aynı anda birden fazla elemanın seçilmesine izin verilip
verilmeyeceğini belirler. Tek bir elemanın seçilmesine izin vermek isteseydik SINGLE_SELECTION seçeneğini, belirli bir aralıkta olmak üzere birden fazla elemanın seçilmesine izin vermek
isteseydik SINGLE_INTERVAL_SELECTION seçeneğini kullanacaktık. Kullandığımız yapıda ise
belirli bir aralığa dahil olan veya olmayan birden fazla eleman seçilebilir. JList nesnesi varsayılan olarak sahip olduğu bütün elemanları alt alta gösterir. Eleman sayısı arttıkça nesne uygulama arayüzü üzerinde fazla yer kaplamaya başlayacağından scroll özelliğine ihtiyaç duyulabilir.
JList nesnesinin kendine ait bir scroll özelliği olmadığı halde JScrollPane bileşeni kullanılarak JList nesnesine scroll özelliği verilebilir. Koda dikkat edilirse JList nesnesinin doğrudan
Container nesnesine eklenmediği görülebilir. JList nesnesi JScrollPane nesnesine, JScrollPane nesnesi ise Container nesnesine eklenmiştir. JList nesnesinin setVisibleRowCount metodu scroll işleminden önce görüntülenecek eleman sayısını belirlemek amacıyla
kullanılır. Örnek uygulamada, dört tane elemanın görünür halde olmasına izin verilmiştir, diğer
elemanlara ancak scroll işlemiyle ulaşılabilir.
Örnek uygulamada, JList nesnesi üzerinde kullanıcının seçtiği elemanların değeri butona basıldıktan sonra JTextArea nesnesine yazılır. Butona her tıklandığında JTextArea bileşenin text
özelliği boş string değeri almaktadır, bunun sebebi sadece butona tıklandığı anda seçili olan
elemanların değerlerini görüntülemek istememizdir.
Uygulama çalıştırıldığında ve butona tıklandığında Şekil 21 ve Şekil 22’de olduğu gibi görünür.
Şekil 21: Uygulama çalıştırıldığında JTextArea
nesnesi görünmüyor.
Şekil 22: Üç tane eleman seçildi ve Göster butonuna tıklandı.
85
86
Bölüm 6
JList kontrolü sıklıkla kullanılabilecek bir kontrol olduğu için, birçok uygulamada karşımıza çıkabilecek bir arayüz oluşturalım ve iki tane JList kontrolü arasında veri aktarımı yapalım.
Örnek Uygulama 6.13:
1 import java.awt.Container;
2 import java.awt.FlowLayout;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.DefaultListModel;
6 import javax.swing.JButton;
7 import javax.swing.JFrame;
8 import javax.swing.JList;
9 import javax.swing.ListSelectionModel;
10 public class VeriAktarimi extends JFrame
11 {
12 private JList lstIlgiAlanlari;
13 private JList lstSecilmisIlgiAlanlari;
14 private JButton btnEkle;
15 private JButton btnCikar;
16 private DefaultListModel modelElemanlar;
17 private DefaultListModel modelSeciliElemanlar;
18 public VeriAktarimi()
19 {
20 super(“JListBox nesneleri arasında veri aktarımı”);
21 Container container = getContentPane();
22 container.setLayout(new FlowLayout());
23 modelElemanlar = new DefaultListModel();
24 modelSeciliElemanlar = new DefaultListModel();
25 modelElemanlar.addElement(“Spor”);
26 modelElemanlar.addElement(“Müzik”);
27 modelElemanlar.addElement(“Edebiyat”);
28 modelElemanlar.addElement(“Tiyatro”);
29 modelElemanlar.addElement(“Resim”);
30 modelElemanlar.addElement(“Sinema”);
31 lstIlgiAlanlari = new JList(modelElemanlar);
32 MULTIPLE_
lstIlgiAlanlari.setSelectionMode(ListSelectionModel.
INTERVAL_SELECTION);
33 container.add(lstIlgiAlanlari);
34 btnCikar = new JButton(“<<<<”);
35 btnCikar.setEnabled(false);
36 btnCikar.addActionListener
37 (
38 new ActionListener()
39 {
Swing
40 event)
public void actionPerformed(ActionEvent
41 {
42 Object[] seciliElemanlar =
lstSecilmisIlgiAlanlari.getSelectedValues();
43 seciliElemanlar)
for (Object eleman :
44 {
45 removeElement(eleman.toString());
modelSeciliElemanlar.
46 addElement(eleman.toString());
modelElemanlar.
47 }
48 == 0)
if(modelSeciliElemanlar.getSize()
49 {
50 51 }
52 if(modelElemanlar.getSize() != 0)
53 {
54 55 }
56 }
57 }
58 );
59 container.add(btnCikar);
60 btnEkle = new JButton(“>>>>”);
61 btnEkle.addActionListener
62 (
63 new ActionListener()
64 {
65 event)
public void actionPerformed(ActionEvent
66 {
btnCikar.setEnabled(false);
btnEkle.setEnabled(true);
67 Object[] seciliElemanlar =
lstIlgiAlanlari.getSelectedValues();
68 seciliElemanlar)
for (Object eleman :
69 {
70 removeElement(eleman.toString());
modelElemanlar.
71 addElement(eleman.toString());
modelSeciliElemanlar.
72 }
73 if(modelElemanlar.getSize() == 0)
74 {
87
88
Bölüm 6
75 btnEkle.setEnabled(false);
76 }
77 != 0)
if(modelSeciliElemanlar.getSize()
78 {
79 80 }
81 }
82 }
83 );
84 container.add(btnEkle);
btnCikar.setEnabled(true);
85 nlar);
lstSecilmisIlgiAlanlari = new JList(modelSeciliElema
86 lstIlgiAlanlari.setSize(100, 100);
87 container.add(lstSecilmisIlgiAlanlari);
88 setSize(200, 200);
89 setVisible(true);
90 }
91 public static void main(String[] args)
92 {
93 VeriAktarimi test = new VeriAktarimi();
94 test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
95 }
96 }
Kodun açıklaması: Uygulamada iki tane JList kontrolü ile iki tane JButton kontrolü kullandık. Bir önceki örnekte JList kontrolüne veri kaynağı olarak bir string dizisi verdiğimiz halde
bu örnekte DefaultListModel nesnesinden yararlandık. Bunun sebebi, DefaultListModel
bileşeninin uygulamanın çalışması sırasında veri ekleme ve çıkartma işlemlerini desteklemesidir.
Uygulama ilk çalıştığı sırada bütün ilgi alanları sol tarafta bulunan JList bileşenin içinde bulunur
ve sol tarafa veri aktarmayı sağlayan buton aktif değildir. Bir veya birden fazla ilgi alanı seçilip
sağ tarafa veri aktarmayı sağlayan butona tıklandığında, seçili elemanlar modelElemanlar nesnesinden removeElement metodu yardımıyla çıkartılır modelSeciliElemanlar nesnesine
addElement metodu yardımıyla eklenir. Bu işlemler JButton nesneleri için yazılan ve ActionListener interface’ini implement eden metodlar içinde gerçeklenir. Sol taraftaki JList bileşenin
içinde eleman kalmadığında sola aktarma işlemini gerçekleyen buton aktif olmaktan çıkar. JList
nesnelerine veri kaynağı olarak bağladığımız DefaultListModel nesnelerini event handler
metodları içinde tekrar bağlamaya gerek olmadığına dikkat edelim, bu durum kullandığımız nesnelerin referans tipinde olmasından kaynaklanır. DefaultListModel nesnelerinin barındırdığı
veriler değiştiğinde otomatik olarak JList görünümleri de değişir.
Uygulama çeşitli çalışma aşamalarında Şekil 23, Şekil 24 ve Şekil 25’te olduğu gibi görünür:
Swing
Şekil 23: Üç tane eleman seçili durumda, henüz
butona tıklanmış.
Şekil 24: Sağ tarafa aktarma işlemi yapıldıktan sonra iki buton
da aktif.
Şekil 25: Sol taraftaki bütün veriler sağ tarafa geçmiş, sağa aktarma butonu kullanılamıyor.
Mouse Event’lerinin Yönetilmesi:
Fare hareketleri ile tetiklenen event yapıları MouseListener ve MouseMotionListener interface’lerinin
implement edilmesiyle kontrol edilebilir. Bu interface’lerin içinde bulunan metodlar şu şekildedir:
MouseListener
mousePressed: Fare butonlarından birine basıldığı anda tetiklenir.
mouseClicked: Fare butonlarından birine basılıp bırakıldığında tetiklenir.
mouseReleased: Fare butonlarından birine basıldıktan sonra bırakıldığında tetiklenir.
mouseEntered: Fare imleci bir bileşenin alanına girdiğinde tetiklenir.
mouseExited: Fare imleci bir bileşenin alanını terk ettiğinde tetiklenir.
MouseMotionListener:
mouseDragged: Fare imleci bir bileşenin üzerindeyken butonlardan birine basılarak mouse hareket ettirildiğinde tetiklenir.
mouseMoved: Fare imleci bir bileşenin üzerindeyken fare hareket ettirildiğinde tetiklenir.
Fare ile ilgili event’leri kontrol eden bütün metodlar parametre olarak bir MouseEvent nesnesi
alırlar. Fare imlecinin x ve y koordinatları, hangi butona kaç kere basıldığı gibi bilgiler bu nesne
aracılığıyla alınır. Mouse event’leri herhangi bir bileşen için kaydedilebilir ve bu bileşen üzerinde
herhangi bir fare hareketi olduğunda ilgili event metodu tetiklenir. Interface mantığından dolayı
MouseListener ve MouseMotionListener interface’lerinden herhangi biri implement edildiğinde bu
interface’in içinde bulunan bütün metodlar implement edilmek zorundadır. Kullanılmayacak olan
metodların tanımları yapılarak içleri boş bırakılır.
Mouse event’lerini kontrol etmek amacıyla oluşturduğumuz uygulamanın kodları aşağıdaki gibidir.
89
90
Bölüm 6
1import java.awt.Container;
2import java.awt.FlowLayout;
3import java.awt.event.MouseEvent;
4import java.awt.event.MouseListener;
5import javax.swing.JFrame;
6import javax.swing.JLabel;
7import javax.swing.JTextArea;
8public class MouseYonetimi extends JFrame
9{
10
private JTextArea txtContainerEvent;
11
private JTextArea txtLabelEvent;
12
private JLabel lblAlan;
13
public MouseYonetimi()
14
{
15
super(“Mouse yönetimi”);
16
Container container = getContentPane();
17
container.setLayout(new FlowLayout());
18
container.addMouseListener(new
ContainerMouseListenerHandler());
19
lblAlan = new JLabel(“Mouse imlecini bu alanın
üzerine getirin”);
20
lblAlan.addMouseListener(new
JLabelMouseListenerHandler());
21
container.add(lblAlan);
22
txtContainerEvent = new JTextArea();
23
container.add(txtContainerEvent);
24
txtLabelEvent = new JTextArea();
25
container.add(txtLabelEvent);
26
setSize(200, 200);
27
setVisible(true);
28
}
29
private class ContainerMouseListenerHandler
implements MouseListener
30
{
31
public void mouseClicked(MouseEvent event)
32
{
33
txtContainerEvent.
append(ButonAdiAl(event.getButton()) + “ butona “ + event.
getClickCount() + “ kez basıldı ve bırakıldı\n”);
34
}
35
public void mousePressed(MouseEvent event)
36
{
37
txtContainerEvent.
append(ButonAdiAl(event.getButton()) + “ butona (“ + event.getX()
+ “,” + event.getY() + “) noktasında basıldı\n”);
38
}
Swing
39
public void mouseReleased(MouseEvent event)
40
{
41
txtContainerEvent.
append(ButonAdiAl(event.getButton()) + “ buton bırakıldı\n”);
42
}
43
public void mouseEntered(MouseEvent event)
44
{
45
}
46
public void mouseExited(MouseEvent event)
47
{
18
}
49
}
50
private class JLabelMouseListenerHandler implements
MouseListener
51
{
52
public void mouseEntered(MouseEvent event)
53
{
54
txtLabelEvent.append(“Mouse imleci
JLabel bölgesine girdi\n”);
55
}
56
public void mouseExited(MouseEvent event)
57
{
58
txtLabelEvent.append(“Mouse imleci
JLabel bölgesinden çıktı\n”);
59
}
60
public void mouseClicked(MouseEvent event)
61
{
62
}
63
public void mousePressed(MouseEvent event)
64
{
65
}
66
public void mouseReleased(MouseEvent event)
67
{
68
}
69
}
70
public static String ButonAdiAl(int butonNumarasi)
71
{
72
String butonAdi = “”;
73
if(butonNumarasi == MouseEvent.BUTTON1)
74
{
75
76
}
77
else if(butonNumarasi == MouseEvent.BUTTON2)
78
{
79
butonAdi = “Sol”;
butonAdi = “Orta”;
91
92
Bölüm 6
80
}
81
else if(butonNumarasi == MouseEvent.BUTTON3)
82
{
83
butonAdi = “Sağ”;
84
}
85
return butonAdi;
86
}
87
public static void main(String[] args)
88
{
89
MouseYonetimi test = new MouseYonetimi();
90
CLOSE);
test.setDefaultCloseOperation(JFrame.EXIT_ON_
91
}
92
}
Kodun açıklaması: Container nesnesi ve JLabel nesnesi için birer tane event handler sınıfı
oluşturduk. İki sınıf da MouseListener interface’ini implement ediyor. Kullanılmayan metodların
gövdelerini boş bırakarak interface yapısından kaynaklanan derleme hatalarını önlemiş olduk.
Uygulamada kullanılan statik ButonAdiAl metodu, tıklanan butonun numarasını alarak butona
bir isim vererek döndürür. Örneğin sol fare butonuna tıklandığında buton kodu olarak “1” değeri
oluşur, ButonAdiAl metodunu kullanarak “Sol” değeri döndürülür.
Container nesnesinin ilişkili olduğu ContainerMouseListenerHandler sınıfının içinde bulunan metodlar aşağıdaki işlevlere sahiptir:
mousePressed: Fare butonlarından biriyle formun üzerine tıklandığında hangi butona basıldığı
ve tıklanan pozisyonun x ve y değerleri JTextArea bileşenine eklenir.
mouseReleased: Tıklandıktan sonra bırakılan mouse butonunun adı JTextArea bileşenine eklenir.
mouseClicked: Tıklandıktan sonra bırakılan fare butonunun adı ve tıklanma sayısı JTextArea
bileşenine eklenir.
JLabel nesnesinin ilişkili olduğu JLabelMouseListenerHandler sınıfının içinde bulunan metodlar aşağıdaki işlevlere sahiptir:
mouseEntered: Fare imleci JLabel kontrolünün üzerine geldiğinde ikinci JTextArea nesnesine
bu bilgi yazılır.
mouseExited: Fare imleci JLabel kontrolünün bölgesinden çıktığında ikinci JTextArea nesnesine
bu bilgi yazılır.
Uygulama çalıştırıldıktan sonra mouse ile JLabel kontrolünün bölgesine girilip çıkıldığında ve
form üzerine farklı fare butonlarıyla çeşitli seferlerde tıklandığında, uygulama arayüzü aşağıdaki
gibi bir görünüm alır.
Swing
Java ortamının event altyapısı interface’ler üzerine kurulu olduğu için, içinde birden fazla metod
tanımı bulunan interface’lerin kullanılması durumunda gereksiz metodlar da implement edilmek
zorundadır. Bu durumun önüne geçmek için Adapter sınıfları oluşturulmuştur. Adapter sınıfları
ilgili interface’lerin bütün metodlarını gövdeleri boş olacak şekilde implement eder. Yeni oluşturulan event handler sınıfları Adapter sınıflarından türetilirse sadece gerekli event metodları override
edilebilir. Mouse event’lerinin kontrol edilmesi için MouseAdapter sınıfının temel sınıf olarak kullanıldığı bir uygulamanın kodları aşağıdadır.
1import java.awt.Container;
2import java.awt.FlowLayout;
3import java.awt.event.MouseAdapter;
4import java.awt.event.MouseEvent;
5import javax.swing.JFrame;
6import javax.swing.JTextArea;
7public class MouseAdapterTest extends JFrame
8{
9
private JTextArea txtContainerEvent;
10
public MouseAdapterTest()
11
{
12
super(“Mouse yönetimi”);
13
Container container = getContentPane();
14
container.setLayout(new FlowLayout());
15
container.addMouseListener(new
ContainerMouseHandler());
93
94
Bölüm 6
16
txtContainerEvent = new JTextArea();
17
container.add(txtContainerEvent);
18
setSize(200, 200);
19
setVisible(true);
20
}
21
private class ContainerMouseHandler extends
MouseAdapter
22
{
23
public void mouseClicked(MouseEvent event)
24
{
25
txtContainerEvent.append(event.
getButton() + “ numaralı butona “ + event.getClickCount() + “ kez
basıldı ve bırakıldı\n”);
26
}
27
}
28
public static void main(String[] args)
29
{
30
MouseAdapterTest test = new
MouseAdapterTest();
31
CLOSE);
32
}
33
}
test.setDefaultCloseOperation(JFrame.EXIT_ON_
Uygulama çalıştırılıp formun üzerine çeşitli mouse butonlarıyla tıklanırsa arayüz aşağıdaki gibi bir
görünüme sahip olur.
Klavye Event’lerinin Yönetilmesi
Kullanıcının klavye ile etkileşimi sonucunda oluşan event’ler KeyListener interface’ini implement
eden sınıfların oluşturulması ile kontrol edilir. KeyListener interface’inin içinde aşağıdaki metodlar
bulunur:
keyPressed: Klavyedeki herhangi bir tuşa basıldığında tetiklenir.
Swing
keyTyped: Aksiyon tuşu olmayan tuşlardan herhangi birine basıldığında tetiklenir. Aksiyon tuşları
ok tuşları, home, end, scroll lock gibi işlevsel özellikleri olan tuşlardır.
keyReleased: Herhangi bir buton bırakıldıktan sonra, yani keyTyped veya keyPressed event’inden
sonra tetiklenir.
Klavye event’lerinin kullanımını gösteren uygulamayı oluşturan kodlar aşağıda verilmiştir.
1import java.awt.Container;
2import java.awt.FlowLayout;
3import java.awt.event.KeyEvent;
4import java.awt.event.KeyListener;
5import javax.swing.JFrame;
6import javax.swing.JTextArea;
7public class KeyboardEventTest extends JFrame
8{
9
private JTextArea txtContainerEvent;
10
public KeyboardEventTest()
11
{
12
super(“Klavye yönetimi”);
13
Container container = getContentPane();
14
container.setLayout(new FlowLayout());
15
txtContainerEvent = new JTextArea();
16
txtContainerEvent.setEnabled(false);
17
container.add(txtContainerEvent);
18
this.addKeyListener(new
KeyboardEventHandler());
19
setSize(200, 200);
20
setVisible(true);
21
}
22
KeyListener
private class KeyboardEventHandler implements
23
{
24
public void keyPressed(KeyEvent event)
25
{
26
txtContainerEvent.append(“keyPressed\
tDeğer: “ + event.getKeyText(event.getKeyCode()) + “\n”);
27
}
28
public void keyReleased(KeyEvent event)
29
{
30
n\n”);
31
}
32
public void keyTyped(KeyEvent event)
33
{
txtContainerEvent.append(“keyReleased\t\
34
txtContainerEvent.append(“keyTyped\
tDeğer: “ + event.getKeyChar() + “\n”);
95
96
Bölüm 6
35
}
36
}
37
public static void main(String[] args)
38
{
39
KeyboardEventTest test = new
KeyboardEventTest();
40
CLOSE);
41
}
42
}
test.setDefaultCloseOperation(JFrame.EXIT_ON_
Kodun açıklaması: Kullanıcı klavyedeki herhangi bir tuşa bastığında keyPressed event’i tetiklenir. Basılan tuş aksiyon tuşu değilse keyTyped event’i de tetiklenir. Basılan tuş ne olursa olsun
keyReleased event handler metodu en son çalışır. keyPressed ve keyTyped event handler metodları; çalışan event’in adını ve basılan tuşa karşılık gelen karakter değerini JTextArea bileşenine
ekler. keyReleased event handler metodu ise tuşun bırakıldığını belirtir, hangi tuş üzerine işlem
yapıldığını bildirmez. Uygulama çalıştırıldıktan sonra sırasıyla q, home, F2, 7, alt, ctrl tuşlarına
basılırsa arayüz aşağıdaki gibi bir görünüme kavuşur.
Layout Yönetimi
Swing tabanlı arayüzler içeren Java uygulamalarında arayüze eklenen bileşenlerin form üzerindeki görünümleri layout yapılarıyla şekillendirilir.
FlowLayout: Bu görünümde arayüze eklenen bileşenler soldan sağa doğru eklendikleri sırada
görüntülenirler. Bütün örneklerimizde FlowLayout görünümünü kullandık. Dört tane JButton nesnesiyle bir tane JTextArea nesnesini FlowLayout biçiminde düzenlenmiş bir Swing arayüzüne
ekleyelim. Uygulamanın kodları aşağıda verilmiştir.
1import java.awt.Container;
2import java.awt.FlowLayout;
3import javax.swing.JButton;
Swing
4import javax.swing.JFrame;
5import javax.swing.JTextArea;
6public class FlowLayoutTest extends JFrame
7{
8
public FlowLayoutTest()
9
{
10
super(“BorderLayout”);
11
Container container = getContentPane();
12
FlowLayout layout = new FlowLayout();
13
container.setLayout(layout);
14
JButton btn1 = new JButton(“1. Buton”);
15
container.add(btn1);
16
JButton btn2 = new JButton(“2. Buton”);
17
container.add(btn2);
18
JButton btn3 = new JButton(“3. Buton”);
19
container.add(btn3);
20
JButton btn4 = new JButton(“4. Buton”);
21
container.add(btn4);
22
JTextArea txt = new JTextArea(“Metin alanı”);
23
container.add(txt);
24
setSize(300, 200);
25
setVisible(true);
26
}
27
public static void main(String[] args)
28
{
29
FlowLayoutTest test = new FlowLayoutTest();
30
CLOSE);
test.setDefaultCloseOperation(JFrame.EXIT_ON_
31
}
32
}
Bileşenler formun üzerine soldan sağa doğru eklenmiştir. Çalışma sırasında formun boyutu değiştirilirse arayüz kontrollerinin form üzerindeki yerleri de değişecektir. Formun iki farklı boyutu
için arayüzün görünümü aşağıda verilmiştir.
BorderLayout: JFrame sınıfından türeyen sınıfların varsayılan layout görünümüdür. Uygulama
arayüzü kuzey, güney, doğu, batı ve merkez olmak üzere beş parçaya ayrılır. Uygulamaya kon-
97
98
Bölüm 6
trol ekleme aşamasında hangi bölgeye ekleneceği belirtilir. Dört tane JButton nesnesi ile bir tane
JTextBox nesnesi içeren bir arayüzü BorderLayout biçiminde oluşturalım.
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
1public class BorderLayoutTest extends JFrame
2{
3
public BorderLayoutTest()
4
{
5
super(“BorderLayout”);
6
Container container = getContentPane();
7
BorderLayout layout = new BorderLayout(10, 10);
8
container.setLayout(layout);
9
JButton btnNorth = new JButton(“Kuzey”);
10
container.add(btnNorth, BorderLayout.NORTH);
11
JButton btnSouth = new JButton(“Güney”);
12
container.add(btnSouth, BorderLayout.SOUTH);
13
JButton btnEast = new JButton(“Doğu”);
14
container.add(btnEast, BorderLayout.EAST);
15
JButton btnWest = new JButton(“Batı”);
16
container.add(btnWest, BorderLayout.WEST);
17
bölge”);
JTextArea txtCenter = new JTextArea(“Merkez
18
container.add(txtCenter, BorderLayout.CENTER);
19
setSize(300, 200);
20
setVisible(true);
21
}
22
public static void main(String[] args)
23
{
24
BorderLayoutTest test = new
BorderLayoutTest();
25
CLOSE);
26
}
27
}
test.setDefaultCloseOperation(JFrame.EXIT_ON_
JButton kontrolleri arayüzün kuzey, güney, doğu ve batı bölgelerine, JTextArea bileşeni ise merkez bölgesine eklenmiştir. Uygulama çalıştırıldığında aşağıdaki gibi görünür.
Swing
GridLayout: GridLayout biçimi, container’ı satırlar ve sütunlardan oluşan bir grid şeklinde düzenler. GridLayout şeklinde düzenlenmiş bir arayüzdeki bütün bileşenlerin boyutu aynı olur. GridLayout biçiminde düzenlenmiş bir Swing arayüzünü aşağıdaki kod bloğuyla oluşturabiliriz.
1import java.awt.Container;
2import java.awt.GridLayout;
3import javax.swing.JButton;
4import javax.swing.JFrame;
5import javax.swing.JTextArea;
6public class GridLayoutTest extends JFrame
7{
8
public GridLayoutTest()
9
10
{
super(“GridLayout”);
11
Container container = getContentPane();
12
GridLayout layout = new GridLayout(2, 3);
13
container.setLayout(layout);
14
JButton btn1 = new JButton(“1. Buton”);
15
container.add(btn1);
16
JButton btn2 = new JButton(“2. Buton”);
17
container.add(btn2);
18
JButton btn3 = new JButton(“3. Buton”);
19
container.add(btn3);
20
JButton btn4 = new JButton(“4. Buton”);
21
container.add(btn4);
22
JTextArea txt = new JTextArea(“Metin alanı”);
23
24
25
container.add(txt);
setSize(300, 200);
setVisible(true);
26
27
}
public static void main(String[] args)
28
29
{
GridLayoutTest test = new GridLayoutTest();
30
CLOSE);
31
test.setDefaultCloseOperation(JFrame.EXIT_ON_
32
}
}
99
100
Bölüm 6
Uygulama çalıştırıldığında aşağıdaki gibi bir arayüz oluşur:
Bunların dışında daha az kullanılan BoxLayout, CardLayout ve GridBagLayout görünümleri de
vardır.
7
JDBC
7 JDBC
• Veritabanı Bağlantısının Kurulması
• Veri Değiştirme Komutları (insert, update,
delete)
• Veri Sorgulama Komutları (Select)
• Parametreli SQL İfadelerinin Çalıştırılması
• Stored Procedure’lerin Çalıştırılması
JDBC
Java uygulamaları üzerinden veri kaynaklarını bulmak ve bulunan kaynaklara bağlanarak bu kaynaklar üzerinde çeşitli sorguları çalıştırmak için JDBC adı verilen Java API’si kullanılır. JDBC,
.Net ortamındaki ADO.Net yapısının Java platformundaki karşılığıdır. JDBC, platform bağımsızlığını sağlayabilmek için, ortamdaki veri kaynaklarına bağlanmak amacıyla kullanılan sürücüleri
çalışma zamanında tespit edebilen bir sürücü yönetim sistemine(Driver Manager) sahiptir. Veri
kaynaklarına bağlanmadan önce sürücülerin yüklenmesini sağlamak için Class.forName()
metodu gereken parametreler kullanılarak çağrılır.
ODBC sürücüsüne sahip olan veri kaynaklarına bağlanmak için JDBC-ODBC köprüsü kullanılır.
Sürücüler bulunduktan sonra ODBC üzerinde kayıtlı bulunan herhangi bir veri kaynağına bağlanılabilir. Windows tabanlı işletim sistemleri üzerinde bulunan bir veritabanı yönetim sistemi yazılımındaki bir veritabanına bağlanmak için, bu veritabanının ODBC kaynaklarına eklenmesi gerekir.
Bu işlem denetim masasında veya yönetimsel araçlarda bulunan veri kaynakları (ODBC) seçeneneği kullanılarak gerçekleştirilebilir.
Bilgisayarımızda bulunan Microsoft SQL Server 2005 veritabanı sunucusu üzerinde dört tablodan
oluşan AlisveriSitesi adında bir veritabanı oluşturarak uygulamalarımızı bu veritabanı üzerinde
çalıştıralım. AlisverisSitesi veritabanını oluşturmak ve sahip olduğu tabloları oluşturmak için kullanılacak SQL ifadeleri ve veritabanının diyagramı Şekil 1’de gösterilmiştir.
Şekil 1
Örnek Uygulama 7.1:
1 create database AlisverisSitesi
2 use AlisverisSitesi
3 create table Urun
4 (
5 urunID int primary key identity(1, 1),
6 urunAdi varchar(20),
7 fiyat money
8 )
9 create table Musteri
104
Bölüm 7
10 (
11 musteriID int primary key identity(1, 1),
12 ad varchar(20),
13 soyad varchar(30),
14 )
15 create table Siparis
16 (
17 siparisID int primary key identity(1, 1),
18 musteriID int foreign key references Musteri(musteriID),
19 siparisTarihi smalldatetime
20 )
21 create table SiparisDetay
22 (
23 siparisID int foreign key references Siparis(siparisID),
24 urunID int foreign key references Urun(urunID),
25 miktar int
26 )
Veritabanımızı oluşturduktan sonra denetim masasından veya yönetimsel araçlardan veri kaynakları (ODBC) ayarlarını açalım. Java üzerinden herhangi bir veri kaynağına bağlanmadan önce
kullanacağımız veritabanı sunucusunu ve veritabanını System DSN menüsünden kayıt edeceğiz.
System DSN menüsü ilk açıldığında Şekil 2’dekine benzer bir görünüme sahip olacaktır.
Şekil 2
Yeni bir veri kaynağı eklemek için Add butonuna tıklayalım. Karşımıza çıkan pencerede, bağlanmak istediğimiz veri kaynağını seçtikten sonra Finish butonuna tıklayarak veri kaynağımızla ilgili
JDBC
ek bilgiler istenir. Microsoft SQL Server veritabanı sunucusu kullandığımız için en altta bulunan
SQL Server seçeneğini seçmeliyiz.
Şekil 3
Bir sonraki pencerede, veri kaynağımıza vereceğimiz ismi ve kullanılacak veritabanı sunucusunun adını veya adresini yazdıktan sonra Next butonuna tıklayalım. Veri kaynağı ile ilgili ayarlar
Şekil 4’te görülebilir.
Şekil 4
Veritabanı sunucumuz belirlendikten sonra, bu sunucuya bağlanmak için kullanılacak olan kimlik
bilgilerinin girileceği ekran karşımıza çıkar. SQL Server veritabanı sunucusuna bağlanmak için
Windows Authentication veya SQL Authentication kullanabiliriz. Windows Authentication kullanmamız durumunda kullanıcı adı ve şifre bilgileri istenmez, veritabanı sunucusuna bağlanmak
için sisteme giriş yapmış olan Windows kullanıcı hesabı kullanılır. Bahsedilen ayarlar Şekil 5’te
görülebilir.
105
106
Bölüm 7
Şekil 5
SQL Server 2005 veritabanı sunucusuna bağlanmak için Windows NT Authentication modunu
seçtikten sonra Next butonuna tıklayın. AlisverisSitesi adını verdiğimiz sürücüyle bağlanılacak
olan varsayılan veritabanını en üstteki change default database to checkbox’ı yardımıyla belirleyebiliriz. AlisverisSitesi veritabanını varsayılan veritabanı olarak seçtikten sonra Next butonuna
ve bir sonraki pencerede Finish butonuna tıklayın. Son üç aşamada karşımıza çıkan ekran görüntüleri aşağıdadır.
Şekil 6
JDBC
Şekil 7
Finish butonuna tıkladıktan sonra ODBC veri kaynağının başarıyla eklendiğini belirten bir mesaj
aldık. ODBC kaynağı eklendikten sonra Şekil 8’de gösterilen Test Data Source butonuna tıklayarak veritabanı bağlantımızın doğru çalışıp çalışmadığını kontrol edin. Şekil 9’da görülen mesaj,
veri kaynağına başarıyla bağlandığımızı gösterir.
Şekil 8
107
108
Bölüm 7
Şekil 9
Veritabanı Bağlantısının Kurulması
Veritabanına bağlanmak için kullanılacak ODBC kaynağını işletim sistemine ekledikten sonra
Java ortamı üzerinden AlisverisSitesi veritabanına bağlanmaya çalışalım. Veri kaynağına bağlanmak için aşağıdaki adımların gerçekleşmesi gerekir:
1� İşletim sistemi üzerinde bulunan JDBC sürücüsünün Class.forName() metodu yardımıyla
bulunması.
2. DriverManager sınıfında bulunan getConnection() metodu ile veritabanı bağlantısının
sağlanması.
Class.forName metodunun uygulamada kullanılabilmesi için, bu metodu çağıran metodun
ClassNotFoundException tipinden hata fırlatabilmesi gerekir. Benzer bir şekilde DriverManager.getConnection() metodunu çağıran metodun SQLException tipinden hata fırlatabilmesi gerekir. İki metod çağrısını da uygulamanın main metodundan yapacağımız için main metodumuz bu iki hatayı da fırlatabilecek şekişlde oluşturulur. Aşağıdaki kodu yazıp çalıştırdığımızda
herhangi bir mesaj almazsak ODBC kaynağına bağlantı kurmayı başardık demektir.
Örnek Uygulama 7.2:
1 import java.sql.Connection;
2 import java.sql.DriverManager;
3 import java.sql.SQLException;
4 public class VeritabaniBaglantisi
5 {
6 public static void main(String[] args) throws
ClassNotFoundException, SQLException
7 {
8 try
9 {
10 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
11 Connection baglanti = DriverManager.
getConnection(“jdbc:odbc:AlisverisSites1i”);
JDBC
12 }
13 catch (Exception e)
14 {
15 16 }
17 }
System.out.println(e.getMessage());
18 }
Eğer bağlantı kurma aşamasında SQLException veya ClassNotFoundException oluşursa
aşağıdaki iki hata mesajından birini alırız.
[Microsoft][ODBC Driver Manager] Data source name not found and no
default driver specified
sun.jdbc.ODBC.JdbcOdbcDriver
JDBC altyapısı kullanılarak veritabanı sunucularının desteklediği komutlar çalıştırılabilir. SQL
Server veritabanı sunucusu üzerinde veri değiştirme komutları (insert, update, delete), veri
tanım komutları(create, alter, drop) ve sorgu komutları (select) çalıştırılarak uygulamanın
ihtiyaçlarına göre bir veri erişim altyapısı oluşturulması sağlanabilir.
Veri kaynağı üzerinde çalıştırılacak ifadeler, Connection nesnesi aracılığıyla oluşturulur. Connection nesnesinin createStatement() metodu ile oluşturulan Statement nesnesi veritabanına
SQL ifadelerini göndermek amacıyla kullanılır. Statement nesnesi oluştuktan sonra, bu nesnenin
sahip olduğu executeXxx metodları ile SQL ifadeleri veritabanı sunucusu üzerinde çalıştırılır.
Connection nesnesini sahip olduğı metodlarla Statement tipinden başka tiplerde ifadeler de oluşturulabilir. (Örneğin BLOB, XML..)
Veri Değiştirme Komutları (insert, update, delete)
JDBC kütüphanesi kullanılarak veritabanı üzerinde insert, update, delete gibi veri ile alakalı komutlar çalıştırmak için genellikle Statement nesnesinin executeUpdate komutları kullanılır.
executeUpdate komutları, veritabanı üzerinde çalıştırılan ifadeden etkilenen kayıt sayısını tam
sayı değeri olarak döndürür ve ADO.Net mimarisinde bulunan Command nesnesinin ExecuteNonQuery metoduna benzerlik gösterir.
Örnek Uygulama 7.3’de verdiğimiz kod bloğunda veritabanına üç tane müşteri ve beş tane ürün
eklenmektedir. Tablolarda bulunan xxxID alanları identity olarak tanımlandığından, değerleri otomatik olarak ve birer birer artarak verilir. Bu sebepten dolayı insert ifadesinin içinde xxxID alanlarının bulunması hata oluşmasına neden olur.
Örnek Uygulama 7.3:
1 import java.sql.Connection;
2 import java.sql.DriverManager;
3 import java.sql.SQLException;
4 import java.sql.Statement;
5 public class VeritabaniBaglantisi
6 {
7 public static void main(String[] args) throws
ClassNotFoundException, SQLException
8 {
9 try
109
110
Bölüm 7
10 {
11 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
12 Connection dbConnection = DriverManager.
getConnection(“jdbc:odbc:AlisverisSitesi”);
13 Statement staInsert = dbConnection.
createStatement();
14 staInsert.executeUpdate(“INSERT INTO
Musteri(ad, soyad) VALUES (‘Yalçın’, ‘Kaya’)”);
15 staInsert.executeUpdate(“INSERT INTO
Musteri(ad, soyad) VALUES (‘Erkut’, ‘Kutlar’)”);
16 staInsert.executeUpdate(“INSERT INTO
Musteri(ad, soyad) VALUES (‘Hasan’, ‘Polat’)”);
17 staInsert.executeUpdate(“INSERT INTO
Urun(urunAdi, fiyat) VALUES (‘1GB Ram’, 40)”);
18 staInsert.executeUpdate(“INSERT INTO
Urun(urunAdi, fiyat) VALUES (‘3 GHz CPU’, 80)”);
19 staInsert.executeUpdate(“INSERT INTO
Urun(urunAdi, fiyat) VALUES (‘2 GB USB Bellek’, 30)”);
20 staInsert.executeUpdate(“INSERT INTO
Urun(urunAdi, fiyat) VALUES (‘256 MB Ekran Kartı’, 20)”);
21 staInsert.executeUpdate(“INSERT INTO
Urun(urunAdi, fiyat) VALUES (‘DVD Writer’, 45)”);
22 staInsert.close();
23 }
24 catch (Exception e)
25 {
26 27 }
28 }
System.out.println(e.getLocalizedMessage());
29 }
Kodun açıklaması: JDBC sürücüsü çalışma zamanında bulunduktan sonra daha önce oluşturulan AlisverisSitesi isimli ODBC kaynağı aracılığıyla AlisverisSitesi veritabanı üzerinde insert
ifadeleri çalıştırıldı. Statement nesnesinin işi bittikten sonra kapatılması, alınan sistem ve veritabanı kaynaklarının geri verilmesini sağlar. Uygulamanın çalışması aşamasında bir hata oluşmazsa arayüz üzerinde herhangi bir mesaj oluşmaz. Gerçek bir uygulamada ürün ve müşteri bilgileri
Java kodunun içinde girilmez, web veya işletim sistemi ortamında çalışan bir kullanıcı arayüzü
aracılığıyla kullanıcıdan alınır. İlerleyen sayfalarda, Swing görsel programlama kütüphanesini kullanarak benzer bir uygulama geliştireceğiz.
Veri Sorgulama Komutları (Select)
Select komutunun Java ortamından veritabanı sunucusu üzerinde çalıştırılması için benzer nesneler oluşturulur. İşletim sistemi üzerinde bulunan JDBC sürücüsüne ulaşıldıktan sonra ODBC
kaynağına bağlanılır, bu bağlantı üzerinden Statement nesnesi oluşturulur ve Statement nesnesinin executeXxx komutlarından biri çalıştırılır. Veritabanından tek bir tam sayı değişkeni yerine
birden fazla satır ve sütündan oluşabilen bir değer kümesi döndüğünden, select ifadelerinin
çalıştırılması insert, update, delete ifadelerinin çalıştırılmasından farklıdır. executeXxx komutları select ifadelerini veritabanına göndermek için kullanıldığında geriye bir sonuç kümesi
(result set) döndürür. Bu sonuç kümesi veri kaynağına bağlı olarak çalışan tek yönlü bir işaretçi
JDBC
yapısıdır ve ADO.Net yapısında bulunan xxxDataReader sınıflarının Java ortamındaki karşılığıdır. Sonuç kümesi alındıktan sonra kümenin sonuna gelene kadar okuma işlemi tekrar edilir ve
bu işlem döngüler aracılığıyla gerçekleştirilir.
AlisverisSitesi veritabanında bulunan Urun tablosundaki verileri okuyalım:
Örnek Uygulama 7.4:
1 import java.sql.Connection;
2 import java.sql.DriverManager;
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5 import java.sql.Statement;
6 public class Urunler
7 {
8 public static void main(String[] args) throws
ClassNotFoundException, SQLException
9 {
10 try
11 {
12 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
13 Connection dbConnection = DriverManager.
getConnection(“jdbc:odbc:AlisverisSitesi”);
14 Statement staSelect = dbConnection.
createStatement();
15 ResultSet resultSet = staSelect.
executeQuery(“SELECT urunID, urunAdi, fiyat FROM Urun”);
16 while(resultSet.next())
17 {
18 getInt(“urunID”));
System.out.print(resultSet.
19 System.out.print(“\t” + resultSet.
getString(“urunAdi”) + “\t\t”);
20 getDouble(“fiyat”));
System.out.println(resultSet.
21 }
22 staSelect.close();
23 }
catch (Exception e)
{
}
}
System.out.println(e.getLocalizedMessage());
}
Kodun açıklaması: Daha önceki uygulamada yaptığımız gibi JDBC sürücüsünü bulduktan sonra
ODBC veri kaynağına bağlantıyı kurduk ve bağlantı üzerinden Statement nesnesini oluşturduk.
executeUpdate() metodu yerine executeQuery() metodunu yazdığımızda geri dönüş tipinin ResultSet olduğunu görürür. Bu durum, veritabanı sunucusu üzerinde çalışan ifadenin bir
değer kümesi döndürebileceğini gösterir. executeQuery metoduna parametre olarak “SELECT
111
112
Bölüm 7
urunID, urunAdi, fiyat from Urun” şeklindeki SQL ifadesini yazdığımızdan dolayı executeQuery metodu Urun tablosundaki bütün verileri sorgulayarak ResultSet cinsinden bir nesne
oluşturur ve bu nesnenin veri kaynağına doğrudan bağlı olmasını sağlar. Bu noktadan sonra veri
kaynağına bağlı durumda olan ResultSet nesnesi ile veriler üzerine tek yönlü ve salt okunur bir
biçimde gezebilirir.
Uygulama çalıştığı zaman Örnek Uygulama 7.5’teki gibi bir çıktı alınır:
Örnek Uygulama 7.5:
11GB Ram
40.0
23 GHz CPU
80.0
30.0
4256 MB Ekran Karti
20.0
5DVD Writer 45.0
32 GB USB Bellek
Parametreli SQL İfadelerinin Çalıştırılması
JDBC kütüphanesi komutlarını kullanarak parametreli SQL ifadeleri de çalıştırılabilir. ADO.Net
kütüphanesi kullanılarak çalıştırılan SQL sorgularında “@” karakteri ile başlayan parametrelerin
tanımlanması gibi JDBC mimarisinde “?” karakteri ile parametreler oluşturulur. ADO.Net’te olduğu gibi parametre adının belirtilmesine gerek yoktur, parametreler sırayla eklenirse sorgu doğru
şekilde çalışır. Parametresiz SQL ifadelerinin çalıştırılması için Statement nesnesi kullanılmasına
karşın parametreli SQL ifadelerinin çalıştırılması için PreparedStatement nesnesi kullanılır.
Daha önce bahsettiğimiz gibi veritabanına gönderilen ve sorguların sınırlandırılmasını sağlayan
veriler kullanıcı arayüzünden alınabilir. Kullanıcı tarafından veri girişinin yapıldığı durumlarda kötü
niyetli kullanıcıların sisteme zarar vermesini engellemek için parametrik sorguların oluştulması
gerekir.
Bir SQL ifadesinin parametreli olarak Java ortamında çalıştırılmasını ve sorgu sonucunda dönen
değer kümesinin ekranda gösterilmesini sağlayan kod Örnek Uygulama-7.6’da gösterilmiştir.
Örnek Uygulama 7.6:
1 import java.sql.Connection;
2 import java.sql.DriverManager;
3 import java.sql.PreparedStatement;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 public class ParametreliSqlSorgusu
7 {
8 public static void main(String[] args) throws
ClassNotFoundException, SQLException
9 {
9 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
10 Connection dbConnection = DriverManager.getConnection(“jdbc:
odbc:AlisverisSitesi”);
11 PreparedStatement statement = dbConnection.
prepareStatement(“SELECT * FROM Urun WHERE fiyat > ? AND fiyat <
?”);
12 statement.setDouble(1, 20);
13 statement.setDouble(2, 60);
JDBC
14 ResultSet resultSet = statement.executeQuery();
15 while(resultSet.next())
16 {
17 System.out.println(resultSet.getInt(“urunID”) + “
“ + resultSet.getString(“urunAdi”) + “ “ + resultSet.
getDouble(“fiyat”));
18 }
19 statement.close();
20 }
21 }
Kodun Açıklaması: Select ifadesi iki tane parametre ile sınırlandırılarak belirli bir fiyat aralığındaki ürünlerin getirilmesi sağlanmıştır. PreparedStatement nesnesi, Connection nesnesi
tarafından oluşturulur. Select ifadesinin içinde bulunan “?” karakterleri parametrelerin bulunacağı yerlerdir ve bu parametre değerleri PreparedStatement nesnesinin setXxx metodları ile
verilir. Örneğimizde iki tane fiyat parametresine değer vermek amacıyla PreparedStatement
nesnesinin setDouble metodunu kullandık. setXxx metodlarının ilk parametresi, veritabanına
gönderilecek sorgunun içinde bulunan parametresinin indeksini belirtir. “SELECT * FROM Urun
WHERE fiyat > ? AND fiyat < ?” sorgusunda ilk parametre değerini 20, ikinci parametre
değerini 60 olarak verdik. Bu aşamadan sonra, parametresiz ifadelerin çalıştırılmasında yaptığımız gibi PreparedStatement nesnesinin executeXxx metodlarından birini çalıştırarak çalıştırılacak ifadeyi veritabanı sunucusuna göndeririz. Örnekte Select ifadesi kullandığımız için,
dönen veri kümesini ResultSet nesnesi aracılığıyla aldık ve ekrana bastık. Uygulama çalıştırıldığında oluşan ekran çıktısı Örnek Uygulama 7.7’deki gibidir:
Örnek Uygulama 7.7:
1 1GB Ram 40.0
3 2 GB USB Bellek 30.0
5 DVD Writer 45.0
Stored Procedure’lerin Çalıştırılması
Stored procedure’ler veritabanı sunucuları üzerinde bulunan ve farklı veritabanı yönetim sistemi
yazılımlarında farklı biçimlerde oluşturulan prosedürel programlama yapılarıdır. Genelde iş mantığının bir bölümünün uygulamadan alınıp veritabanı sunucusuna aktarılması amacıyla kullanılırlar. Stored procedure yapıları parametre kullanılarak çalıştırıldığı için ve yetkilendirme seviyeleri
veritabanı tablolarından farklı olarak ayarlanabildiği için uygulama güvenliğinin arttırılmasını da
sağlar. JDBC kütüphanesi ile stored procedure’leri çalıştırmak için Connection nesnesi üzerinden
bir CallableStatement nesnesi oluşturulur.
Örnek veritabanımızda bulunan ürün ve müşteri tablolarına veri eklemek amacıyla kullanmak için
iki tane stored procedure oluşturalım.
Örnek Uygulama 7.8:
1 CREATE PROC insUrun
2 @urunAdi VARCHAR(20),
3 @fiyat MONEY
4 AS
5 INSERT INTO Urun (urunAdi, fiyat)
6 VALUES (@urunAdi, @fiyat)
7 GO
113
114
Bölüm 7
8 CREATE PROC insMusteri
9 @ad VARCHAR(20),
10 @soyad VARCHAR(30)
11 AS
12 INSERT INTO Musteri (ad, soyad)
13 VALUES (@ad, @soyad)
14 GO
Örnek Uygulama 7.8’de verdiğimiz SQL ifadeleri ile oluşturulan stored procedure’leri çalıştırmak
için aşağıdaki gibi bir Java uygulaması oluşturabiliriz.
Örnek Uygulama 7.9:
1 import java.sql.CallableStatement;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.SQLException;
5 public class StoredProcedure
6 {
7 public static void main(String[] args) throws
ClassNotFoundException, SQLException
8 {
9 try
10 {
11 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
12 Connection dbConnection = DriverManager.
getConnection(“jdbc:odbc:AlisverisSitesi”);
13 CallableStatement staInsertUrun =
dbConnection.prepareCall(“{call insUrun(?, ?)}”);
14 Notebook”);
staInsertUrun.setString(1, “Toshiba M70
15 staInsertUrun.setDouble(2, 1200);
16 int rowCount = staInsertUrun.executeUpdate();
17 if(rowCount == 0)
18 {
19 20 }
21 else
22 {
23 24 }
System.out.println(“Ürün eklenemedi”);
System.out.println(“Ürün eklendi”);
25 CallableStatement staInsertMusteri =
dbConnection.prepareCall(“{call insMusteri(?, ?)}”);
26 staInsertMusteri.setString(1, “Ahmet”);
27 staInsertMusteri.setString(2, “Balaban”);
28 rowCount = staInsertUrun.executeUpdate();
29 if(rowCount == 0)
JDBC
30 {
31 32 }
33 else
34 {
35 System.out.println(“Müşteri eklenemedi”);
System.out.println(“Müşteri eklendi”);
36 }
37 staInsertUrun.close();
38 staInsertMusteri.close();
39 }
40 catch(Exception e)
41 {
42 43 44 System.out.println(e.getMessage());
}
}
45 }
Kodun Açıklaması: Veritabanı bağlantısının sağlanması için gereken ayarları yaptıktan sonra
stored procedure çalıştırmak için Connection nesnesi üzerinden iki tane CallableStatement nesnesi oluşturduk. Bu nesnelerden biri insUrun stored procedure’ünün çalıştırılması için,
diğeri insMusteri stored procedure’ünün çalıştırılması için gerekli. Stored procedure çağrısının
yapılması için “{call sp_name(?, ..)}” ifadesi kullanılır. Bu ifadede sp_name metni yerine
çalıştırılacak stored procedure’ün adı yazılır. Stored procedure’ü çalıştırmak için gereken parametreler daha önce yaptığımız gibi Statement nesnelerinin setXxx metodları kullanılarak verilir.
insMusteri prosedürünü çalıştırmak için müşterinin ad ve soyad değerlerini, insUrun prosedürünü çalıştırmak için ürünün ad ve fiyat değerlerini parametre olarak verdikten sonra ifadeleri
executeUpdate metodu ile çalıştırdık ve etkilenen kayıt sayısını kontrol ederek ürün ve müşteri
verilerinin veritabanına eklenip eklenmediği bilgisini ekrana bastık. Uygulama çalıştırıldığı zaman
Örnek Uygulama 7.10’da olduğu gibi bir çıktı alınırsa ürün ve müşteri bilgilerini başarıyla ekledik
demektir.
Örnek Uygulama 7.10:
1 Ürün eklendi
2 Müşteri eklendi
Veritabanı Erişimi için Bileşen Oluşturulması:
Veritabanı sunucuları üzerinde çalıştırılacak metodlar merkezi bir package altında toplanırsa,
veritabanı sunucusu üzerinde herhangi bir değişiklik olması durumunda karşılaşılacak bakım
maliyeti düşürülebilir. Bunun yanında uygulamanın geliştirilmesi aşamasında veritabanı konfigürasyonu ve çeşitli komutların veritabanı sunucusu üzerinde çalıştırılması daha kolay bir şekilde
gerçekleştirilebilir. Bu amaçla kullanılabilecek temel bir veri erişim bileşeni oluşturalım.
115
116
Bölüm 7
Şimdiye kadar kullandığımız veritabanı erişim yöntemlerini bir sınıf altında toplayabiliriz. Oluşturacağımız bileşenin farklı veritabanı tabloları ile kullanılabilmesi ve geri dönüş değerlerini temel veri
tipleri şeklinde döndürebilmesi gerekir. Alt yapıda kullanılan veritabanı sunucusunun değişmesi
riskinin olduğu senaryolarda, veritabanı sistemine bağımlı olmayan veri tiplerinin kullanılması büyük avantaj sağlayacaktır.
Veri erişim bileşeninin kodu aşağıda verilmiştir. Bileşen ayrı bir Java paketi (package) şeklinde
oluşturulmuştur ve bu bileşeni başka bir yerde kullanmak için import anahtar kelimesi ile uygulamaya eklemek gerekir.
Örnek Uygulama 7.11:
1 package dbAccess;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.ResultSetMetaData;
7 import java.sql.SQLException;
8 import java.sql.Statement;
9 import java.util.ArrayList;
10 public class DbConnection
11 {
12 private Connection connection;
13 public DbConnection() throws SQLException,
ClassNotFoundException
14 {
15 Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
16 connection = DriverManager.getConnection(“jdbc:odbc:
AlisverisSitesi”);
17 }
18 public int NonQuery(String commandText) throws
SQLException
19 {
20 Statement stNonQuery = connection.createStatement();
21 ;
int rowCount = stNonQuery.executeUpdate(commandText)
22 stNonQuery.close();
23 return rowCount;
24 }
25 public int NonQuery(String commandText, Object[]
parameterValues) throws SQLException
26 {
27 PreparedStatement pstNonQuery = connection.prepareSt
atement(commandText);
28 for (int parameterIndex = 0; parameterIndex <
parameterValues.length; parameterIndex++)
29 {
JDBC
30 pstNonQuery.setObject(parameterIndex + 1,
parameterValues[parameterIndex]);
31 }
32 int rowCount = pstNonQuery.executeUpdate();
33 pstNonQuery.close();
34 return rowCount;
35 }
36 public ArrayList ReturnArrayList(String commandText)
throws SQLException
37 {
38 ArrayList result = new ArrayList();
39 Statement stQuery = connection.createStatement();
40 xt);
ResultSet resultSet = stQuery.executeQuery(commandTe
41 ResultSetMetaData metaData = resultSet.
getMetaData();
42 int columnCount = metaData.getColumnCount();
43 while(resultSet.next())
44 {
45 String[] row = new String[columnCount];
46 for(int columnIndex = 0; columnIndex <
columnCount; columnIndex++)
47 {
48 row[columnIndex] = resultSet.
getString(columnIndex + 1).toString();
49 }
50 result.add(row);
51 }
52 stQuery.close();
53 return result;
54 }
55 public ArrayList ReturnArrayList(String commandText,
Object[] parameterValues) throws SQLException
56 {
57 ArrayList result = new ArrayList();
58 PreparedStatement pstQuery = connection.prepareState
ment(commandText);
59 for (int parameterIndex = 0; parameterIndex <
parameterValues.length; parameterIndex++)
60 {
61
pstQuery.setObject(parameterIndex + 1, paramet
erValues[parameterIndex]);
62 63 }
ResultSet resultSet = pstQuery.executeQuery();
64 ResultSetMetaData metaData = resultSet.
getMetaData();
117
118
Bölüm 7
65 int columnCount = metaData.getColumnCount();
66 while(resultSet.next())
67 {
68 String[] row = new String[columnCount];
69 for(int columnIndex = 0; columnIndex <
columnCount; columnIndex++)
70 {
71
row[columnIndex] = resultSet.
getString(columnIndex + 1).toString();
71 }
result.add(row);
72 73 }
74 pstQuery.close();
75 return result;
76 }
77 }
Kodun açıklaması: Veri erişim mantığını uygulamadan ayırmak için dbAccess isimli bir package içinde DbConnection isimli bir sınıf oluşturduk. Geri dönüşsüz sorguları çalıştırmak için iki
tane metod ve değer kümesi döndüren sorguları çalıştırmak için iki tane metod yazdık. İki işlev
için de ikişer tane metod yazmamızın sebebi SQL ifadelerini çalıştırırken parametre eklenmesine
olan sağlamaktır. Sınıfta bulunan nitelikleri ve metodları kısaca açıklayalım:
Connection connection: Veritabanına bağlanmak amacıyla kullanılan nesne. Bütün Statement nesneleri Connection nesnesi tarafından oluşturulur.
DbConnection(): DbConnection sınıfının yapıcı metodu. JDBC sürücüsünü bulmak ve Connection nesnesine ilk değerini vermek için kullanılır.
int NonQuery(String commandText): Parametresiz ve veri kümesi döndürmeyen SQL ifadelerinin çalıştırılması amacıyla kullanılır. commandText parametresi ile, çalıştırılacak olan SQL
ifadesi alınır. Statement nesnesi oluşturulduktan sonra executeUpdate komutu çalıştırılacak
işlemden etkilenen kayıt sayısı veritabanı sunucusundan alınır ve döndürülür.
int NonQuery(String commandText, Object[] parameterValues): Veritabanı üzerinde çalıştırılacak olan SQL ifadesi commandText parametresi ile, sorgunun içinde bulunan
parametrelerin değerleri Object dizisi cinsinden parameterValues parametresiyle alınır. Connection nesnesi üzerinden PreparedStatement nesnesi oluşturulduktan sonra parameterValues dizisinin eleman sayısı kadar parametre setValue(Object) metodu ile PreparedStatement nesnesine eklenir . SQL ifadesi çalıştırıldıktan sonra veritabanında etkilenen kayıt
sayısı geri döndürülür.
ArrayList ReturnArrayList(String commandText): Veritabanı üzerine çalıştırılan Select ifadesinin sonucunda dönen değer kümesi ResultSet nesnesi üzerinden alınır. ResultSetMetaData nesnesi, veritabanından dönen sonuç kümesinin sütun sayını almak için kullanılır.
Veritabanından dönen değerleri uygulamaya göndermek için ArrayList nesnesi kullanılmıştır.
ArrayList nesnesinin her bir kaydı, veritabanından gelen bir satır veriyi içerir. Bir veri satırını
tutmak için String dizisi kullanılmıştır ve String dizisinin eleman sayısı ResultSetMetaData nesnesinden alınan sütun sayısına göre belirlenir. ResultSet nesnesinin içindeki kayıt sayısı
kadar String dizisi oluşturulur ve ArrayList’e eklenir. resultSet.getString() metodu
columnIndex+1 parametresiyle çalıştırılır. Bunun sebebi, .Net ortamından farklı olarak parametre ve sütun indekslerinin 1 değerinden başlamasıdır.
JDBC
ArrayList ReturnArrayList(String commandText, Object[] paramaterValues): Parametreli select ifadelerinin çalıştırılması için bu metod kullanılır. parameterValues
Object dizisi aracılığıyla select ifadesinin parametre değerleri alınır ve PreparedStatement
nesnesine setObject() metodu yardımıyla eklenir. Bir önceki metod yapısında olduğu gibi
ArrayList nesnesi oluşturulur. ArrayList nesnesinin her bir kaydı veritabanından gelen bir
satırı tutan String dizisinden oluşur.
Örnek Uygulama 7.12:
1 import java.sql.SQLException;
2 import java.util.ArrayList;
3 import dbAccess.DbConnection;
4 public class VeriErisimi
5 {
6 public static void main(String[] args) throws
ClassNotFoundException, SQLException
7 {
8 9
DbConnection connection = new DbConnection();
// Yeni bir ürün veritabanına kaydediliyor
10 int rowCount = connection.NonQuery(“INSERT INTO Urun
(urunAdi, fiyat) VALUES (‘HP 870cxi Yazıcı’, ‘70’)”);
11 if(rowCount != 0)
12 {
13 14 }
15 else
16 {
17 18 }
System.out.println(“Ürün kaydedildi”);
System.out.println(“Ürün kaydedilemedi”);
19 // Yeni bir müşteri veritabanına kaydediliyor
20 Object[] musteriInsertParameters = new Object[2];
21 musteriInsertParameters[0] = “Veli”;
22 musteriInsertParameters[1] = “Karaman”;
23 rowCount = connection.NonQuery(“INSERT INTO Musteri
(ad, soyad) VALUES (?, ?)”, musteriInsertParameters);
24 if(rowCount != 0)
25 {
26 27 }
28 else
29 {
30 System.out.println(“Müşteri kaydedildi”);
System.out.println(“Müşteri kaydedilemedi”);
31 }
32 System.out.println();
33 // Veritabanından belirli bir fiyat aralığındaki
ürün bilgileri çekilip ekrana basıldı
34 Object[] urunSelectParameters = new Object[2];
119
120
Bölüm 7
35 urunSelectParameters[0] = 30;
36 urunSelectParameters[1] = 60;
37 ArrayList arrUrun = connection.
ReturnArrayList(“SELECT * FROM Urun WHERE Fiyat BETWEEN ? AND ?”,
urunSelectParameters);
38 for (Object object : arrUrun)
39 {
40 String[] urun = (String[])object;
41 for(int i = 0; i < urun.length; i++)
42 {
43 44 }
45 System.out.println();
46 }
47 System.out.println();
System.out.print(urun[i] + “\t”);
48 // Veritabanından bütün müşteri bilgileri çekilip
ekrana basıldı
49 ArrayList arrMusteri = connection.
ReturnArrayList(“SELECT * FROM Musteri”);
50 for (Object object : arrMusteri)
51 {
52 String[] musteri = (String[])object;
53 for(int i = 0; i < musteri.length; i++)
54 {
55 System.out.print(musteri[i] + “\t”);
56 }
57 System.out.println();
58 }
59 }
60 }
Uygulamada; müşteri kaydı eklenmesi için parametreli NonQuery metodu, ürün kaydı eklenmesi için parametresiz NonQuery metodu, belirli bir fiyat aralığındaki ürünlerin çekilmesi için
parametreli ReturnArrayList metodu, bütün müşteri bilgilerinin çekilmesi için parametresiz
ReturnArrayList metodu kullanılmıştır. Uygulama çalıştırıldığında aşağıdaki gibi bir ekran
çıktısı alınır.
Örnek Uygulama 7.13:
Ürün kaydedildi
Müşteri kaydedildi
11GB Ram
40.0000
22 GB USB Bellek
30.0000
3DVD Writer 45.0000
1Yalçin
2Erkut
3Hasan
4Veli Kaya
Kutlar
Polat
Karaman 8
JSP
8 JSP
• JSP Teknolojisinde Kullanılan Etiketler
• JSP Direktifleri
• JSP Script Etiketleri
• Form Verilerinin Kullanılması
• Durum Yönetimi
JSP
Java platformunu kullanarak web uygulamaları geliştirmek için JSP (Java Server Pages) teknolojisi kullanılır. JSP, .Net ortamının web geliştirme teknolojisi olan ASP.Net mimarisinin Java ortamındaki karşılığıdır. ASP.Net uygulamaları geliştirirken kullanılan code-behind mimarisini JSP
ortamında doğrudan bir karşılığı olmadığından Java kodları ile HTML kodları aynı sayfanın içinde
bulunur. JSP uygulamalarında iş mantığını web sayfalarından ayırmak ve uygulamaları bileşenlere bölmek için Java tabanlı Servlet mimarisi kullanılılır. Bu bölümde JSP uygulaması geliştirme
ve Servlet bileşenleri oluşturmayı öğreneceğiz.
JSP uygulamalarını ve Servlet bileşenlerini çalıştırmak için aşağıdaki adresten Apache Tomcat
sunucusunun işletim sisteminize uygun olan versiyonunu indirebilirsiniz. http://tomcat.apache.
org/download-60.cgi
http://apache.karegen.com/tomcat/tomcat-6/v6.0.14/bin/apache-tomcat-6.0.14.exe
Windows binary formatında indirilen Tomcat sunucusunun kurulumu aşağıda adım adım gösterilmiştir.
Kurulum standart Windows uygulaması kurulum biçimindedir.
Uygulamayı kurmadan önce sözleşmenin kabul edilmesi gerekir.
124
Bölüm 8
Examples seçeneği işaretlenirse JSP ve Servlet bileşenleriyle ilgili örnek uygulamalar yerel ağ
üzerinde çalıştırılabilir.
Kurulum için standart dizinden farklı bir dizin de seçilebilir. Uygulamalarda kullanılan Tomcat,
standart dizine kurulmuştur.
Kurulumun bu aşamasında Tomcat sunucusunun çalışacağı port numarasının belirlenir ve admin
kullanıcısı için şifre oluşturulur. Bilgisayarınızın 8080 numaralı portunu kullanan başka bir uygulama yoksa Tomcat sunucusunun 8080 portunu kullanmasını sağlayabilirsiniz. Uygulamalarda
kullanılan Tomcat sunucusu 8080 portu üzerinde çalışmaktadır. Admin kullanıcısının şifresinin
boş bırakılması genel olarak tavsiye edilmez. Özellikle üzerinde aktif bir biçimde kullanılan uygulamalar çalışan bir sunucunun admin şifresinin boş olması uygulamalarda ve sistemde ciddi
güvenlik açıklarına neden olur.
JSP
Tomcat sunucusu çalışmak Java platformunun 5.0 sürümüne ihtiyaç duyduğundan JRE 5.0 uygulamasının yeri belirtilmelidir. Java motoru standart olarak kurulmuşsa bu dizin otomatik olarak
belirlenir, aksi takdirde bilgisayar üzerindeki yerinin manuel olarak belirtilmesi gerekir.
Tomcat sunucusunun kurulumu tamamlandı. “Run Apache Tomcat” seçeneği işaretli olarak bırakırsa Tomcat sunucusuna ait Windows servisi çalışır.
125
126
Bölüm 8
Tomcat kurulumu başarılı olduysa ve ilişkili Windows servisi çalıştırıldıysa bilgisayarın sağ alt
köşesinde Tomcat’e ait ikon belirir. Tomcat Windows servisi ile ilgili ayarlar bu ikona çift tıklandıktan sonra çıkan pencerede yapılabilir. Tomcat Windows servisi varsayılan olarak manuel
çalıştırılacak şekilde ayarlanır. İşletim sisteminin her açılışında Tomcat servisinin otomatik olarak
başlaması için servisin Şekil 8’deki gibi ayarlanması gerekir.
Tomcat servisinin bilgisayarın her açılışında otomatik olarak çalışması için “Startup Type” seçeneği “Automatic” olarak değiştirilir.
Tomcat sunucusunun kurulumu sırasında farklı bir dizin belirtmediyseniz C:\Program Files\Apache Software Foundation\Tomcat 6.0 dizinine kurulacaktır. Bu dizinin altındaki webapps dizininin
altında bulunan ROOT dizini JSP uygulamalarının barındırıldığı standart dizindir. Tomcat konfigürasyonunu değiştirmek için Tomcat ana dizininin altındaki conf dizininde bulunan konfigürasyon
dosyaları kullanılabilir.
Webapps dizininin altında bulunan ROOT dizininin içinde yeni bir dizin oluşturalım ve adını IlkOrnek olarak değiştirelim. Tomcat sunucumuza http://localhost:8080 adresinden, IlkOrnek adını verdiğimiz web uygulamamıza ise http://localhost:8080/IlkOrnek adresi üzerinden ulaşabiliriz.
Uygulamamız henüz bir JSP sayfasına sahip olmadığı için web tarayacısı üzerinden bu adrese
ulaşmaya çalışırsak hata mesajı alırız.
Notepad veya benzer bir metin editörü kullanarak IlkOrnek dizininin içinde boş bir metin dosyası
oluşturalım ve adını ilkornek.jsp olarak değiştirelim. Dosyanın uzantısının .jsp olması gerektiğini
unutmamalıyız. Örnek Uygulama 8.1’deki kod bloğunu bu dosyanın içine yazarak dosyayı kaydedelim.
Örnek Uygulama 8.1:
1 <%
2 out.println(“Ilk Ornek”);
3 %>
Tomcat kurulumu başarılı bir şekilde tamamlandıysa web tarayıcısının adres kısmına http://localhost:8080/IlkOrnek/ilkornek.jsp yazıp enter tuşuna bastığımızda Şekil-9’daki gibi bir sayfanın
açılması gerekir.
JSP
Şekil 9
Erişmeye çalıştığımız JSP sayfasının adının küçük-büyük harf duyarlı olduğuna dikkat edelim.
http://localhost:8080/IlkOrnek/ilkornek.jsp sayfası yerine http://localhost:8080/IlkOrnek/IlkOrnek.
jsp sayfasına ulaşmaya çalışırsak Şekil 10’daki gibi bir hata mesajı alırız.
Şekil 10: Küçük-büyük harf duyarlılığından kaynaklanan sayfa bulunamadı hatası.
Oluşturduğumuz JSP sayfasının koduna bir göz atarsak <% ve %> etiketlerini görürüz. Bu etiketlerin arasına yazdığımız bütün kod blokları Java kodu olarak yorumlanır JSP script’leri yazmak
için kullanılır. İşletim sistemi üzerinde çalışan Java uygulamalarında kullanılan System.out.
println() komutu JSP ortamında out.println() şeklini alır ve istemciye (client) metin çıktısı vermek için kullanılır.
ROOT dizininin altında JspOrnekleri adında bir dizin oluşturalım ve bundan sonraki örnekleri bu
dizinin içine kaydedelim.
Java dilinde standart olarak bulunan komutlar JSP sayfaları oluşturulurken de kullanılır. Az önce
yazdığımız metni beş defa yazan bir programı for döngüsü kullanarak oluşturalım. Dongu.jsp
adında bir jsp sayfasını Notepad kullanarak JspOrnekleri dizinine kaydedelim. Dongu.jsp sayfasını oluşturmak için kullanılan kod aşağıdaki gibidir.
Örnek Uygulama 8.2:
1<%
2
for(int i = 0; i < 5; i++)
3
out.println(“Ilk Ornek<br>”);
4%>
Kodu incelersek, JSP sayfalarında Java ve HTML kodlarının bir arada bulunaibildiğini görürüz.
out.println() komutunun sonunda kullandığımız <br> etiketi çıktının bir alt satıra geçmesini
127
128
Bölüm 8
sağlar ve standart HTML etiketlerindendir. Döngü yapısının Java dilinin standart for döngüsü
olduğunu görüyoruz.
http://localhost:8080/JspOrnekleri/Dongu.jsp adresi üzerinden sayfayı çalıştırdığımızda Şekil
11’deki gibi bir görünüm elde ederiz.
Şekil 11: Döngü kullanımı.
JSP ortamı; ASP, PHP, ASP.Net, vb. teknolojileri gibi sunucu tarafında çalışır. Bunun anlamı,
JSP kodunun sunucunun üzerinde çalışması ve istemci tarafında HTML kodunun gönderilmesidir. JSP sayfalarına http://Adres/SayfaAdi.jsp şeklinde ulaşılsa da istemci üzerinde çalışan web
tarayıcısına saf HTML ve gerekirse Javascript kodu gelir. Web ortamında çalışan bütün sunucu
tabanlı teknolojilerin web tarayıcıları tarafından yorumlanabilmesinin sebebi de budur. Dongu.
jsp sayfasına sağ tıkladığımızda karşımıza çıkan menüden “view source” komutunu çalıştırırsak
bahsedilen özellik daha iyi anlaşılır. İstemci tarafına gelen HTML kodu aşağıdaki gibidir.
Ilk Ornek<br>
Ilk Ornek<br>
Ilk Ornek<br>
Ilk Ornek<br>
Ilk Ornek<br>
Karşımıza çıkan HTML kodunda aynı ifade beş kere yazılmıştır ve ifadeler arasında bulunan <br>
etiketinden dolayı çıktı beş satır halinde görünmektedir. Sunucu tarafında çalışan JSP sayfası
üzerinde kullanılan döngü ve “<%”, “%>” etiketleri istemci tarafında görünmez.
JSP Teknolojisinde Kullanılan Etiketler
JSP Direktifleri
JSP sayfalarının özelliklerini değiştirmek amacıyla kullanılan yapılardır ve başlarında “@” karakteri bulunur. JSP direktifleri istemciye çıktı göndermez. En çok “Page” direktifi kullanılır. Page
direktifi ile sayfanın script dili, durum yönetimi, buffer gibi özellikleri ile ilgili ayarlar yapılır, harici
kütüphanelerin sayfa tarafından kullanılması sağlanır. Örneğin;
<%@ page session=”true” import=”java.util.*” %> direktifi ile sayfada durum yönetimi etkin hale getirilir ve java.util paketinin içisnde bulunan bileşenler sayfaya eklenerek bu
pakette bulunan sınıfların sayfa tarafından kullanılması sağlanır. session=”true” yazmasak
bile varsayılan olarak sayfanın session desteği açıktır, kapatmak için session=”false” yazmamız gerekir.
JSP
JSP Script Etiketleri
Script etiketleri, JSP sayfalarında asıl işi yapan etiketlerdir. Sayfada bulunacak Java kodları script
etiketleri içine yazılır, sunucu bu etiketler içinde bulunan kodları Java kodu olarak algılar. JSP’de
üç çeşit script etiketi bulunur.
Tanımlama etiketleri: Java değişkenlerini tanımlamak için kullanılır ve <%! ...
oluşturulur.
%> şeklinde
Scriptlet etiketleri: Java ifadelerinden oluşan kod parçalarını çalıştırmak için kullanılır ve <% ...
%> şeklinde oluşturulur.
İfade etiketleri: Bütün Java ifadelerini çalıştırmak için kullanılır ve <%= ... %> şeklinde oluşturulur.
Bu etiketlerin dışında, JSP sayfaları içinde yorum satırı oluşturmak için <%-- ... --% etiketi
kullanılır.
Form Verilerinin Kullanılması
JSP uygulamalarında sayfalar arasında veri taşımak için HTML standartlarının içinde bulunan
POST veya GET metodları kullanılabilir. Herhangi bir HTML veya JSP sayfasının içinde oluşturulan form alanının içinde bulunan kontrollerin verileri GET veya POST işlemi sırasında üzerinde
çalışılan sayfaya veya farklı bir sayfaya gönderilir. Basit bir HTML sayfasından bir JSP sayfasına
POST metodu aracılığıyla verilerin gönderilmesi işlemi aşağıdaki gibi yapılabilir.
FormOrnegi.html sayfasını oluşturan HTML kodu aşağıdaki gibidir.
1<html>
2<body>
3
<form method=”post” action=”FormData.jsp”>
4
<table>
5
<tr>
6
<td>Ad:</td>
7
<td><input type=”text” name=”txtAd” /> </td>
8
</tr>
9
<tr>
10
<td>Soyad:</td>
11
/> </td>
<td><input type=”text” name=”txtSoyad”
12
</tr>
13
<tr>
14
<td><input type=”submit”
name=”btnGonder” value=”Gonder” /><td>
15
</tr>
16
</table>
17
</form>
18
</body>
19
</html>
HTML sayfasında, <body> etiketinin içinde bir form oluşturduk ve POST metodunu kullanacağımızı belirttik. Formun içine eklenen “submit” butonunun tetiklenmesi sonrasında form verileri
129
130
Bölüm 8
FormData.jsp sayfasına gönderilir. Bu işlem action=”FormData.jsp” satırıyla gerçeklenir. Kullanıcının ad ve soyad değerlerini girmesi forma iki tane “text” tipinden input ekledik. Kontrollerin arayüz üzerinde düzgün bir şekilde görüntülenmesi için standart HTML yapılarından biri olan <table>
etiketini kullandık. HTML sayfası aşağıdaki gibi görünür.
Şekil 12
Kullanıcı tarafından veri girişi yapıldıktan sonra Gönder butonuna tıklandığında form verileri
FormData.jsp sayfasına gönderilir. FormData.jsp adında bir JSP sayfası oluşturarak gönderilen
verileri alıp işleyebiliriz.
1<%@ page import=”java.util.*” %>
2<%
3
out.print(“Ad:” + request.getParameter(“txtAd”));
4
;
out.print(“<br>Soyad:” + request.getParameter(“txtSoyad”))
5%>
Request.getParameter metodu, herhangi bir form üzerinden FormData.jsp sayfasına gönderilen
verileri almak için kullanılır. txtAd ve txtSoyad anahtarları, FormOrnegi.html sayfasında bulunan
text türünden veri giriş elemanlarının isim (name) değeridir. Gönder butonuna tıklandıktan sonra
FormData.jsp sayfası yüklenir ve aşağıdaki gibi bir görünüm elde edilir.
Şekil 13
HTML sayfasında verileri göndermek için POST yerine GET metodunu kullansak da FormData.
jsp sayfasından verilere aynı şekilde ulaşabilir. Bu durumda veriler gizli olarak değil URL üzerinden gönderilecektir. Önemli verilerin GET metodu ile gönderilmesi güvenlik açısından sakıncalıdır. GET metodu kullanıldığında FormData.jsp sayfası aşağıdaki gibi görünür:
Adres çubuğunda görünen URL değerine dikkat edersek bütün form verilerinin açık bir şekilde ve
saf metin formatında aktarıldığını görebiliriz.
JSP
Durum Yönetimi
HTTP protokolü durum özelliğine sahip değildir. Durum mekanizması, bir kullanıcı sisteme bağlı
kaldığı sürece verilerinin birden fazla sayfa arasında taşınabilmesine olanak verir. JSP de diğer
sunucu tabanlı web teknolojileri gibi kendine özel bir durum yönetimi mekanizmasına sahiptir.
JSP’de durum yönetimi session nesnesiyle sağlanır. Session nesnesine request.getSession()
metodu aracılığıyla ulaşılır. Basit bir sisteme giriş sayfasıyla kullanıcının bilgilerini session nesnesine kaydeden ve uygulama içindeki farklı bir sayfadan bu bilgilere ulaşan bir JSP uygulaması
yazalım:
1<%--------- KullaniciGirisi.jsp ---------%>
2<html>
3<body>
4<%
5
out.print(“Session ID: “ + session.getId());
6%>
7<form method=”post” action=”KullaniciGirisi.jsp”>
8
<table>
9
<tr>
10
<td>Ad:</td>
11
<td><input type=”text” name=”txtAd” /> </td>
12
</tr>
13
<tr>
14
<td>Sifre:</td>
15
</td>
<td><input type=”password” name=”txtSifre” />
16
</tr>
17
<tr>
18
<td><input type=”submit” name=”btnGonder”
value=”Gonder” /><td>
19
</tr>
20
</table>
21
</form>
22
<%
23
String ad = request.getParameter(“txtAd”);
24
String sifre = request.getParameter(“txtSifre”);
25
if(ad != null && sifre != null)
26
{
131
132
Bölüm 8
27
equals(“1234”))
if(ad.equals(“Yalcin”) && sifre.
28
{
29
session.putValue(“kullaniciAdi”, ad);
30
response.sendRedirect(“SifreDogru.jsp”);
31
}
32
else
33
{
34
hatali”);
35
}
36
}
37
%>
38
</body>
39
</html>
out.println(“Kullanici adi veya sifre
Kullanıcının kullanıcı adı ve şifre bilgilerini girmesi için KullaniciGirisi.jsp adında bir JSP sayfası
oluşturduk. Bir önceki örnekten farklı olarak kullanıcıdan gelecek bilgileri HTML sayfası yerine JSP
sayfası üzerinden almayı tercih ettik. Bunun sebebi, kullanıcı giriş sayfasında da JSP kullanmayı
planlamamız. Sayfanın başında kullandığımız <% out.print(“Session ID: “ + session.getId()); %>
komutuyla o anda geçerli olan oturumun ID değerini kullanıcıya gösterdik. Form etiketinin action
özelliğinin KullaniciGirisi.jsp sayfasını gösterdiğine dikkat edelim. Kullanıcı bilgilerini aldığımız
sayfayla bu bilgilerin geçerliliğini kontrol ettiğimiz sayfa aynı. Form etiketinden sonra kullanıcının
girdiği bilgilerin geçerliliğini kontrol etmek için request.getParameter() metodu ile form verilerini
aldık. Kullanıcı adı ve şifre bilgilerini sayfanın içinde kontrol ettik; kullanıcı adı olarak “Yalcin”,
şifre olark “1234” değerleri girilmişse sisteme giriş yapılabildiğini varsaydık. Gerçek bir uygulamada kullanıcıdan girilen değerler bir veri kaynağı üzerinden doğrulanır. Eğer kullanıcı sisteme
girmeyi başarabilirse kullanıcı adı değeri session nesnesine ekleniyor ve kullanıcı SifreDogru.
jsp sayfasına yönlendiriliyor. Sisteme giriş işlemi başarısız olursa “Kullanıcı adı veya şifre hatalı”
mesajı veriliyor ve yönlendirme yapılmıyor. KullaniciGirisi.jsp sayfası ilk açıldığında ve şifre yanlış
girildiğinde aşağıdaki gibi görünür:
Şekil 15: KullaniciGirisi.jsp sayfası ilk defa yüklendi.
Şifre yanlış girildi. Sayfanın yeniden yüklenmesi sırasında Session nesnesinin ID değerinin değişmediği görülüyor.
JSP
Kullanıcı adı ve şifre değerlerinin doğru girilmesi durumunda kullanıcının yönlendirileceği SifreDogru.jsp sayfasının kodu aşağıda verilmiştir:
<%
out.print(“Kullanici adi: “ + session.getValue(“kullaniciAdi”));
out.print(“<br>Session ID: “ + session.getId());
%>
Session nesnesine kaydedilmiş olan kullanıcı adı değeri alınıyor ve ekrana basılıyor. Session
değişkeninin ID değeri de aynı şekilde ekrana basılıyor.
Kullanıcı SifreDogru.jsp sayfasına yönlendirildiğinde aşağıdaki gibi bir sayfayla karşılaşır:
Kullanıcı adı ve şifre doğru girildi, session nesnesinde bulunan kullanıcı adı değeri ve session ID
değeri görüntülendi. Bu sayfadaki session ID değeriyle daha önceki sayfalardaki session ID değerinin aynı olduğunu görüyoruz. Session bilgileri bütün oturum boyunca ve uygulamanın bütün
sayfaları arasında geçerli olduğundan ID değeri de aynıdır.
JSP Uygulamalarında JDBC Kullanımı:
JSP uygulamalarının veritabanı sistemleriyle iletişim kurması için Java platformunun JDBC kütüphanesi kullanılır. JDBC kütüphanesi kullanarak bir ürün ekleme sayfası oluşturalım.
1<%@ page import=”java.util.*” %>
2<%@ page import=”java.sql.Connection” %>
3<%@ page import=”java.sql.DriverManager” %>
4<%@ page import=”java.sql.PreparedStatement” %>
5<%@ page import=”java.sql.SQLException” %>
6
7<html>
8<body>
133
134
Bölüm 8
9
<form method=”post” action=”UrunEkle.jsp”>
10
<table>
11
<tr>
12
<td>Urun adi:</td>
13
/> </td>
<td><input type=”text” name=”txtUrunAd”
14
</tr>
15
<tr>
16
<td>Fiyat:</td>
17
<td><input type=”text”
name=”txtUrunFiyat” /> </td>
18
</tr>
19
<tr>
20
<td><input type=”submit”
name=”btnUrunKaydet” value=”Kaydet” /><td>
21
</tr>
22
</table>
23
</form>
24
<%
25
Ad”);
String urunAdi = request.getParameter(“txtUrun
26
unFiyat”);
String urunFiyat = request.getParameter(“txtUr
27
if(urunAdi != null && urunFiyat != null)
28
{
29
try
30
{
31
valueOf(urunFiyat);
double fiyat = Double.
32
JdbcOdbcDriver”);
Class.forName(“sun.jdbc.odbc.
33
Connection dbConnection =
DriverManager.getConnection(“jdbc:odbc:AlisverisSitesi”);
34
PreparedStatement statement =
dbConnection.prepareStatement(“INSERT INTO Urun (urunAdi, fiyat)
VALUES (?, ?)”);
35
statement.setString(1, urunAdi);
36
statement.setDouble(2, fiyat);
37
executeUpdate();
int rowCount = statement.
38
statement.close();
39
if(rowCount == 0)
40
{
41
kaydedilemedi”);
42
}
System.out.println(“Ürün
JSP
43
}
44
catch(Exception e)
45
{
46
degeri girin<br>”);
47
}
48
}
49
%>
50
</body>
51
</html>
out.print(“Fiyat alanina sayi
Ürün bilgilerini veritabanına kaydetmek için JDBC kütüphanesini kullandık. Veritabanı üzerinde çalıştırılacak olan sorgunun parametreleri kullanıcıdan alındığından PreparedStatement sınıfı
cinsinden bir nesne oluşturarak parametrelerini verdik. Ürün fiyatı alanının cinsi double olması
gerektiği için fiyat alanına girilen değeri double’a çevirmeye çalıştık. Uygulamanın akışına göre,
fiyat alanının değeri double’a çevrilebilirse sorgu çalıştırılıyor, çevrilemezse kullanıcıya hata mesajı veriliyor. Bir önceki örnekte olduğu gibi formun action değeri, yani post edildiğinde verilerini
göndereceği sayfa, yine formun kendisi.
UrunEkle.jsp sayfası çalıştırılmadan önce ve hatalı veri girildiğinde aşağıdaki gibi görünür.
Şekil 18
Şekil 19: Fiyat alanına double tipine çevrilemeyen veri girildi.
Veritabanını sorgulayarak sipariş bilgilerini getirmek için JSP sayfalarımızı oluşturalım. Öncelikle
veritabanı sunucumuzun arayüz programını açarak sipariş ve sipariş detayı bilgilerini ekleyelim.
INSERT INTO Siparis (musteriID, siparisTarihi) VALUES (1,
‘12/2/2007’)
INSERT INTO Siparis (musteriID, siparisTarihi) VALUES (1,
‘10/8/2007’)
135
136
Bölüm 8
INSERT INTO Siparis (musteriID, siparisTarihi) VALUES (2,
‘5/3/2007’)
INSERT INTO Siparis (musteriID, siparisTarihi) VALUES (3,
‘5/8/2007’)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (1,
1, 1)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (1,
3, 2)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (2,
7, 1)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (3,
5, 1)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (3,
8, 3)
INSERT INTO SiparisDetay (siparisID, urunID, miktar) VALUES (4,
3, 1)
Verileri veritabanına ekledikten sonra JSP sayfalarımızı oluşturmaya başlayabiliriz. Öncelikle verilen siparişleri görüntülemek için Siparis.jsp adında bir JSP sayfası oluşturalım.
1<%@ page import=”java.util.*” %>
2<%@ page import=”java.sql.Connection” %>
3<%@ page import=”java.sql.DriverManager” %>
4<%@ page import=”java.sql.ResultSet” %>
5<%@ page import=”java.sql.Statement” %>
6<html>
7<body>
8<%
9
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
10
Connection dbConnection = DriverManager.
getConnection(“jdbc:odbc:AlisverisSitesi”);
11
Statement statement = dbConnection.
createStatement();
12
ResultSet resultSet = statement.executeQuery(“SELECT
siparisID, siparisTarihi, ad, soyad FROM siparis s JOIN Musteri m
ON (s.musteriID = m.musteriID)”);
13
out.println(“Detay bilgilerini ogrenmek istediginiz
siparisin tarihine tiklayin<br><br>”);
14
%>
15
<table>
16
<%
17
while(resultSet.next())
18
{
19
%>
20
<tr>
21
<td width=”100”><a href=”SiparisDetay.
jsp?id=<%out.println(resultSet.getInt(“siparisID”));
JSP
22
%>”>
23
<%
24
out.println(resultSet.getDate(“siparisTarihi”).
toString()); 25
%>
26
</a></td>
27
28
<%
29
30
%>
31
<td width=”60”>
out.println(resultSet.getString(“ad”)); 28
</td>
32
<td width=”60”><% out.println(resultSet.
getString(“soyad”)); 33 %>
34
</td>
35
36
<%
27
38
%>
39
40
<%
41
statement.close();
42
%>
43
</body>
44
</html>
</tr>
}
</table>
Kodun açıklaması: Veritabanı bağlantısı oluşturulduktan sonra sipariş bilgilerini çekmek amacıyla bir select sorgusu veritabanı üzerinde çalıştırılır ve geri dönen sonuç kümesi ResultSet nesnesi
aracılığıyla alınır. Verilerin düzgün bir biçimde görüntülenebilmesi için <table> yapısı kullanılmıştır. ResultSet nesnesinin her bir kaydı için tabloda bir satır oluşturulmuştur. Bir satır üç sütundan
oluşur: İlk sütün siparişin verildiği tarihi içerir ve SiparisDetay.jsp sayfasına bağlantı kurmak amacıyla <a href> etiketinden oluşur. SiparisDetay.jsp sayfasına siparis numarası URL aracılığıyla taşınacağından her bir kaydın siparisID değeri ile <a href> etiketinin URL alanı belirlenir. Bu alanın
değeri SiparisDetay.jsp?id=... şeklinde olup “...” ile ifade edilen yere sipariş numarası gelir. Sayfa
yüklendiği zaman aşağıdaki gibi görünür.
Şekil 20
137
138
Bölüm 8
Sipariş tarihi alanına tıklandığında açılacak olan SiparisDetay.jsp sayfasında seçilen siparişin
detay bilgileri veritabanından çekildikten sonra görüntülenecektir. SiparisDetay.jsp sayfasını oluşturan JSP kodu aşağıdaki gibidir.
1<%@ page import=”java.util.*” %>
2<%@ page import=”java.sql.Connection” %>
3<%@ page import=”java.sql.DriverManager” %>
4<%@ page import=”java.sql.ResultSet” %>
5<%@ page import=”java.sql.Statement” %>
6<%@ page import=”java.sql.PreparedStatement” %>
7<html>
8<body>
9<%
10
if(request.getParameter(“id”) == null)
11
12
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
response.sendRedirect(“Siparis.jsp”);
13
Connection dbConnection = DriverManager.
getConnection(“jdbc:odbc:AlisverisSitesi”);
14
PreparedStatement statement = dbConnection.
prepareStatement(“SELECT urunAdi, fiyat, miktar FROM SiparisDetay
sd JOIN Urun u ON (sd.urunID = u.urunID) WHERE siparisID = ?”);
15
statement.setString(1, request.getParameter(“id”));
16
ResultSet resultSet = statement.executeQuery();
17
%>
18
<table>
19
<%
20
while(resultSet.next())
21
{
22
%>
23
<tr>
24
25
<%
26
27
%>
28
</td>
29
30
<%
31
32
%>
33
</td>
34
35
<%
36
37
%>
38
</td>
<td width=”200”>
out.println(resultSet.getString(“urunAdi”));
<td width=”100”>
out.println(resultSet.getDouble(“fiyat”));
<td width=”100”>
out.println(resultSet.getInt(“miktar”));
JSP
39
40
<%
41
42
%>
43
44
<%
45
46
%>
47
</body>
48
</html>
</tr>
}
</table>
statement.close();
Kodun açıklaması: Sayfanın ilk yüklenmesi sırasında URL aracılığıyla “id” değerinin gelip gelmediği kontrol edilir. Eğer “id” değeri yoksa kullanıcı Siparis.jsp sayfasına yönlendirilir. “id” değeri
varsa veritabanı bağlantısı kurulduktan sonra parametreli bir select ifadesi çalıştırmak üzere PreparedStatement nesnesi oluşturulur ve sipariş numarası URL aracılığıyla gelen siparişin detay
bilgileri veritabanından çekilir. Geri dönen sonuç kümsi ResultSet nesnesi aracılığıyla bir HTML
tablosunda kullanıcıya gösterilir.
SiparisDetay.jsp sayfası açıldığında “id” alanının değeri boş değilse aşağıdaki gibi bir sayfa görüntülenir.
Şekil 21
139
9
JAVA I/O
9 JAVA I/O
• Dosyalar ve Dizinler
• FilterInputStream Sınıfları
• FileInputStream ve FileOutputStream
Sınıflarının Kullanımı
• Reader ve Writer Sınıfları:
• Standart Giriş-Çıkış Biriminin Kullanılması:
• Java ile Ağ Programlama
JAVA I/O
.NET platformunda olduğu gibi Java platformunda da giriş-çıkış işlemleri Stream adı verilen veri
yapıları aracılığıyla yapılır. Veri gönderme ve alma kabiliyetine sahip bütün nesneler Stream olarak tanımlanabilir. Stream yapısının kullanımıyla, giriş-çıkış birimlerinin içinde bulunan veri yazılım ortamından soyutlanmış olur. Java ortamındaki Stream okuma amacıyla kullanılan sınıflar
InputStream sınıfından, Stream yazma amacıyla kullanılan sınıflar OutputStream sınıfından türetilirler. InputStream türünden sınıflarda bulunan Read() metodu ile byte bazında okuma yapılabilir. Benzer bir şekilde OutputStream türünden sınıflarda bulunan sınıfların sahip olduğu Write()
metodu ile byte bazında yazma işlemi yapılabilir. Stream yapılarını kullanmak için oluşturulmuş
olan InputStream ve OutputStream sınıfları temel olarak byte veri tipinden verilerle çalışsa da
Java ortamında bulunan farklı sınıflar kullanılarak char veri tipi ile de işlem yapılabilir. Aşağıdaki
veri kaynakları kullanılarak Stream üzerinden okuma veya yazma işlemi gerçekleştirilebilir:

Byte dizileri

Dosyalar

String nesneleri

Ağ (network) kaynakları
Stream yapısının detaylarına girmeden önce dosya sistemi üzerinde duralım.
Dosyalar ve Dizinler
Okuma ve yazma işlemleri için disk üzerinde bulunan dosyalara erişilmek istendiğinde File sınıfından oluşturulan nesneler kullanılır. File kelimesi sadece dosya kavramını temsil ediyor gibi
görünse de dizin kavramını da içerir. Disk üzerinde bulunan dizinlere ve dosyalara erişmek için
File nesneleri kullanılır. File nesnesinin bir dosyayı temsil etmesi istendiğinde yapıcı metoduna
parametre olarak bu dosyanın yeri, adı ve uzantısı String formatında verilir. Benzer şekilde, File
nesnesinin yapıcı metoduna parametre olarak temsil edilecek dizinin yeri ve adı da verilebilir.
File nesnesi kullanılarak C:\Program Files\Java\jre1.6.0_02 dizininin içinde bulunan bütün dosya
ve dizinler aşağıdaki gibi görüntülenebilir:
1import java.io.File;
2public class Giris
3{
4
public static void main(String[] args)
5
{
6
File kaynakDizin = new File(“C:\\Program Files\\
Java\\jre1.6.0_02”);
7
String[] dosyalarVeDizinler = kaynakDizin.list();
8
for (String dosyaVeyaDizin : dosyalarVeDizinler)
9
{
10
11
}
12
}
13
}
System.out.println(dosyaVeyaDizin);
Kodun açıklaması: File nesnesi oluşturularak C:\Program Files\Java\jre1.6.0_02 dizininin Java
programında temsil edilmesi sağlanır. File nesnesinin list() metodu, dizin içinde bulunan bütün
dosya ve dizinlerin adını bir String dizisi şeklinde döndürür.
144
Bölüm 9
Uygulama çalıştırıldığında aşağıdaki gibi bir çıktı alınır:
bin
COPYRIGHT
lib
LICENSE
PATCH.ERR
README.txt
THIRDPARTYLICENSEREADME.txt
Welcome.html
Bilgisayarınızda bu dizin bulunmuyorsa File sınıfının yapıcı metoduna başka bir dizin adını parametre olarak verebilirsiniz. C:\Program Files\Java\jre1.6.0_02 dizininin altında bulunan bütün
dosya ve klasörlerin görüntülendiğine ve verilen dizin altında bulunan dizinlerin içindeki dosya ve
klasörlerin listelenmediğine dikkat edelim. Sadece dosyaların görüntülenmesi için aşağıdaki kod
bloğu kullanılabilir:
1import java.io.File;
2public class Giris
3{
4
public static void main(String[] args)
5
{
6
File kaynakDizin = new File(“C:\\Program Files\\
Java\\jre1.6.0_02”);
7
File[] dosyalarVeDizinler = kaynakDizin.listFiles();
8
for (File dosyaVeyaDizin : dosyalarVeDizinler)
9
{
10
if(dosyaVeyaDizin.isFile())
11
{
12
getName());
13
}
14
}
15
}
16
}
System.out.println(dosyaVeyaDizin.
Kodun açıklaması: Bir önceki örnekten farklı olarak File nesnesinin listFiles() metodunu kullandık. Bu metod String dizisi yerine File dizisi döndürür. Böylece verilen dizinin altında bulunan
bütün dosya ve dizinler birer tane File nesnesiyle temsil edilmiş olur. Döngü içinde bulunan File
nesnesinin isFile() metodu ile temsil edilen yapının dosya olup olmadığını kontrol ediyoruz, eğer
dosyaysa dosyanın adını ekrana basıyoruz. Sadece dizinleri görüntülemek isteseydik File nesnesinin isDirectory() metodunu kullanabilirdik. Uygulama çalıştırıldığında aşağıdaki gibi bir çıktı
alınır:
COPYRIGHT
LICENSE
PATCH.ERR
README.txt
JAVA I/O
THIRDPARTYLICENSEREADME.txt
Welcome.html
InputStream
Çeşitli veri kaynaklarından veri okumak amacıyla aşağıdaki sınıflardan oluşturulan nesneler kullanılabilir. Bu sınıflar InputStream sınıfından türetilmiştir.
ByteArrayInputStream: Bellek üzerinde bulunan tampon bölgelerden veri alınması amacıyla
kullanılır.
StringBufferInputStream: Bir String nesnesinin InputStream nesnesi olarak kullanılmasını sağlar.
FileInputStream: Disk üzerinde bulunan dosyaların okunması için kullanılır.
SequenceInputStream: Birden fazla InputStream nesnesinin tek bir InputStream nesnesine dönüştürülmesini sağlar.
PipedInputStream: PipedOutputStream nesnesine yazılan verileri biçimlendirmek için kullanılır.
OutputStream
Çeşitli veri kaynaklarına veri yazmak amacıyla aşağıdaki sınıflardan oluşturulan nesneler kullanılabilir. Bu sınıflar OutputStream sınıfından türetilmiştir.
ByteArrayOutputStream: Bellek üzerinde buffer bölgesi oluşturulması amacıyla kullanılır. ByteArrayOutputStream üzerine yazılan bütün verilen bellekte bulunan tampon bölgeye yazılır.
FileOutputStream: Disk üzerinde bulunan dosyalara veri yazılması için kullanılır.
PipedOutputStream: PipedInputStream nesnesine gönderilecek verileri hazırlamak için kullanılır.
Bahsedilen Stream sınıflarından başka, InputStream türevi sınıflardan oluşan nesneler aracılığıyla yapılan okuma işleminin veya OutputStream türevi sınıflardan oluşan nesneler aracılığıyla
yapılan yazma işleminin özelliklerinin belirlenmesi amacıyla FilterInputStream ve FilterOutputStream sınıfları kullanılır. Byte veri tipinden farklı veri tipleri ile okuma veya yazma yapma, okunacak veya yazılacak verilerin bir tampon bölgede tutulması veya tutulmaması gibi özellikler Filter
sınıfları aracılığıyla sağlanır. FilterInputStream ve FilterOutputStream sınıfları soyut olarak oluşturulmuştur, bu sınıflardan türetilen ve yerleşik olarak Java ortamında bulunan sınıflar yardımıyla
Stream nesnelerine çeşitli özellikler kazandırılabilir.
FilterInputStream Sınıfları
Giriş kaynaklarını biçimlendirmek amacıyla kullanılan sınıfların bir kısmı şunlardır:
DataInputStream: Farklı veri tiplerinde verilerin okunması amacıyla kullanılır.
BufferedInputStream: Her okumada fiziksel kaynağa erişilmesini engeller, okunan verilerin bellekte bulunan bir tampon bölgeye aktarılmasını sağlar.
LineNumberInputStream: Giriş kaynağına gelen satır sayısını saklar. Bu sınıfın kullanılması
tavsiye edilmez, satır sayısını elde etmek amacıyla kullanılan LineNumberReader sınıfı ileride
açıklanacaktır.
Bu sınıfların yapıcı metodları parametre olarak InputStream sınıfından türemiş bir sınıftan oluşan
bir nesne alır.
145
146
Bölüm 9
FilterOutputStream Sınıfları
Çıkış kaynaklarını biçimlendirmek amacıyla kullanılan sınıfların bir kısmı şunlardır:
DataOutputStream: Farklı veri tiplerinde verilerin yazılması amacıyla kullanılır.
BufferedOutputStream: Her yazma işleminde fiziksel kaynağa erişilmesini engeller, yazılacak
verilerin bellekte bulunan bir tampon bölgeye aktarılmasını sağlar.
PrintOutputStream: Çıkış kaynağına gönderilen verilerin görsel olarak biçimlendirilmesini sağlar.
Bu sınıfların yapıcı metodları parametre olarak OutputStream sınıfından türemiş bir sınıftan oluşan bir nesne alır.
FileInputStream ve FileOutputStream Sınıflarının Kullanımı
Disk üzerinde bulunan bir dosyanın okunarak içeriğinin disk üzerindeki başka bir dosyaya yazılmasını aşağıdaki kod ile gerçekleştirebiliriz.
1import java.io.FileInputStream;
2import java.io.FileOutputStream;
3import java.io.IOException;
4public class DosyaIslemleri
5{
6
public static void main(String[] args) throws IOException
7
{
8
FileInputStream okuma = new FileInputStream(“c:\\
okunan.txt”);
9
FileOutputStream yazma = new FileOutputStream(“c:\\
yazilan.txt”);
10
int okunanKarakter;
11
while((okunanKarakter = okuma.read()) != -1)
12
{
13
System.out.print((char)okunanKarakter);
14
yazma.write(okunanKarakter);
15
}
16
okuma.close();
17
yazma.close();
18
}
19
}
Kodun açıklaması: C sürücüsünde oluşturduğumuz okunan.txt dosyasını okuyarak içeriğini C
sürücüsündeki “yazilan.txt” dosyasında kopyalamak istiyoruz. okunan.txt dosyasını aşağıdaki gibi
oluşturabilirsiniz:
Java ile dosyadan okuma
islemi yaptık
Dosyadaki verileri okumak için FileInputStream nesnesi, dosyaya yazmak için FileOutputStream nesnesi oluşturduk. FileInputStream nesnemizin read() metodu döngünün her dönüşünde bir
byte değerini tam sayı olarak okur, ekranda görüntüler ve yazmak için açtığımız dosyaya yazar.
JAVA I/O
yazilan.txt isimli dosya disk üzerinde bulunmuyorsa FileOutputStream nesnesi tarafından oluşturulur, bulunuyorsa içi boşaltılır.
Uygulama çalıştırıldığında ekranda aşağıdaki gibi bir görüntü oluşur. Türkçe karakterlerin düzgün
görünmemesinin sebebi, okunan değerlerin unicode desteğine sahip olmamasıdır.
Java ile dosyadan okuma
i?lemi yapt?k
“yazilan.txt” dosyasının içeriği ise aşağıdaki gibi olur. Türkçe karakterlerin “yazilan.txt” dosyasına
düzgün bir şekilde aktarılmıştır.
Java ile dosyadan okuma
işlemi yaptık
Dosyadan okunan karakteri ekrana basmak için tip dönüşümü işlemini kullanarak okunan tam
sayı cinsinden verileri karakter tipine çevirdik. Tip dönüşümü yapmasaydık veriler ekrana tam
sayı olarak basılırdı. Aşağıdaki veriler, dosyadan okunan karakterlerin tam sayı cinsinden karşılığıdır. Println() metodunu kullanırken araya boşluk bırakmadığımız için bütün sayılar aralıksız
gösterildi. Bunun sebebi, boşluk karakterinin de tam sayı cinsinden bir karşılığa sahip olmasıdır.
74971189732105108101321001111151219710097110321111071171099713101
052541081011091053212197112116253107
Okuma veya yazma işlemini tek bir tamsayı ile sınırlandırmak yerine byte blokları şeklinde de
yapabiliriz. Bunun için bir tane byte dizisi tanımlanarak read() ve write() metodlarına parametre
olarak verilir. Okunan veriler byte dizisine yazılır, yazma işlemi yapılacaksa byte dizisi kullanılarak
yapılır. Örnek kod aşağıda verilmiştir.
1import java.io.FileInputStream;
2import java.io.FileOutputStream;
3import java.io.IOException;
4public class DosyaIslemleri
5{
6
public static void main(String[] args) throws IOException
7
{
8
FileInputStream okuma = new FileInputStream(“c:\\
okunan.txt”);
9
FileOutputStream yazma = new FileOutputStream(“c:\\
yazilan.txt”);
10
byte[] veri = new byte[1000];
11
int dosyaBoyutu = okuma.read(veri);
12
yazma.write(veri);
13
okuma.close();
14
yazma.close();
15
}
16
}
147
148
Bölüm 9
FileInputStream ve FileOutputStream Sınıflarının File Sınıfıyla Birlikte Kullanımı:
Duruma göre FileInputStream ve FileOutputStream nesnelerinin yapıcı metodlarına parametre
olarak dosya adı yerin File nesneleri de verebiliriz. Uygulamanın kodunun aşağıdaki gibi olması
durumunda da ekran çıktısı ve yeni oluşan dosyanın içeriği değişmeyecektir:
1import java.io.File;
2import java.io.FileInputStream;
3import java.io.FileOutputStream;
4import java.io.IOException;
5public class DosyaIslemleri
6{
7
public static void main(String[] args) throws IOException
8
{
9
File okunanDosya = new File(“c:\\okunan.txt”);
10
txt”);
File yazilanDosya = new File(“c:\\yazilan.
11
unanDosya);
FileInputStream okuma = new FileInputStream(ok
12
yazilanDosya);
FileOutputStream yazma = new FileOutputStream(
13
int okunanKarakter;
14
while((okunanKarakter = okuma.read()) != -1)
15
{
16
System.out.print((char)okunanKarakter);
17
yazma.write(okunanKarakter);
18
}
19
okuma.close();
20
yazma.close();
21
}
22
}
DataInputStream ve DataOutputStream Sınıflarının Kullanımı:
DataInputStream ve DataOutputStream sınıflarından oluşturulan nesneler kullanılarak çeşitli veri
tipleri ile okuma ve yazma işlemi yapılabilir. Bu sınıflardan oluşan nesneler ile UTF formatında
veri okunabilir ve yazılabilir. UTF formatında veri yazma kabiliyeti, farklı platformlar arasında veri
aktarımı yapılacağında kullanılır.
Aşağıdaki örnekte, bir DataInputStream ile readChar() metodunu kullanarak karakter bazında
okuma yaptıktan sonra DataOutputStream nesnesini kullanarak bu karakterleri dosyaya yazdıracağız.
1import java.io.DataInputStream;
2import java.io.DataOutputStream;
3import java.io.FileInputStream;
4import java.io.FileNotFoundException;
5import java.io.FileOutputStream;
6import java.io.IOException;
JAVA I/O
7public class DosyaIslemleri
8{
9
public static void main(String[] args) throws
FileNotFoundException, IOException
10
{
11
FileInputStream okuma = new
FileInputStream(“c:\\okunan.txt”);
12
FileOutputStream yazma = new
FileOutputStream(“c:\\yazilan.txt”);
13
DataInputStream ozellesmisOkuma = new
DataInputStream(okuma);
14
DataOutputStream ozellesmisYazma = new
DataOutputStream(yazma);
15
while(ozellesmisOkuma.available() != 0)
16
{
17
readChar();
char okunanKarakter = ozellesmisOkuma.
18
);
ozellesmisYazma.writeChar(okunanKarakter
19
}
20
ozellesmisOkuma.close();
21
ozellesmisYazma.close();
22
okuma.close();
23
yazma.close();
24
}
25
}
Kodun açıklaması: Bir önceki örnekte yaptığımız gibi FileInputStream ve FileOutputStream
nesnelerini oluşturduk. Farklı veri tipleri kullanarak okuma yapmak için DataInputStream sınıfını,
farklı veri tipleri kullanarak yazma yapmak için DataOutputStream sınıfını kullanacağımızı söylemiştik. DataInputStream sınıfının yapıcı metodu parametre olarak bir FileInputStream nesnesi,
DataOutputStream sınıfının yapıcı metodu parametre olarak bir FileOutputStream nesnesi alır.
Dosyanın sonuna gelinip gelinmediğini, DataInputStream nesnesinin available() metodu ile anlayabiliriz. Bu metod, DataInputStream nesnesinin bulunduğu yerden dosyanın sonuna kadar
okunabilecek byte sayısını döndürür. Bu metodun döndürdüğü değer sıfır olduğunda dosyanın
sonuna gelinmiş demektir. Uygulamayı çalıştırdığımızda, “yazilan.txt” dosyasının içeriğinin aşağıdaki gibi olduğunu görürüz.
Uygulamayı çalıştırdığımızda, “yazilan.txt” dosyasının içeriğinin aşağıdaki gibi olduğunu görürüz.
Java ile dosyadan okuma
işlemi yaptık
DataInputStream sınıfında bulunan readChar() metodu ile iki byte uzunluğunda okuma yapılır.
Aynı şekilde DataOutputStream sınıfında bulunan writeChar() metodu ile iki byte uzunluğunda
yazma gerçekleştirlir. Bu durumda dolayı; DataInputStream sınıfından oluşan bir nesne üzerinden okunan verileri FileOutputStream sınıfından oluşturulan bir nesne ile başka bir dosyaya yazarsak veri kaybıyla karşılaşırız.
Az önce yazdığımız örneği aşağıdaki gibi değiştirelim:
149
150
Bölüm 9
1import java.io.DataInputStream;
2import java.io.FileInputStream;
3import java.io.FileNotFoundException;
4import java.io.FileOutputStream;
5import java.io.IOException;
6public class DosyaIslemleri
7{
8
public static void main(String[] args) throws
FileNotFoundException, IOException
9
{
10
FileInputStream okuma = new
FileInputStream(“c:\\okunan.txt”);
11
FileOutputStream yazma = new
FileOutputStream(“c:\\yazilan.txt”);
12
DataInputStream ozellesmisOkuma = new
DataInputStream(okuma);
13
while(ozellesmisOkuma.available() != 0)
14
{
15
readChar();
char okunanKarakter = ozellesmisOkuma.
16
yazma.write(okunanKarakter);
17
}
18
ozellesmisOkuma.close();
19
okuma.close();
20
yazma.close();
21
}
22
}
Okuma işlemini DataInputStream nesnesi ile, yazma işlemini FileOutputStream nesnesi ile yaptık. Uygulamayı çalıştırdığımızda oluşan “yazilan.txt” dosyasının içeriği aşağıdaki gibidir.
aaiedsaa km
ilm atk
Dikkat edersek, “okunan.txt” dosyasında bulunan verilen birer karakter atlanarak “yazilan.txt”
dosyasına yazılmış olduğunu görürüz.
Reader ve Writer Sınıfları:
Java 1.1 sürümünden itibaren platforma Stream’ler üzerinde okuma ve yazma işlemlerini daha
işlevsel hale getirmek için Reader ve Writer sınıfları eklenmiştir. Bu sınıflar byte veri tipi yerine
unicode karakter tipini kullanırlar. Karakter tipinden verilerin kullanılması yazılımcının işini birçok
durumda kolaylaştırdığı gibi desteklenen karakter formatının unicode olması yazılımın farklı dilleri
desteklemesini de sağlar. InputStream ve OutputStream sınıfları aracılığıyla okunan ve yazılan
veriler 8 bitlik byte tipi verilerden oluştuğu halde, Reader ve Writer sınıfları 16 bitlik veri desteğine sahiptir. Reader ve Writer sınıfları birçok durumda InputStream ve OutputStream sınıflarının
yerine kullanılabilse de byte bazında işlemlerin yapılması gereken senaryolar da olabilir; bu gibi
durumlarda InputStream ve OutputStream sınıflarının ve bu sınıfların türevlerinin kullanılması
gerekir. Writer türevi sınıflarla Stream yapıları üzerinde append() işlemi yapılabilir.
JAVA I/O
Stream sınıflarının Reader ve Writer karşılıkları aşağıdaki tabloda gösterilmiştir.
Stream sınıfları
Reader ve Writer sınıfları
InputStream
Reader
OutputStream
Writer
ByteArrayInputStream
CharArrayReader
ByteArrayOutputStream
CharArrayWriter
FileInputStream
FileReader
FileOutputStream
FileWriter
PipedInputStream
PipedReader
PipedOutputStream
PipedWriter
StringBufferInputStream
StringReader
Verileri ve veri aktarma şekillerini biçimlendirmek amacıyla Stream sınıflarının biçimlendirilmesinde kullanılan Filter sınıflarına benzer sınıflar da vardır. Bu sınıflar aşağıdaki tabloda gösterilmiştir.
Stream sınıfları
Reader ve Writer sınıfları
FilterInputStream
FilterReader
FilterOutputStream
FilterWriter
BufferedInputStream
BufferedReader
BufferedOutputStream
BufferedWriter
DataInputStream
-
PrintStream
PrintWriter
LineNumberInputStream
LineNumberReader
FileReader ve FileWriter Sınıflarının Kullanılması:
FileReader ve FileWriter sınıflarının kullanımı, FileInputStream ve FileOutputStream sınıflarının
kullanımıyla benzerdir. Aşağıdaki örnekte FileReader nesnesi ile dosya içeriği okunmakta ve FileWriter nesnesi ile diğer dosyaya yazılmaktadır. Okuma işlemi için daha önce oluşturduğumuz
“okunan.txt” dosyası kullanılmıştır.
1import java.io.FileNotFoundException;
2import java.io.FileReader;
3import java.io.FileWriter;
4import java.io.IOException;
5public class DosyaIslemleri
6{
7
public static void main(String[] args) throws
FileNotFoundException, IOException
8
{
9
FileReader okuma = new FileReader(“c:\\okunan.txt”);
10
yazilan.txt”);
FileWriter yazma = new FileWriter(“c:\\
11
int okunanKarakter;
12
while((okunanKarakter = okuma.read()) != -1)
151
152
Bölüm 9
13
{
14
System.out.print((char)okunanKarakter);
15
yazma.write(okunanKarakter);
16
}
17
okuma.close();
18
yazma.close();
19
}
20
}
Uygulama çalıştırıldığında aşağıdaki gibi bir çıktı alınır. FileInputStream sınıfının kullanımında
Türkçe karakterler bozuk göründüğü halde FileReader sınıfı kullanıldığında Türkçe karakterler
düzgün bir şekilde görünür. “yazilan.txt” dosyası da aynı verileri içerir.
Java ile dosyadan okuma
işlemi yaptık
FileInputStream sınıfından oluşan bir nesne ile bir dosyadaki verileri byte dizisi şeklinde okuyabiliyorduk. FileReader sınıfından oluşan bir nesne ile veriler karakter dizisi şeklinde okunabilir.
Örnek kullanım aşağıdaki gibidir:
1import java.io.FileNotFoundException;
2import java.io.FileReader;
3import java.io.FileWriter;
4import java.io.IOException;
5public class DosyaIslemleri
6{
7
public static void main(String[] args) throws
FileNotFoundException, IOException
8
{
9
FileReader okuma = new FileReader(“c:\\okunan.txt”);
10
yazilan.txt”);
FileWriter yazma = new FileWriter(“c:\\
11
char[] veri = new char[1000];
12
okuma.read(veri);
13
yazma.write(veri);
14
okuma.close();
15
yazma.close();
16
}
17
}
Uygulama çalıştırıldığında, “yazilan.txt” dosyasının içeriğinin “okunan.txt” dosyasının içeriğiyle
aynı olduğu görülür.
BufferedReader Sınıfının Kullanımı:
BufferedReader sınıfını kullanarak verileri satır bazında okuyabilir ve yazabiliriz. Örnek kullanım
aşağıda verilmiştir.
1import java.io.BufferedReader;
2import java.io.FileNotFoundException;
JAVA I/O
3import java.io.FileReader;
4import java.io.FileWriter;
5import java.io.IOException;
6public class DosyaIslemleri
7{
8
public static void main(String[] args) throws
FileNotFoundException, IOException
9
{
10
txt”);
11
yazilan.txt”);
FileReader okuma = new FileReader(“c:\\okunan.
FileWriter yazma = new FileWriter(“c:\\
12
BufferedReader tamponOkuma = new
BufferedReader(okuma);
13
String satir = new String();
14
String butunVeri = new String();
15
null)
while((satir = tamponOkuma.readLine()) !=
16
{
17
18
}
19
System.out.println(butunVeri);
20
yazma.write(butunVeri);
21
tamponOkuma.close();
22
okuma.close();
23
yazma.close();
24
}
25
}
butunVeri += satir + “\n”;
Daha önceki örneklerden farklı olarak, dosyada bulunan veriler satır satır okunmuştur. BufferedReader nesnesinin readLine() metodu kullanılarak okunan satırlar satir adındaki String değişkenine aktarılır, her satır butunVeri isimli String değişkenine eklenir. butunVeri değişkeni dosyadan
okunan bütün metni saklamak amacıyla kullanılmıştır. Uygulama çalıştırıldığında ekranda ve “yazilan.txt” dosyasında aşağıdaki gibi bir görünüm oluşur.
Java ile dosyadan okuma
işlemi yaptık
Okunan satır değerinin butunVeri değişkenine eklenmesi sırasında “\n” karakteri kullanılmasaydı
bütün satırlar ekran çıktısında yan yana görünür ve “yazilan.txt” dosyasına yan yana yazılırdı.
Bunun sebebi, readLine() metodunun satırı okuduktan sonraki “\n” değerini almamasıdır. “\n”
karakterinin kullanımaması durumunda dosyadaki veri aşağıdaki gibi olur:
Java ile dosyadan okumaişlemi yaptık
153
154
Bölüm 9
Standart Giriş-Çıkış Biriminin Kullanılması:
Konsol üzerinden veri okuma ve veri yazma işlemlerinin yapılması için standart giriş-çıkış birimini
oluşturan System.in, System.out ve System.err sınıfları kullanılır. Bu sınıflar, .Net platformundaki
Console sınıfının karşılığıdır. Genelde konsole üzerinden yapılan readLine() işleminin tampon
bellek bölgesi ile kullanımı uygundur.
Konsoldan girilen verileri okuyan ve standart çıkışa yazan bir Java programı aşağıda verilmiştir.
Kullanıcı boş satır girdiğinde uygulama sonlanır.
1import java.io.BufferedReader;
2import java.io.IOException;
3import java.io.InputStreamReader;
4public class Konsol
5{
6
public static void main(String[] args) throws IOException
7
{
8
InputStreamReader giris = new
InputStreamReader(System.in);
9
BufferedReader tampon = new BufferedReader(giris);
10
String satir;
11
System.out.println(“Uygulamadan çıkmak için
enter tuşuna basın”);
12
System.out.print(“Veri girin: “);
13
satir = tampon.readLine();
14
while(satir.length() != 0)
15
{
16
satir);
System.out.println(“Girdiğiniz veri: “ +
17
System.out.print(“Veri girin: “);
18
satir = tampon.readLine();
19
} 20
}
21
}
Uygulama çalıştırıldığında kullanıcıdan sürekli veri girmesini bekler, kullanıcı Enter tuşuna bastığında uygulama sonlanır. Veri girin metninin doğru yerde görüntülenmesini sağlamak için döngüden önce readLine() metodu bir kere çalıştırılmıştır. Örnek girişlerle aşağıdaki gibi bir çıkış
üretilir:
Uygulamadan çıkmak için enter tuşuna basın
Veri girin: Java ile
Girdiğiniz veri: Java ile
Veri girin: Giriş-Çıkış
Girdiğiniz veri: Giriş-Çıkış
Veri girin: İşlemleri
Girdiğiniz veri: İşlemleri
Veri girin:
JAVA I/O
Java ile Ağ Programlama:
Ağ üzerinde bulunan farklı bilgisayarlar üzerinde çalışan programların haberleşmesi Socket yapıları ile sağlanır. Socket’ler, uygulamaların haberleşmesini sağlayan iletişim noktalarıdır. Sunucu
tarafında tanımlanan ServerSocket nesnesi ile herhangi bir istemcinin sunucuya belirli bir port
üzerinden bağlanması beklenir, istemci bağlandığında sıradaki işlemler gerçekleştirilir. Sunucu
ile istemci arasındaki veri aktarımı Socket arabirimleri üzerinden, Stream yapıları kullanılarak
gerçekleştirilir. ServerSocket sınıfı adından dolayı özelleşmiş bir Socket yapısı gibi görünse de,
temel işlevi sunucunun istemciden gelen isteği beklemesini ve istek geldiğinde bu isteği kabul
etmesini sağlamaktır. İstemci sunucuya bağlandığı zaman ServerSocket nesnesi bir Socket nesnesi oluşturarak döndürür.
ServerSocket ve Socket nesneleri kullanılarak ağ üzerinden sunucu-istemci arasında veri aktarımı yapan Java dosyaları aşağıda verilmiştir. Sunucu ve istemci için birer tane Java sınıfı oluşturulmuştur.
1// Sunucu Uygulaması
2import java.io.BufferedReader;
3import java.io.BufferedWriter;
4import java.io.IOException;
5import java.io.InputStreamReader;
6import java.io.OutputStreamWriter;
7import java.net.ServerSocket;
8import java.net.Socket;
9public class Sunucu
10
{
11
IOException
public static void main(String[] args) throws
12
{
13
ServerSocket serverSocket = new
ServerSocket(60000);
14
bekleniyor”);
System.out.println(“İstemcinin bağlanması
15
Socket clientSocket = serverSocket.accept();
16
kuruldu”);
System.out.println(“İstemci ile bağlantı
17
InputStreamReader okuma = new
InputStreamReader(System.in);
18
BufferedReader tamponOkuma = new
BufferedReader(okuma);
19
OutputStreamWriter yazma = new
OutputStreamWriter( clientSocket.getOutputStream());
20
BufferedWriter tamponYazma = new
BufferedWriter(yazma);
21
String veri = new String();
22
!= 0)
while((veri = tamponOkuma.readLine()).length()
23
{
24
tamponYazma.write(veri);
155
156
Bölüm 9
25
tamponYazma.write(“\n”);
26
tamponYazma.flush();
27
veri);
System.out.println(“Gönderilen veri: “ +
28
}
29
System.out.println(“Bağlantı kesildi”);
30
serverSocket.close();
31
clientSocket.close();
32
okuma.close();
33
yazma.close();
34
tamponOkuma.close();
35
tamponYazma.close();
36
}
37
}
Kodun açıklaması: Sunucu üzerinde tanımlanan ServerSocket nesnesi, daha önce anlatıldığı
gibi istemcinin bağlanmasını bekler ve bir istemci bağlanana kadar uygulamanın çalışmasını elinde tutar. İstemci sunucuya bağlandıktan sonra ServerSocket nesnesinin accept() metodu Socket
cinsinden bir nesne döndürür. Bu nesne ile sunucu istemciyle iletişim kurar. “okuma” isimli InputStreamReader nesnesi, standart giriş-çıkış biriminden veri almak için kullanılır. Standart giriş-çıkış
biriminden alınan verileri satır bazında okumak için BufferedReader nesnesi kullanılmıştır. Benzer şekilde Socket nesnesi üzerinden istemciye veri göndermek için OutputStreamWriter nesnesi
oluşturulmuştur. OutputStreamWriter sınıfının yapıcı metoduna parametre olarak Socket nesnesinin getOutputStream() metodundan dönen OutputStream nesnesi verilir. Verileri istemciye satır
bazında göndermek için BufferedWriter nesnesi kullanılmıştır. Bir döngü içinde standart giriş-çıkış
biriminden okunan veriler BufferedWriter nesnesi aracılığıyla istemciye gönderilir. BufferedWriter
nesnesine veriyi yazdıktan sonra flush() komutu çalıştırılır. Bunun sebebi satır bazında gönderilen
verinin hemen Stream’e yazılmasını sağlamaktır. Kullanıcı boş satır girdiğinde döngü sonlanır ve
bağlantı sunucu tarafından kesilir.
1// İstemci Uygulaması
2import java.io.BufferedReader;
3import java.io.IOException;
4import java.io.InputStreamReader;
5import java.net.Socket;
6public class Istemci
7{
8
public static void main(String[] args) throws IOException
9
{
10
Socket socket;
11
try
12
{
13
14
}
15
catch(IOException ex)
16
{
socket = new Socket(“127.0.0.1”, 60000);
JAVA I/O
17
kurulamadı”);
System.out.println(“Bağlantı
18
return;
19
}
20
InputStreamReader okuma = new
InputStreamReader(socket.getInputStream());
21
BufferedReader tamponOkuma = new
BufferedReader(okuma);
22
kuruldu”);
System.out.println(“Sunucu ile bağlantı
23
String veri = new String();
24
try
25
{
26
null)
while((veri = tamponOkuma.readLine()) !=
27
{
28
+ veri);
29
}
30
System.out.println(“Gelen veri: “
System.out.println(“Bağlantı kesildi”);
31
}
32
catch(IOException ex)
33
{
34
System.out.println(“Bağlantı hatası”);
35
}
36
finally
37
{
38
okuma.close();
39
tamponOkuma.close();
40
socket.close();
41
}
42
}
43
}
Kodun açıklaması: İstemci tarafında, sunucu ile iletişim kurmak için bir Socket nesnesi tanımlanır. İstemci üzerinde çalışan uygulamada ServerSocket nesnesi kullanılmamıştır, bunun sebebi
istemcinin herhangi bir port üzerinden bağlantı beklememesidir. İstemci sadece sunucuya bağlanmak ve veri almak için tasarlanmıştır. Verilen IP adresine belirtilen port üzerinden bağlantı
kurulamazsa IOException oluşur ve program sonlanır. Sunucu çalıştırılmadan istemci çalıştırılırsa bahsedilen hata mesajı alınır. Sunucu uygulamadan Stream üzerinden gelen verileri almak
için InputStreamReader nesnesi, gelen verileri satır bazında işleyebilmek içinse BufferedReader
nesnesi kullanılmıştır. Sunucu üzerinde çalışan uygulamada olduğu gibi istemcide de InputStreamReader sınıfının yapıcı metoduna parametre olarak Socket nesnesinin getInputStream()
metodundan dönen InputStream nesnesi verilir. Sunucuyla bağlantı kurulduktan sonra bir sonsuz
döngü içinde sunucudan gelen mesajlar BufferedReader nesnesinin readLine() metodu ile satır
bazında alınır ve standart çıkışa yazılır. Bu noktadan sonra IOException oluşursa sunucunun
kapandığı anlaşılır ve “bağlantı kesildi” mesajı verilir.
157
158
Bölüm 9
Her iki uygulamada da Stream ve Socket nesnelerini kapatmayı unutmamalıyız.
Sunucu ve istemci uygulamalarının farklı şekillerde çalıştırılmaları aşağıdaki gibi çıktılar verir.
1.Sunucu çalıştırılmadan istemci çalıştırıldığında:
Bağlantı kurulamadı
2.Sunucu çalıştırıldıktan sonra istemcinin bağlanmasını beklerken:
İstemcinin bağlanması bekleniyor
3.İstemci ile sunucu arasında bağlantı kurulduğunda:
Sunucu tarafı:
İstemcinin bağlanması bekleniyor
İstemci ile bağlantı kuruldu
İstemci tarafı:
Sunucu ile bağlantı kuruldu
4.Sunucudan istemciye mesaj gönderildiğinde:
Sunucu tarafı:
İstemcinin bağlanması bekleniyor
İstemci ile bağlantı kuruldu
Java ile
Gönderilen veri: Java ile
Ağ Programlama
Gönderilen veri: Ağ Programlama
İstemci tarafı:
Sunucu ile bağlantı kuruldu
Gelen veri: Java ile
Gelen veri: Ağ Programlama
5.Bağlantı kesildiğinde:
Sunucu tarafı:
İstemcinin bağlanması bekleniyor
İstemci ile bağlantı kuruldu
Java ile
Gönderilen veri: Java ile
Ağ Programlama
Gönderilen veri: Ağ Programlama
Bağlantı kesildi
İstemci tarafı:
Sunucu ile bağlantı kuruldu
Gelen veri: Java ile
Gelen veri: Ağ Programlama
Bağlantı kesildi
10
Oracle
Veritabanı
Ailesi
10 Oracle Veritabanı Ailesi
• Oracle Üzerinde Uygulama Geliştirme
• Oracle Veri Tabanı Sisteminin Kurulması
• Tablespace
• Undo Tablespace
• Oracle’da Veri Tabanı Oluşturmak
• Temel Veri Tipleri
Oracle Veritabanı Ailesi
Oracle Personal Edition: Microsoft SQL Server 2005’teki Express Edition gibi düşünülebilir.
Kişisel veritabanıdır. Uygulama geliştirme için kullanılır.
Oracle Standard Edition: Giriş seviyesinde çok kullanıcılı sürümdür. Microsoft SQL Server 2005
Standard Edition’a karşılık olarak düşünülebilir.
Oracle Enterprise Edition: En geniş kapsamlı sürümdür. Microsoft SQL Server 2005 Enterprise
Edition’a karşılık olarak düşünülebilir.
Oracle Lite: Mobil uygulamalar için kullanılır.
Oracle Üzerinde Uygulama Geliştirme
Oracle üzerinde uygulama geliştirme için kullanılacak çeşitli diller ve ortamlar mevcuttur. Bunlar
SQL, PL/SQL, Java olarak sayılabilir. Bunların dışında .NET, C, C++ gibi dil ve ortamlardan erişim
yapılabilir.
PL/SQL: Microsoft SQL Server’daki T-SQL’e karşılık olarak düşünülebilecek olan prosedürel SQL
genişletmesidir. Oracle üzerinde PL/SQL kullanılarak SP (stored procedure), trigger gibi nesneler
oluşturulabilir. T-SQL’deki gibi değişkenler, döngüler ve koşullar PL/SQL’de de mevcuttur. SQL
Plus arayüzü kullanılarak ya da TOAD ile PL/SQL yazılabilir.
Java: Microsot SQL Server üzerine .NET ile nesnelerin yazılmasına karşılık olarak, bunun için
Oracle tarafında Java kullanılır.
Oracle Veri Tabanı Sisteminin Kurulması
1� Öncelikle, eğer değilse, bilgisayarınızın bölgesel ayarlarını İngilizce olarak değiştirmeniz gerekir. Bunun için, Start > Control Panel > Regional and Language Options’ tan (Başlat >
Denetim Masası > Bölge ve Dil Seçenekleri) English (United States) (İngilizce (A.B.D.)) olarak
belirleyin.
162
Bölüm 10
2. Daha sonra, Advanced (Gelişmiş) sekmesinde kullanılan dil seçeneği olarak yine English
(United States) (İngilizce (A.B.D))‘yi seçin ve tamam butonuna tıklayın.
3� Tamam butonuna tıkladığınızda, gerekli dosyaların bilgisayarınızda yüklü olduğunu ve
Setup’ın (Kur) dosyaları buradan kurabileceğini belirten bir uyarı ile karşılaşabilirsiniz. Bu
durumda, Yes (Evet) seçeneğini tıklayın. Ardından Windows bilgisayarınızı yeniden başlatmak isteyebilir. Bu durumda yine Yes (Evet) seçeneğini tıklayarak bilgisayarınızı yeniden
başlatın.
4. Ardından Oracle10g kurulu dosyalarının bulunduğu klasöre giderek setup.exe’yi çalıştırın.
Karşınıza ilk olarak daha önce yüklenmiş bir Oracle ürünü olup olmadığını kontrol eden bir
işlem penceresi gelecektir.
Oracle Veritabanı
5. Kontol işleminin ardından gelen ekranda yükleme seçeneği olarak Basic Installation ve Advanced Installation olmak üzere iki yöntem karşınıza çıkacaktır. Bunlardan Basic Installation
seçeneğini seçin. Böylelikle birçok ayarın otomatik olarak yapılması sağlanacaktır.
Oracle Home Location: Veritabanının kurulacağı klasörün yerini belirtir.
Installation Type: Kurulum tipini belirtir. Standart ya da Enterprise Edition olarak belirlenir.
Create Starter Database: Bu seçenek işaretlendiğinde kurulum işlemi gerçekleştikten sonra
veritabanı da oluşturulur. Aksi halde sadece Oracle 10g kurulumu gerçekleştirilecek, veritabanı
yaratmak için SQL-Plus altından Create Database komutu ile veritabanı oluşturmak gerekecektir.
Bu seçeneğin işaretli olmasına dikkat edin.
Global Database Name: Veritabanının adı girilir.
Database Password: Veritabanı şifresi girilir. Bu bölümde girilen şifre kesinlikle unutulmamalıdır.
Oracle’da en üst seviyedeki admin kullanıcısı “sys” olarak hazır gelmekte ve burada belirlenen
şifre bu kullanıcının şifresi olarak belirlenmektedir.
Confirm Password: Girilen şifre tekrar teyit amacıyla bu bölüme girilir.
Girişleri tamamladıkan sonra Next butonuna tıklayın.
1� Karşınıza gelen pencerede, kurulum sırasında yaptığınız seçimleri özet olarak görebilirsiniz.
Değişiklik yapmak isterseniz Back butonuna tıklayarak geri dönebilirsiniz. Daha sonra Install
butonuna tıklayarak devam edin.
163
164
Bölüm 10
2. Kurulum işlemi otomatik olarak başlayacaktır.
3� Kurulum sırasında belirlenen ayarlar çerçevesinde konfigürasyon işlemleri otomatik olarak
gerçekleştirildikten sonra işlemlerin özeti görüntülenir. Yine Next butonuna tıklayın.
Oracle Veritabanı
4. Veritabanı otomatik olarak oluşturulur.
5. Daha sonra, oluşturulan veritabanı ile ilgili bilgilerin özetlendiği ve şifre ayarlarının yapılabildiği pencere gelir.
165
166
Bölüm 10
6. Özet penceresinde yer alan Password Management butonuna tıklandığında açılan ekrandan,
varsayılan kullanıcılara ilişkin şifre değişiklikleri ve kilitli/kilitsiz ayarları yapılabilir.
7. Belirtilen ayarların yapılmasından sonra, kurulum tamamlanır. Exit butonuna tıklayarak çıkın.
8. Açılan browserdan Oracle Enterprise Manager’a kullanıcı adı ve şifre ile giriş yapabilirsiniz.
Oracle Veritabanı
Tablespace
Microsoft SQL Server’da data file olarak geçen MDF ve NDF uzantılı dosyalar Oracle’da
tablespace’lerde tutulur.
system Tablespace
system tablespace’i Oracle’ın veri sözlüğünü barındırır. Bu da Microsoft SQL Server’daki master
veritabanındaki metadata tutan sys ile başlayan tablolar gibi düşünülebilir.
sysaux Tablespace
Eskiden system tablespace’te yer alan birtakım veriler ve özellikler 10g ile birlikte sysaux
tablespace’ine alınmıştır. Oracle sisteminin kullandığı bir tablespace olarak düşünülmelidir.
Default Temporary Tablespace
Default Temporary Tablespace ilgili veritabanında çalıştırılan sorgu için bellek alanı yetersiz geliyorsa disk üzerinde bellek alanı gibi kullanılır. Windows ve Linux gibi işletim sistemlerinde kullanılan swap alanı gibi düşünülebilir.
Undo Tablespace
Microsoft SQL Server’daki Transaction Log Space gibi düşünülebilir. Herhangi bir transaction
başladığında rollback ya da commit edilene kadar undo tablespace’te eski veri tutulur.
Arka Planda Çalışan Processler
Veritabanı sisteminin düzenli çalışabilmesi için arka planda çalışan birtakım process’lere ihtiyaç
vardır. Oracle’da çalışan temel arka plan process’leri şunlardır:
dbwr – Database Writer Process: Tampon bölgelere alınan verilerin veritabanına yazılmasından sorumludur.
lgwr – Log Writer Process: Online redo logları bellekte geçici olarak tutulur. Bu log’ların veritabanına aktarılmasından log writer process sorumludur.
ckpt – Chekpoint Process: Checkpoint işlemi bellekteki verilerin veritabanı üzerinde uygun bölümlere yazılmasından sorumludur. Checkpoint process database writer ve log writer’ı tetikleyebilir.
167
168
Bölüm 10
smon – System Monitor Process: System monitor process veritabanlarının bütünlüğü ve tutarlılığından sorumludur.
pmon – Process Monitor: .NET ortamındaki garbage collector gibi düşünülebilir. Genel olarak
kaynak yönetimi yaptığını söyleyebiliriz.
Oracle’da Veri Tabanı Oluşturmak
Oracle’da veri tabanı oluşturmak için kullanılabilecek en kolay yol Oracle Database Configuration
Assistant (DBCA) kullanmaktır. DBCA’e Start > Programs > Oracle Oracle Home > Configuration
and Migration Tools > Database Configuration Assistant yoluyla ulaşılır. Program açılınca bir
sihirbaz aracılığıyla veri tabanını yapılandırabiliriz.
Şekil 1: DBCA açılış ekranı.
Sihirbazın ilk adımı sadece bilgilendirici bir ekrandır. Bu adımda Next butonuna tıklayarak devam
edebiliriz. Bu adımdan sonra veri tabanını oluşturmak için önümüze çıkan kavramları, opsiyonlarla birlikte değerlendireceğiz.
Sihirbazın ikinci adımında veri tabanı yönetiminde ne yapacağımızı belitmemiz gerekir. Burada ilk
seçenek olan Create a Database (Veri tabanı oluştur) seçeneğini seçeceğiz. Diğer opsiyonlar ve
açıklamaları da aşağıdaki gibidir; fakat sihirbazı bu seçeneklere göre ilerletmeyeceğiz.
Opsiyon
Açıklama
Create a Database
Sihirbazla adım adım veritabanı oluşturmak için kullanılır. Varolan veri
tabanı şablonları kullanılabildiği gibi şablonlardan farklılaştırarak da veri
tabanı oluşturulabilir.
Configure Database Options
Var olan bir veri tabanının dedicated (adanmış) bir sunucudan Shared
(paylaşılan) bir sunucuya taşınması için gerekli işlerin yapılmasını sağlar.
Delete a Database
Var olan bir veri tabanının tamamen silinmesini sağlar.
Manage Templates
Veritabanı şablonlarının yönetilmesini sağlar. Şablonlar yerel diskte XML
formatında saklanmaktadır. Mevcut şablonlarda değişiklik yapılabilir ya da
yeni bir şablon oluşturulabilir.
Oracle Veritabanı
Şekil 2: DBCA ilk kurulum ekranı.
Şekil 3: DBCA veri tabanı şablonu seçme ekranı.
Şekil 3’deki veri tabanı şablonu seçim ekranında yeni oluşturulacak veri tabanının yapısı belirlenir. Herhangi bir şablonu seçerek sağ alt köşedeki Shoe Details butonuna tıklayarak şablonun alt yapısı hakkında bilgi alabilirsiniz, ancak bu aşamada kavramlar karmaşık gelebilir. Her
şablon için genel veri tabanı özellikleri, başlangıç parametreleri, karakter setleri, veri dosyaları
(tablespace’ler), kontrol dosyaları ve redo log grupları hakkında bilgileri bu pop-up’tan görebilirsiniz; ancak mevcut şablonların yapıları üzerinde değişiklik yapamazsınız. Burada hazır olarak
göreceğiniz şablonlar Data Warehouse, General Purpose ve Transaction Processing’tir. Burada
General Purpose seçeneğini seçip Next butonuna tıklayarak devam edebiliriz.
169
170
Bölüm 10
Şekil 4: DBCA veri tabanı isimlendirme ekranı.
Sihirbazın 3. adımında Şekil 4’te gördüğümüz isimlendirme ekranı gelir. Bu ekranda veri tabanı
adı ve SID (system identification)’si tanımlanır. Veri tabanı adı yazarken SID’de de aynı karakterlerin yazıldığını göreceksiniz. Bir sistemde aynı isimde birden fazla veri tabanı olabilirken aynı
SID’ye sahip birden fazla veri tabanı bulunamaz. Aynı zamanda SID’nin maksimum uzunluğu 8
karakterdir. SID kısmına 8 karakterden daha uzun bir ifade yazsanız da SID 8 karaktere kısaltılacaktır. Bu ekranda veri tabanı adına ve SID’ye “ornek” yazıp Next butonuna tıklayarak devam
edebiliriz.
Şekil 5: DBCA yönetim seçenekleri ekranı.
Oracle Veritabanı
Şekil 5’teki yönetim seçenekleri ekranında veri tabanının Enterprise Manager (EM) ile kontrol
edilip edilemeyeceği seçeneği ile birlikte uyarıların e-mail ile gönderilmesi ve backup seçenekleri tanımlanır. Bu ekranda Configure the Database with Enterprise Manager seçeneğeni işaretli
olarak bırakalım. Eğer makinenizde grid kurulumu varsa ilk opsiyon olan Use Grid Control for
Database Management opsiyonu da açık olacaktır. Diğer opsiyon olan Use Database Control for
Database Management seçeneği mecburen seçili olarak kalarak devam edecektir. Enable Email
Notifications ve Enable Daily Backup seçeneklerini işaretlemeden devam edebiliriz.
Şekil 6: DBCA şifre tanımlamaları ekranı.
Şekil 6’daki şifre tanımlama ekranında SYS, SYSTEM, DBSNMP ve SYSMAN kullanıcıları için
şifre tanımlamaları yapmamız gerekir. Burada 2 seçenek mevcuttur. Birincisi varsayılan olarak
seçili gelen Use the Same Password for All Accounts seçeneğidir. Bu seçenekte yukarıda adı
geçen 4 sistem kullanıcısı için de yazılan aynı şifre geçerli olur. Eğer veri tabanını yönetirken bu
4 hesabı tek kişi kullanıyorsa hepsi için tek şifre tanımlamak daha uygun olacaktır. Diğer seçenek
olan Use Different Password seçilirse 4 kullanıcının hepsi için farklı farklı şifreler tanımlanabilir.
Bu noktada adı geçen kullanıcıların özelliklerini listeleyelim:
Kullanıcı
Özellik
SYS
SYS kullanıcısı veri sözlüğünü oluşturan tüm iç Oracle tablolarının sahibidir. SYS
kullanıcısıyla hiçbir işlem yapılmaması için bu hesabın kilitlenmesi tercih edilmelidir. SYS
kullanıcısının sahibi olduğu nesnelerde de değişiklik yapılmamalıdır.
SYSTEM
SYSTEM kullanıcısı birtakım yönetimsel tabloların ve view’ların sahibidir. Yetkisiz kullanım
ihtimaline karşı kilitlenmesi ve kullanılmaması tercih edilmelidir.
DBSNMP
Veri tabanı hakkında performans istatistiklerini toplamak ve görüntülemek amacıyla
Enterprise Manager tarafından kullanılan kullanıcıdır.
SYSMAN
Enterprise Manager’da SYS kullanıcısıyla aynı haklara sahiptir.
Bu ekranda Use the Same Password for All Accounts seçiliyken şifreyi 2 defa yazıp Next butonuna tıklayarak devam edebiliriz.
Şekil 7’deki saklama seçenekleri ekranında 3 seçenek söz konusudur. Bu ekranda dikkat edeceğimiz bir nokta da bu aşamada Finish butonuna tıklayarak veri tabanı oluşturma işlemini tamamlayabilecek olmamızdır. Bundan sonraki sihirbaz ekranı buradaki seçime göre değişir. Bu
seçeneklerin özellikleri şu şekildedir:
171
172
Bölüm 10
Şekil 7: DBCA Diskte saklama seçenekleri ekranı.
Saklama Seçenekleri
Özellik
File System
En çok kullanılan seçenektir. Veri tabanının disk üzerinde normal bir veri
tabanı gibi oluşturulmasını sağlar.
ASM Storage
ASM (Automatic Storage Management) için öncelikle CSS (Oracle Cluster
Synchronization Service) kurulumu yapılması gerekir. Disk yönetimini
File System seçeneğine göre kolaylaştırır. Birçok işi veri tabanı yöneticisi
yerine Oracle kendisi yapar.
Raw Devices
Veri tabanı dosyalarını işletim sistemi yerine donanım aracılığıyla
doğrudan Oracle yönetir. RAC (Real Application Cluster) veri tabanları için
paylaşımlı alan olarak kullanılabilir.
Bu adımda File System seçeneğini işaretleyip Next butonuna tıklayarak devam edebiliriz.
Şekil 8’deki veri tabanı dosyaları ekranında tanımladığımız veri tabanına ait fiziksel dosyaların
nereye konulacağı belirtilir. Bu adımda 3 seçenek mevcuttur. Bu seçeneklerin açıklamaları şu
şekilde özetlenebilir:
Seçenek
Açıklama
Use Database File
Locations From Template
Daha önce seçilen şablona göre veri tabanı dosyalarının yerleri belirlenir,
sonradan değiştirilebilir.
Use Common Location fo
All Database Files
Veri tabanı dosyalarının yeri için farklı bir klasör tanımlamak için kullanılır,
belirlenen klasör sonradan değiştirilebilir.
Use Oracle-Managed Files
Diskte saklama seçeneklerinde ASM seçildiyse bu seçenek seçilmelidir.
Bu seçenek seçildiğinde dosyaların yerleri veya adları ile ilgili sonradan
yapılamaz.
Oracle Veritabanı
Şekil 8: DBCA dosya konumlandırma ekranı.
Bu adımda Use Database File Locations From Template seçeneğini seçip Next butonuna tıklayarak devam edebiliriz.
Şekil 9: DBCA kurtarma yapılandırması ekranı.
Şekil 9’daki kurtarma yapılandırası ekranı backup ve kurtarma işlemlerinin yapılandırılması için
kullanılır. Bu aşamada 2 seçenek mevcuttur ve her ikisi bir arada da kullanılabilir seçeneklerdir.
İlk seçenek olan Specify Flash Recovery Area seçildiğinde ilgili dosyaların nerede saklanacağı
ve bu alanın MB cinsinde büyüklüğü tanımlanır. Bu alan tercihen fiziksel olarak veri tabanı dosyalarının bulunduğu yerden farklı olmalıdır. Diğer seçenek olan Enable Archiving seçeneği seçili
olduğunda arşiv loglaması yapacağımızı ifade eder. DBCA kurtarma yapılandırması ekranında
173
174
Bölüm 10
sadece Specify Flash Recovery Area seçeneğini işaretleyip Next butonuna tıklayarak devam
edebiliriz.
Şekil 10: DBCA veri tabanı içeriği ekranı, Database Components sekmesi.
Şekil 10’daki veri tabanı içeriği ekranının Database Components sekmesinde, Oracle Data Mining, Oracle Text, Oracle OLAP gibi Oracle veritabanı bileşenlerinin hangilerinin kurulan veritabanı için kullanılacağı ve hangi tablespace üzerine yerleştirileceği belirlenir. Bu sekmede sample
Schemas seçeneğini işaretlemeden Custom Scripts sekmesine geçelim.
Şekil 11: DBCA veri tabanı içeriği ekranı, Custom Scripts sekmesi.
Veri tabanı içeriği Custom Scripts sekmesinde, veri tabanı oluşturulduktan sonra üzerinde çalışmasını istediğimiz bir SQL script dosyası varsa bu dosyayı seçerek birtakım kurulumların oto-
Oracle Veritabanı
matik olarak yapılmasını sağlayabiliriz. Bu ekranda No scripts to run seçeneğini işaretleyip Next
butonuna tıklayarak devam edebiliriz.
Şekil 12: DBCA başlangıç parametreleri, Memory sekmesi.
Şekil 12’deki başlangıç parametreleri, Memory sekmesinde oluşturduğumuz veritabanı için fiziksel bellek alanı üzerinde ne kadar yer kullanılacağını tanımlayabiliriz. Typical– Allocate memory
as a percentage of total physical memory seçeneği ve Custom seçeneği bulunur. Eğer 1.seçenek
seçilirse bellek yönetimini Oracle kendisi yapar. Diğer seçenekte ise bellek yönetiminde SGA
(System Global Area) ve PGA (Process Global Area) için bellekte ne kadar yer ayıracağımızı
belirtebiliriz. Bu sekmede 1.seçeneği işaretleyerek Sizing sekmesine geçelim.
Şekil 13: DBCA başlangıç parametreleri, Sizing sekmesi.
175
176
Bölüm 10
Şekil 13’deki başlangıç parametreleri, Sizing sekmesinde Microsoft SQL Server’daki veri sayfasına (data page) karşılık gelen blok boyutu girilebilir. Transactional veri tabanları için bu boyut
genellikle 8KB’dir. Data warehouse için 16KB ve üstü düşünülmelidir. Processes’de belirtilen sayı
işletim sisteminden bu veritabanına açılabilecek maksimum eş zamanlı process sayısını belirtir.
En başta belirtilen arka planda çalışan process’ler için en az 6 olarak tanımlanmalıdır. Burada
belirtilen sayı büyüdükçe bellekte SGA olarak bu veri tabanı için ayrılacak alan büyüyecektir.
Buradaki sayıyı da 150’de bırakarak Character Sets sekmesine geçelim.
Şekil 14: DBCA başlangıç parametreleri, Character Sets sekmesi.
Şekil 14’teki başlangıç parametreleri, Character Sets sekmesinde yerelleştirme ayarları yapılır.
Bu ayarları Microsoft SQL Server’daki collation yapılandırması gibi düşünebiliriz. Use the default
seçeneği işletim sisteminde o andaki seçili karakter setine göre, Use Unicode, Unicode’a göre,
Choose from the list of character sets’de seçeceğimiz karakter setine göre veri tabanını yapılandırır. Bu 3’lü seçimin altında bulunan National Character Set Unicode olarak tanımlanmayan karakter setine alternatif Unicode karakter setinin eklenmesini sağlar. Default Language, tarih, AM,
PM gibi yerel ayarlar ve ORDER BY ile sıralama yapısının hangi dile göre yapılacağını belirler.
Default Date Format ise tarih verilerinin hangi ülkeye, dile göre gösterileceğini tanımlar. Bu sekmede sadece Use the Default seçeneğini seçip, diğer hiçbir seçeneği değiştirmeden Connection
Mode sekmesine geçelim.
Şekil 15’teki başlangıç parametreleri, Connection Mode sekmesinde Oracle veri tabanı sunucusuna bağlantı şekli belirtilir. Burada 2 seçenek mevcuttur. Dedicated Server Mode seçildiğinde
veri tabanına bağlanan her istemci için ayrı bir kaynak ayrılır. Eğer veri tabanına bağlanan kullanıcı sayısı çok değişken değil ve az sayıdaysa ve bağlanan kullanıcılar çok kısa sürede bağlantılarını sonlandırmıyorlarsa bu seçenek seçilmelidir. 2. seçenek olan Shared Server Mode ise bir
önceki seçenek için tanımlanan durumların dışında kalan uygulamalar için idealdir. Bu seçenekte
kaynakların ortak kullanımı söz konusu olduğundan ne kadar ortak server process’inin oluşturulacağı tanımlanmalıdır. Genellikle çoğu OLTP veri tabanı için Shared Server Mode, çoğu OLAP veri
tabanı için de Dedicated Server Mode daha doğru seçim olacaktır. Bu sekmede Shared Server
Mode seçeneğini işaretleyip, Shared Server sayısını 1 bırakıp (bu veri tabanı oluşturma işlemi
örnek olduğu için 1’de bıraktık, bu sayı veri tabanının kullanım yoğunluğuna ve gelen istemlerin
büyüklüklerine göre ayarlanmalıdır) Next butonuna tıklayarak devam edebiliriz.
Oracle Veritabanı
Şekil 15: DBCA başlangıç parametreleri, Connection Mode sekmesi.
Şekil 16: DBCA veri tabanı saklama yapısı ekranı.
Şekil 16’daki veri tabanı saklama yapısı ekranından daha önce belirlediğimiz (örnek şablona göre
seçtiğimiz için tek tek tanımlamadık) veri tabanına yazılacak dosyaların yerleri ve isimleriyle ilgili
değişiklikleri yapabilmemizi sağlar. Bu ekrandan soldaki ağaç yapısından kontrol dosyaları, veri
dosyaları ve log dosyalarının yerlerini ve yapıları görüntülenip değiştirilebilir. Burada herhangi bir
değişiklik yapmadan Next butonuna tıklayarak devam edelim.
Şekil 17’deki veri tabanı oluşturma ekranı DBCA sihirbazının son ekranıdır. Bu ekranda 3 seçenek
mevcuttur. Create Database seçeneği tanımladığımız veri tabanının fiziksel olarak oluşturulmasını sağlar. Save as a Database Template seçeneği yapılandırdığımız veri tabanı yapısının şablon
olarak saklanmasını sağlar. Generate Database Creation Scripts seçeneği de yapılandırdığımız
177
178
Bölüm 10
veri tabanı yapısnın script’inin oluşturulmasını sağlar. Bu ekrandaki seçeneklerini herhangi birini,
ikisini ya da hepsini seçebiliriz. Sadece Create Database seçeneğini seçerek Finish butonuna
tıklayarak tanımladığımız veri tabanını oluşturalım.
Şekil 17: DBCA veri tabanı oluşturma ekranı. Sihirbaz veri tabanını oluşturmadan önce tüm parametreleri özet şeklinde çıkarır. Bu ekran üzerinden değişiklik yapılamaz. Save as an HTML file seçeneğiyle bilgi olarak saklamak faydalı olabilir. OK butonuna tıkladığımızda veri tabanı oluşturulmaya başlayacaktır.
Şekil 18: Veri tabanı parametreleri ekranı.
Oracle Veritabanı
Şekil 19: Veri tabanı oluşturma ekranı.
Şekil 19’da veri tabanının oluşturulma sürecini görebilirsiniz. Böylece Oracle üzerinde örnek veri
tabanı oluşturma işlemini tamamlamış olduk.
Temel Veri Tipleri
varchar2: 4000 taneye kadar karakter tutabilen veri tipidir. Microsoft SQL Server’daki varchar
veri tipi gibi düşünülebilir. Eğer saklanacak verinin başında ya da sonunda boşluk (space) karakteri varsa bunları silerek tutar.
nvarchar2: 4000 taneye kadar Unicode karakter tutabilen veri tipidir. Microsoft SQL Server’daki
nvarchar veri tipi gibi düşünülebilir. Eğer saklanacak verinin başında ya da sonunda boşluk (space) karakteri varsa bunları silerek tutar.
char: 2000 taneye kadar sabit uzunluklu karakter tutabilen veri tipidir. Microsoft SQL Server’daki
char veri tipi gibi düşünülebilir.
nchar: 2000 taneye kadar sabit uzunluklu Unicode karakter tutabilen veri tipidir. Microsoft SQL
Server’daki nchar veri tipi gibi düşünülebilir.
number: Her türlü sayısal verilerin tutulabileceği veri tipidir. Microsoft SQL Server’daki int, float gibi veri tiplerine karşılık olarak düşünülebilir. Dikkat edilmesi gereken nokta Microsoft SQL
Server’daki decimal gibi tanımlanmasıdır.
date: Saniye bazında tarih ve zaman verisi tutar. Geçerli tarih aralığı MÖ 1 Ocak 4712’den MS 31
Aralık 9999’a kadardır. Microsoft SQL Server’daki smalldatetime veri tipi gibi düşünülebilir.
timestamp: date tipine çok benzeyen bir veri tipidir. date tipine göre daha detaylı zaman bilgisi
tutar. Microsoft SQL Server’daki datetime veri tipi gibi düşünülebilir.
clob (character large object): 4 GB’a kadar karakter verisi tutar. varchar2’nin büyütülmüş bir
tipi olarak düşünülebilir. Microsoft SQL Server 2005 ile birlikte gelen varchar(max) veri tipi gibi
düşünülebilir.
blob (binary large object): clob’a benzer bir veri tipi olmakla birlikte içinde tuttuğu veri tipi
binary’dir. Maksimum büyüklüğü 4 GB’tır. Microsoft SQL Server’daki text, image tiplerine benzerdir.
Oracle’da Kullanıcı Yönetimi ve Güvenlik
Oracle sisteminde kullanıcı yönetimi ve güvenlik Microsoft SQL Server’a göre daha detaylıdır;
çünkü Microsoft SQL Server sadece Microsoft Windows ailesi işletim sistemlerinde çalışırken
179
180
Bölüm 10
Oracle Microsoft Windows ailesi, UNIX türevleri ve Linux türevleri üzerinde de çalışmaktadır. Bu
sebeple kullanıcı yapısı farklılıklar göstermektedir. Örneğin Microsoft SQL Server’da olan “Windows Authentication” Oracle için geçerli değildir; ancak bunu karşılayan farklı bir yapı mevcuttur.
Ayrıca Oracle’da kullanıcı, hesap ve şema (schema) ifadeleri aynı anlamda kullanılabilir. Kimlik
denetleme yöntemlerine geçmeden önce kimlik denetiminde kullanılan bazı kavramları tanımlayalım.
Default Tablespace: Bir kullanıcının oluşturduğu/oluşturacağı nesnelerin (schema objects),
nesne oluşturulurken nesnelerin hangi tablespace üzerinde tutulacağı belirtilmediğinde default
olarak tutulduğu tablespace’tir. Kullanıcı tanımlanırken belirtilmezse, veri tabanı kendi default
tablespace’ini kullanıcıya da default tablespace olarak atar.
Ara İşlemler İçin Kullanılan (Temporary) Tablespace: Temporary tablespace üzerinde GROUP
BY, ORDER BY, DISTINCT, JOIN ve index oluşturma gibi geçici alan ihtiyacı olan işlemlerde kullanılan tablespace’tir, aynı zamanda geçici tablolar için de kullanılır. Kullanıcı tanımlanırken belirtilmezse, veri tabanı kendi default tablespace’ini kullanıcıya da default tablespace olarak atar.
Profiller: Kullanıcı yönetimini kolaylaştıran bir mekanizmadır. Her kullanıcı mutlaka bir profil altında tanımlıdır. Kaynakların kullanınımı profil tanımına göre kısıtlar ve şifre kurallarının tanımlanmasını sağlar. Kullanıcı tanımlanırken belirtilmezse, kullanıcı Oracle default profile atanır.
Authentication (Kimlik Denetleme) Yöntemleri
Oracle’da 3 kimlik denetleme yöntemi vardır. Bu yöntemler şu şekildedir:
1� Password Authentication
2. External Authentication
3� Global Authentication
Password Authentication
Microsoft SQL Server’daki SQL Authentication ile eşleniktir. Kullanıcılar Oracle veri tabanı üzerinde tanımlıdır. Oracle kullanıcıya ait şifreyi üzerinde şifreli olarak tutar. Password Authentication
ile kullanılacak bir kullanıcı şöyle tanımlanır:
CREATE USER kaya IDENTIFIED BY qwedcv89;
Burada “kaya” kullanıcının adıyken “qwedcv89” bu kullanıcın şifresidir.
Bu kullanıcıya ait bir default tablespace; yani oluşturacağı nesnelerin tutulacağı bir tablespace
belirtmek istersek;
CREATE USER kaya IDENTIFIED BY qwedcv89
DEFAULT TABLESPACE xyz;
ifadesini kullandığımızda bu kullanıcının nesnelerinin yaratılacağı default tablespace xyz adlı
tablespace olacaktır. Eğer “kaya” kullanıcısı daha önceden oluşturulduysa ALTER ifadesi ile de
default tablespace tanımlayabiliriz.
ALTER USER kaya
DEFAULT TABLESPACE xyz;
Bu kullanıcı için bir de geçici tablespace tanımlamak istersek;
CREATE USER kaya IDENTIFIED BY qwedcv89
DEFAULT TABLESPACE xyz
TEMPORARY TABLESPACE abc;
ifadesini kullanabiliriz. Bu durumda “kaya” kullanıcısının çalıştırdığı büyük veri üzerinde işlem
yapıp geçici alanlar kullanan sorgular, geçici tablespace olarak abc tablespace’ini kullanacaktır.
Oracle Veritabanı
Profil tanımlamak için de şu şekilde bir ifade kullanabilirsiniz:
CREATE USER kaya IDENTIFIED BY qwedcv89
DEFAULT TABLESPACE xyz
TEMPORARY TABLESPACE abc
PROFILE prf1;
External Authentication
External authentication Microsoft SQL Server’daki Windows authentication’a çok benzerdir. Kullanıcılar yine veri tabanında tutulur; ancak kimlik denetlemesini işletim sistemi yapar. Microsoft
SQL Server’daki Windows authentication’dan en önemli farkı sadece Microsoft Windows’la değil
diğer işletim sistemleri ile de entegre çalışabilmesidir. Bu tip kullanıcılar OPS$ kullanıcıları olarka
da adlandırılırlar. External authentication mekanizmasıyla bir kullanıcı tanımlamak için;
CREATE USER ops$kaya IDENTIFIED EXTERNALLY;
ifadesini kullanabiliriz. Bu durumda işletim sistemi üzerinde kullancı adı “kaya” olan kullanıcı,
Oracle sistemine, ilgili işletim sistemi üzerinden onaylanarak girecektir. Bu işlem Linux ve UNIX
türevleri için oldukça kolaydır; ancak Windows üzerinde bir miktar karmaşıktır. Linux ve UNIX
türevlerinde /etc/passwd içinde kullanıcının tanımlanmış olması yeterlidir. Windows üzerindeki bir
kullanıcıyı Oracle’da tanımlamak için yapmamız gerekenler şu şekildedir:
1� Windows işletim sistemi üzerinde kullanıcıyı tanımlayın.
2. Tanımladığınız kullanıcıyı Windows üzerinde ora_dba grubuna ekleyin.
3� Start > Programs > Oracle - OraDb10g_home1 > Configuration and Migration Tools > Administration Assistant for Windows üzerinden OS Database Administrators ve OS Database
Operators gruplarına ekleyin.
4. SPFILE dosyasında OS_AUTHENT_PREFIX=OPS$ şeklinde tanımlana yapın.
5. CREATE USER OPS$kullanici IDENTIFIED EXTERNALLY; ifadesini SQL Plus üzerinde
çalıştırın.
Global Authentication
Oracle üzerinde Microsoft SQL Server’dan farklı olarak bulunan bir authentication mekanizmasıdır. Authentication işlemi, gelişmiş güvenlik opsiyonu ile sağlanan bir servis aracılığıyla sağlanır
ve password authentication’daki şifrelerin tutulması söz konusu değildir. Burada kullanılan mekanizmalara örnek olarak biyometrik yöntemler, Kerberos ve X.509 sertifikaları sayılabilir. Diğer
mekanizmalara göre oldukça detaylı bir yöntemdir.
181
11
Oracle
Üzerinde
Programlama
11 Oracle Üzerinde
Programlama
• PL/SQL Nedir?
• SQL Plus
• TOAD
• PL/SQL ile Programlama
• PL/SQL’de Kontrol Yapıları
• PL/SQL’de Alfanümerik Tipler
• PL/SQL’de Mantıksal Tipler
• PL/SQL’de Tarih ve Zaman Tipleri
• Referans Tipleri
• LOB (Large Object) Tipleri
Oracle Üzerinde Programlama
PL/SQL Nedir?
PL/SQL’i (Procedural Language Extensions to the Structured Query Language) Microsoft SQL
Server’daki T-SQL’in (Transact SQL) Oracle sistemindeki karşılığı olarak düşünebilirsiniz. T-SQL
gibi PL/SQL de standart SQL dilinin, günün gereksinimleri bağlamında yetersiz kalması çerçevesinde ortaya çıkmıştır. PL/SQL ile stored procedure, trigger gibi veri tabanı nesneleri oluşturabilirsiniz. PL/SQL ifadeleri Oracle veri tabanı üzerinde çalışır.
PL/SQL dil olarak ilk bakışta bir miktar yabancı gelebilir; ancak yeterli veri tabanı bilginiz varsa
alışmanız çok zor olmayacaktır. Her dilde olduğu gibi bol bol pratik, PL/SQL’deki yetkinliklerinizi
çabuk geliştirmeniz açısından çok faydalı olacaktır. T-SQL’den tanıdığınız standart SQL dilinin
kapsadığı bütün ifadeleri burada da kullanabileceksiniz. Bildiğiniz 4 temel SQL ifadesi olan SELECT, INSERT, UPDATE, DELETE ifadelerini aynen kullanabilirsiniz.
PL/SQL ifadelerini yazmak için kullanabileceğiniz temel ortam, Oracle yüklemesiyle birlikte gelen
SQL Plus’tır. SQL Plus’ı Microsoft SQL Server 2000 ve öncesindeki Query Analyzer, Microsoft
SQL Server 2005’te SQL Server Management Studio’daki Query Window’a karşılık gelen bir araç
olarak düşünebilirsiniz; ancak her ikisine göre de daha ilkel bulabilirsiniz.
SQL Plus
SQL Plus’ı Start > Programs > Oracle – OraDb10g_home1 > Application Development > SQL
Plus yoluyla çalıştırabilirsiniz. Çalıştırdığınızda karşınıza Şekil – 1’deki ekran görüntüsü gelecektir.
Şekil 1: SQL Plus Açılış Ekranı.
Programı ilk açtığınızda Log On ekranı karşınıza gelecektir. Bu ekranda User Name bölümüne
tanımladığınız kullanıcılardan birini girmeniz gerekir. Veri tabanı oluştururken tanımlanan 4 kullanıcımız vardı, bunlardan SYSTEM kullanıcısını burada kullanabiliriz. Host String bölümüne de
veri tabanımızın adını yazmalıyız. Host String’te kullanabileceğimiz veri tabanlarını tnsnames.ora
dosyasından da bulabiliriz. Bunun için Windows Search ile tnsnames.ora dosyasını aratabilirsiniz. Başarılı bir şekilde login olduğunuzda karşınıza Şekil 2’deki gibi bir ekran gelecektir.
186
Bölüm 11
Şekil 2: SQL Plus Açılış Ekranı – 2.
Önce SQL Plus üzerinden veri tabanımızda basit bir tablo oluşturalım. Bunun için standart
SQL’den bildiğimiz CREATE TABLE ifadesini kullanacağız. Bu tablonun oluşturulmasını Şekil
3’de görebilirsiniz.
Şekil 3: Tablo oluşturmak.
Bu tabloyu oluşturduktan sonra tabloya veri girişi için;
INSERT INTO Urun ( UrunId, UrunAdi) VALUES ( 1, ‘Çikolata’);
yazalım. İfadelerin sonunda noktalı virgül “;” koymayı unutmayın. Microsoft SQL Server’da yazdığımız ifadelere göre ifadelerin sonunda “;” bulunması gerekir. Ayrıca bu ifadeyi ya da ifade
bloğunu çalıştırmak için Enter’a basmanız yeterlidir.
Benzer şekilde bir sorgu yapmak için de SQL Plus’ta
SELECT * FROM Urun;
yazarak Urun tablosunun içindeki verileri inceleyebiliriz. Yazdığımız bu ifadeleri SQL Plus ekranında Şekil 4’te görebilirsiniz.
Oracle Üzerinde Programlama ve PL/SQL
Şekil 4: SQL Plus’ta SQL İfadeleri.
TOAD
SQL Plus’a daha iyi bir alternatif olarak TOAD’u kullanabilirsiniz. http://www.toadsoft.com/lic_agree.html adresinden TOAD’un Oracle için ücretsiz (freeware) versiyonunu indirebilirsiniz.
TOAD Oracle, Microsoft SQL Server, IBM DB2 ve mySQL gibi veri tabanları için kullanılabilen
bir araçtır. TOAD’u Microsoft SQL Server 2005 Management Studio gibi düşünebilirsiniz. Hem
yönetim hem de programlama arayüzlerini birlikte sunar.
Şekil 5: TOAD Login Ekranı.
Şekil 5’teki TOAD’un login ekranını Microsoft SQL Server Login ekranına benzer olarak düşünebilirsiniz. Bağlanacağınız veri tabanını, hangi kullanıcı ile hangi rolle ve hangi sunucuya bağlanacağınızı belirterek TOAD’un ana ekranına geçebilirsiniz. Dikkat edeceğiniz gibi Windows Authentication şeklinde bir seçenek bulunmaz. Oracle’da Windows Authentication şeklinde bir seçenek
bulunmaz; ancak external authentication ile Windows kullanıcıları ile Oracle sistemine login olabilirsiniz. Bu opsiyonu kurmak Microsoft SQL Server kadar kolay ve düz değildir. Bu sebeple
Oracle’ın kendi kullanıcı (schema) sistemini kullanarak devam edeceğiz. TOAD login ekranında
bilgileri doğru olarak girip Connect butonuna tıkladığımızda ana ekrana geçebiliriz.
187
188
Bölüm 11
Şekil 6: TOAD ana ekranı.
TOAD ana ekranında Şekil 6’dan gördüğünüz gibi pek çok işi yapabilirsiniz. Buraya standart SQL
ve PL/SQL sorgularınızı yazarak çalıştırabilirsiniz. Sorgu yazarken, eğer sorguda nesne kullanıyorsak dikkat etmemiz gereken nokta nesne adından önce schema adını yazmamız gerekliliğidir. Schema’ları Microsoft SQL Server 2005’teki schema’lara denk olarak düşünebiliriz. SYSTEM
kullanıcısını da Microsoft SQL Server 2005’deki dbo’ya karşılık gibi görebiliriz. Aslında birebir bu
şekilde denkleştirmeler söz konusu olmasa da bu benzetmeleri bir kolaylık olarak görebilirsiniz.
Şekil 7: TOAD’da sorgu.
Oracle Üzerinde Programlama ve PL/SQL
TOAD’da sorgu yazmayı Şekil 7’de görebilirsiniz. SQL ifadelerinin sonunda “;” kullanmanız ya
da kullanmamanız sorgu sonucunu değiştirmez. Sorguda daha önce oluşturduğumuz Urun tablosunu SYSTEM.Urun olarak kullandığımıza dikkat edin. Bu şekilde yazmazsanız hata alırsınız.
Sorguyu çalıştırmak için klavyeden F5 tuşunu kullanabilirsiniz. Bununla birlikte TOAD üzerindeki
toolbar’dan da sorguları çalıştırabilirsiniz. Sorgu çalıştırabileceğiniz butonları Şekil 8’den görebilirsiniz.
Şekil 8: TOAD sorgu çalıştırma butonları.
PL/SQL ile Programlama
PL/SQL ile programlamaya basit bir örnek ile başlayalım. T-SQL’dekine göre muhtemelen en çok
zorlayacak durum PL/SQL içinde kullanılabilecek fonksiyonların çokluğu olacaktır. PL/SQL’de
büyük ya da küçük harf kullanarak kod yazabilirsiniz.
Uygulama 1: PL/SQL ile İlk Örnek Uygulama
1DECLARE
2 UrunSayisi INTEGER;
3
BEGIN
4
SELECT
5
COUNT(*) INTO UrunSayisi
6
FROM Urun;
7
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi: ‘ || UrunSayisi);
8
END;
Uygulama 1’deki kod oldukça basit bir uygulamadır; ancak PL/SQL konusunda oldukça önemli
bilgiler verir. Bu örnekte 1 ve 2 numaralı satırlar tanımlama (declaration) bloğudur. Altındaki kod
bloğunda kullanılacak değişkenler, parametreler gibi yapılar burada tanımlanır. Örneğimizde 2
numaralı satırda INTEGER tipinde, UrunSayisi adında bir değişken tanımlanmıştır. 3 numaralı
satırda çalıştırma bloğunun (execution block) başladığını gösteren BEGIN ifadesi bulunuyor. Örnekteki 8 numaralı satırda bulunan END ifadesine kadar tüm ifadeler çalıştırma bloğunun içindedir. 4, 5 ve 6 numaralı satırlarda Urun tablosu içindeki satır sayısını UrunSayisi değişkeninin içine
atan basit bir sorguyu görebilirsiniz. 5 numaralı satırdaki INTO ifadesini T-SQL’de kullandığımız
değişkene değer atamadaki “=” gibi düşünebilirsiniz. 7 numaralı satırda ise T-SQL’deki print
ifadesine benzer bir iş yapan DBMS_OUTPUT.PUT_LINE fonksiyonu bulunuyor. DBMS_OUTPUT.
PUT_LINE DBMS Output tamponuna yazma işlemi yapar. Bu fonksiyonun içinde kullandığımız
|| işaretini T-SQL’de alfanümerik ifadeleri birleştirmek için kullandığımız + işaretinin yerine kullanıyoruz. T-SQL’de print ifadesinde bu şekilde bir çıktı almak için ise tanımladığımız int değişkeni öncelikle alfanümerik bir tipe çevirmemiz gerekir, çünkü print 2 ifadeyi otomatik olarak
alfanümeriğe dönüştürmez. Buradan da anlayacağımız gibi DBMS_OUTPUT.PUT_LINE fonksiyonu otomatik çevirme (implicit conversion) yapmaktadır. Burada T-SQL’de kullandığımız SELECT
@UrunSayisi gibi bir ifade ile değişkenin taşıdığı değeri yazdıramayız. 8 numaralı satırda da
çalışma bloğu sona ermektedir. Bu örneğin T-SQL’deki benzer karşılığını Uygulama 1.1’de inceleyebilirsiniz.
189
190
Bölüm 11
Uygulama 1.1: Uygulama – 1’deki PL/SQL Kodunun T-SQL’deki Eşleniği
1DECLARE @UrunSayisi int
2SELECT
3
@UrunSayisi = COUNT(*)
4
FROM Urun
5PRINT ‘Urun Sayisi: ’ + CONVERT( varchar, @UrunSayisi)
Uygulama 1’deki örneği TOAD’da çalıştırdığınızda herhangi bir çıktı göremezsiniz. Çünkü DBMS_
OUTPUT.PUT_LINE fonksiyonu bir çalışma ekranında bir sonuç üretmez bir tampona yazar.
TOAD ile bu tampon bölgeyi görüntüleyebiliriz. Bunun için örnek uygulamayı çalıştırmadan önce
View menüsünden DBMS Output seçeneğini seçin. Karşınıza boş bir ekran gelecektir. Standart
Windows uygulamalarında olduğu gibi, daha önceden kod yazdığınız pencereye dönmek için CtrlTab kullanabilirsiniz ya da TOAD’un Window menüsünden diğer pencereye geçiş yapabilirsiniz.
Şekil 9: Uygulama 1’in çalışmasında sorgu ekranı.
Şekil 9’da görebileceğiniz gibi burada satır sayısı ile ilgili herhangi bir sonuç göremiyoruz, sadece
PL/SQL procedure successfully completed ifadesini görebilirsiniz.
Şekil 10: TOAD DBMS Output penceresi.
Oracle Üzerinde Programlama ve PL/SQL
Şekil 10’da TOAD DBMS Output penceresini görebilirsiniz. Burada DBMS_OUTPUT.PUT_LINE
ifadesinin sonucu olan Urun Sayisi: 2 string’i yazılmıştır.
PL/SQL’de Kontrol Yapıları
PL/SQL’de T-SQL’deki gibi IF-THEN-ELSE kontrol yapısı bulunur. Bununla birlikte T-SQL’de
bulunmayan CASE yapısı da mevcuttur. CASE yapısı C#’taki ve Java’daki switch yapısı şeklinde
çalışır.
IF-THEN-ELSE
Uygulama 2: PL/SQL ile IF-THEN-ELSE
1DECLARE
2 UrunSayisi INTEGER;
3
BEGIN
4
SELECT
5
COUNT(*) INTO UrunSayisi
6
FROM Urun;
7
IF UrunSayisi <= 2
8
THEN
9
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’
|| ‘den az ya da 2’);
10
ELSE
11
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
‘’’’ || ‘den fazla...’);
12
13
END;
END IF;
Uygulama 2’deki kodun 7, 8, 9, 10, 11 ve 12 numaralı satırlarda IF-THEN-ELSE yapısını görebilirsiniz. PL/SQL’deki IF-THEN-ELSE yapısı T-SQL’deki IF-ELSE bloğu ile aynı şekilde çalışır.
Uygulama 2.1’de Uygulama 1’deki PL/SQL kodunun T-SQL eşleniğini inceleyebilirsiniz.
Uygulama 2.1: Uygulama 1’deki Kodun T-SQL Eşleniği
1DECLARE @UrunSayisi int
2SELECT
3
@UrunSayisi = COUNT(*)
4
FROM Urun
5IF @UrunSayisi <= 2
6
PRINT ‘Urun sayisi 2’ + char(39) + ‘den az ya da 2’
7ELSE
8
PRINT ‘Urun sayisi 2’ + char(39) + ‘den fazla...’
IF-THEN-ELSIF-ELSE
IF yapısının en detaylı şekli ELSIF ile kullanılan şeklidir. ELSIF (ELSE IF’in kısaltması) yapısı
T-SQL’deki ELSE IF ile aynı şekilde çalışır. ELSIF, üstündeki IF ya da ELSIF bloğundan false
ile çıkıldığında çalışır ve tanımladığı koşul true sonuç veriyorsa bloğu çalıştırır; aksi takdirde kendinden sonra gelen bloğa geçer.
191
192
Bölüm 11
Uygulama 3: PL/SQL ile ELSIF
1DECLARE
2 UrunSayisi INTEGER;
3
BEGIN
4
SELECT
5
COUNT(*) INTO UrunSayisi
6
FROM Urun;
7
IF UrunSayisi < 2
8
THEN
9
|| ‘den az...’);
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’
10
ELSIF UrunSayisi > 2
11
THEN
12
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
‘’’’ || ‘den fazla...’);
13
ELSE
14
15
END IF;
16
END;
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
Uygulama 3’de 7 numaralı satırda eğer UrunSayisi 2’den küçük değilse 10 numaralı satırdaki
ELSIF çalışır. Eğer UrunSayisi 2’den büyükse 12 numaralı satır çalışır. Eğer UrunSayisi
2’den de büyük değilse 2’ye eşit demektir. Bu durumda da 13 numaralı satırdan dolayı 14 numaralı satır çalışır.
Eğer IF yapısı içerisinde bir blok oluşturumak istersek bunun için T-SQL’de olduğu gibi BEGINEND blok yapılandırıcıları ile bloğu tanımlamalıyız.
Uygulama 3.1: PL/SQL ile ELSIF
1DECLARE
2 UrunSayisi INTEGER;
3 BEGIN
4 SELECT
5 COUNT(*) INTO UrunSayisi
6 FROM Urun;
7 IF UrunSayisi < 2
8 THEN
9 DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’ || ‘den az...’);
10 ELSIF UrunSayisi > 2
11 THEN
12 BEGIN
13 DBMS_OUTPUT.PUT_LINE(‘ELSIF blogu...’);
14 DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’ || ‘den
fazla...’);
15 END;
16 ELSE
Oracle Üzerinde Programlama ve PL/SQL
17 DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
18 END IF;
19 END;
Uygulama 3.1’de 10 numaralı satırdan başlayan ELSIF bloğu 15 numaralı satıra kadar devam eder. Eğer UrunSayisi 2’den büyükse ELSIF içinde tanımlanan her 2 DBMS_OUTPUT.
PUT_LINE ifadesi de çalışacaktır. Her ne kadar yazdığımız BEGIN-END blok yapılandırıcılarını
kullanmak zorunda olmasak da kodun okunurluğunu artırmak açısından blok yapılandırıcılarını
kullanmak faydalıdır.
İç İçe IF Yapıları
PL/SQL’de iç içe IF yapıları da kullanılabilir. Çalışma şekli C#, Java ya da T-SQL’den farklı değildir.
Uygulama 4: PL/SQL ile İç İçe IF Yapısı
1DECLARE
2 UrunSayisi INTEGER;
3
UrunSayisiB INTEGER;
4
BEGIN
5
SELECT
6
COUNT(*) INTO UrunSayisi
7
FROM Urun;
8
SELECT
9
COUNT(*) INTO UrunSayisiB
10
FROM Urun
11
WHERE UrunAdi LIKE ‘B%’;
12
IF UrunSayisi < 2
13
THEN
14
‘’’’ || ‘den az...’);
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
15
IF UrunSayisiB = 1
16
THEN
17
DBMS_OUTPUT.PUT_LINE(‘B ile
baslayan urun sayisi: ’ || UrunSayisiB);
18
END IF;
19
ELSIF UrunSayisi > 2
20
THEN
21
BEGIN
22
DBMS_OUTPUT.PUT_LINE(‘ELSIF blogu...’);
23
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
‘’’’ || ‘den fazla...’);
24
END;
25
ELSE
26
27
END IF;
28
END;
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
193
194
Bölüm 11
Uygulama 4’te 8 ile 11 numaralı satırlardaki SELECT ifadesinde UrunSayisiB değişkenine B
harfiyle başlayan ürünlerin sayısı atanacaktır. Eğer UrunSayisi 2’den küçükse 15 numaralı
satırdaki iç IF yapısı da çalışacaktır. Eğer UrunSayisiB 1’e eşitse de 17 numaralı satır çalışacaktır.
IF Yapısı ile İlgili Dikkat Edilmesi Gereken Noktalar
1� Her IF için mutlaka bir END IF bulunmalıdır.
2. Her END IF kendinden önceki ilk IF ifadesine aittir.
3� END IF birleşik yazılmaz.
4. END IF’in sonunda mutlaka “;” bulunmalıdır.
5. ELSIF yazarken ELSE’in son “E” harfi yoktur.
CASE
CASE yapısı C# ve Java’daki switch yapısı gibi çalışır. IF-THEN-ELSIF-ELSE yapısını daha
kolay ve okunaklı hale getirir. PL/SQL’deki CASE yapısını T-SQL’de SELECT ifadesinin içinde
kullanılan CASE ifadesiyle karıştırmamak gerekir. T-SQL’deki CASE yapısı result set’in içindeki
tüm kayıtlar için tek tek çalışırken PL/SQL’de kayıtlar bazında çalışmaz. Kod yazımı olarak her
ikisi de birbirine çok benzerdir.
Uygulama 5: PL/SQL’de CASE Örneği 1
1DECLARE
2 UrunSayisi INTEGER;
3
BEGIN
4
SELECT
5
COUNT(*) INTO UrunSayisi
6
FROM Urun;
7
CASE UrunSayisi
8
WHEN 2 THEN
9
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
10
WHEN 3 THEN
11
12
ELSE
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
13
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 3‘ ||
‘’’’ || ‘ten fazla...’);
14
15
END;
END CASE;
Uygulama 4’te 7 – 14 numaralı satırlar CASE bloğunu oluşturur. 7 numaralı satırdaki CASE UrunSayisi ifadesi UrunSayisi değişkeninin karşılaştırmada kullanılacağını gösterir. 8 numaralı
satır eğer UrunSayisi değişkeninin 2’ye eşitliğini kontrol eder. Eğer 2’ye eşitse 9 numaralı satıra geçer, eşit değilse 10 numaralı satır ve UrunSayisi değişkeninin 3’e eşit olup olmadığı kontrol eder. 3’e eşit olması halinde 11 numaralı satır çalışr; aksi takdirde 12 numaralı satırdaki ELSE
ifadesine gelir. PL/SQL’de CASE yapısında ELSE ifadesi C# ve Java’daki switch ifadesindeki
default gibi çalışır. Eğer ELSE’ten önce gelen WHEN ifadelerinin hiçbirinde true oluşmazsa ELSE
bloğu çalışır. WHEN bloklarının sonunda C# ve Java’daki break ifadesinin yerine kullanılması
gereken herhangi bir ifade yoktur.
Uygulama 5’teki yapıyı IF-ELSIF-ELSE ile kurmak daha doğru olacaktır. Uygulama 3’deki gibi
bir IF yapısını CASE ile yazmak istersek PL/SQL bu konuda bize esneklik sağlamaktadır.
Oracle Üzerinde Programlama ve PL/SQL
Uygulama 6: PL/SQL’de CASE Örneği 2
1DECLARE
2 UrunSayisi INTEGER;
3
BEGIN
4
SELECT
5
COUNT(*) INTO UrunSayisi
6
FROM Urun;
7
CASE TRUE
8
WHEN UrunSayisi < 2 THEN
9
|| ‘den az...’);
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’
10
WHEN UrunSayisi > 2 THEN
11
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
‘’’’ || ‘den fazla...’);
12
ELSE
13
14
END CASE;
15
END;
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
Uygulama 6’da 7 numaralı satır her durumda çalışacaktır. 8 numaralı satırda UrunSayisi değişkeninin değerinin 2’den küçük olup olmadığı kontrol edilir. Eğer 2’den küçükse 9 numaralı satır
çalışır; aksi takdirde 10 numaralı satırda UrunSayisi değişkeninin değerinin 2’den büyük olup
olmadığı kontrol edilir. Eğer 2’den büyükse 11 numaralı satır çalışır; aksi takdirde 12 numaralı
satırdaki ELSE ifadesi çalışır. Bu noktadan sonraki çalışma Uygulama 5’teki ELSE bloğu ile aynı
şekildedir.
Uygulama 6’daki örneğe benzer olarak CASE ifadesinini farklı bir kullanımı daha vardır. CASE’in
bu kullanımı esnekliği daha da artırır ve özellikle karmaşık mantıksal işlemler için idealdir.
Uygulama 7: PL/SQL’de CASE Örneği 3
1DECLARE
2 UrunSayisi INTEGER;
3 UrunSayisiB INTEGER;
4 BEGIN
5 SELECT
6 COUNT(*) INTO UrunSayisi
7 FROM Urun;
8 SELECT
9 COUNT(*) INTO UrunSayisi
10 FROM Urun
11 WHERE UrunAdi LIKE ‘B%’;
12 CASE
13 WHEN UrunSayisi < 2 AND UrunSayisiB = 1 THEN
14 DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ || ‘’’’ || ‘den az...’);
15 WHEN UrunSayisi > 2 AND UrunSayisiB < 1 THEN
195
196
Bölüm 11
16
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘ ||
‘’’’ || ‘den fazla...’);
17
ELSE
18
19
END CASE;
20
END;
DBMS_OUTPUT.PUT_LINE(‘Urun Sayisi 2‘);
Uygulama 7’de 12 numaralı satırdaki CASE ifadesi ne olursa olsun çalışacaktır ve CASE ile 1’den
fazla sayıda değişken kontrol edilebilecektir.
Şu ana kadar yaptığımız örnekleri TOAD yerine SQL Plus ile yapmak istediğinizde yazarken dikkat etmeniz gereken birkaç nokta vardır. DBMS_OUTPUT.PUT_LINE fonksiyonunun çalışması için
SET SERVEROUTPUT ON ifadesini bir kere çalıştırmalısınız. Bu ifadeyi Microsoft SQL Server’daki
direktiflere benzetebilirsiniz. SET SERVEROUTPUT ON ifadesi TOAD’daki View menüsündeki
DBMS Output öğesinin açılması işlevini görür. SET SERVEROUTPUT ON ifadesini çalıştırdıktan
sonra PL/SQL bloğunu yazabiliriz. Bloğun sonunda “/” işaretini kullandığımızda yazdığımız blok
çalışacaktır. Şekil 11’de SQL Plus ile PL/SQL bloklarının nasıl çalıştırıldığına yönelik ekran çıktısını görebilirsiniz.
Şekil 11: SQL Plus ile PL/SQL bloklarının çalıştırılması.
PL/SQL’de Değişkenler
PL/SQL’de veri tipleri 4 ana gruba ayrılır. Bu gruplar:
1� Basit (skaler) Tipler: T-SQL’deki basit tiplere ya da Java ve C#’taki değer tipli değişkenlere
benzetilebilir. Herhangi bir anda doğrudan tek değer taşırlar, bellekte doğrudan tutulurlar.
2. Bütünleşik (kompozit) Tipler: Dizi gibi kendi içinde tek tek işlenebilecek, T-SQL’de eksikliğini hissettiğimiz tiplerdir. Java ve C#’taki dizilere benzetebiliriz; ancak Java ve C#’ta dizilerin
referans tipli olduğunu unutmamak gerekir.
3� Referans Tipleri: Bir işaretçi (pointer) aracılığıyla taşıdığı değerlere erişilebilen tiplerdir. TSQL’de doğrudan karşılığı yoktur. Java ve C#’taki referans tipli değişkenlerle benzer mantıkta
çalışırlar.
4. LOB (Large Object) Tipleri: Şekil, metin gibi büyük verileri tutmak için geliştirilmiş tiplerdir. TSQL’deki text, image gibi düşünülebilir. Özünde referans tipli yapılara çok benzerdirler; çünkü
taşıdıkları değer resmin ya da metnin başlangıcını gösteren bir işaretçidir.
Oracle Üzerinde Programlama ve PL/SQL
PL/SQL’de bir değişkeni tanımlarken önce değişkenin adını sonra da tipini yazarız.
DECLARE <değişken adı> <tip adı>;
Herhangi bir değişkene değer ataması yaparken “:=” işaretini kullanırız.
<değişken adı> := <değer>
BASİT TİPLER
BÜTÜNLEŞİK TİPLER
REFERANS TİPLERİ
LOB TİPLERİ
BINARY_DOUBLE
RECORD
REF CURSOR
BFILE
BINARY_FLOAT
TABLE
REF object_type
BLOB
BINARY_INTEGER
VARRAY
DEC
DECIMAL
DOUBLE PRECISION
FLOAT
INT
INTEGER
NATURAL
NATURALN
NUMBER
NUMERIC
PLS_INTEGER
POSITIVE
POSITIVEN
REAL
SIGNTYPE
SMALLINT
CHAR
CAHARACTER
LONG
LONG RAW
NCHAR
NVARCHAR2
RAW
ROWID
STRING
UROWID
VARCHAR
VARCHAR2
BOOLEAN
DATE
TIMESTAMP
CLOB
NCLOB
197
198
Bölüm 11
PL/SQL’de Sayısal Tipler
Sayısal tipler adlarından anlaşılabileceği gibi matematiksel işlemlerde kullanılabilecek tiplerdir.
Tam sayıları, reel ve ondalıklı sayıları tutabileceğiniz pek çok tip PL/SQL’de mevcuttur.
BINARY_INTEGER
32 bitlik (4 byte) işaretli (signed), tam sayısal tiptir. -231 ile 231 – 1 aralığında değerleri tutar. PLS_
INTEGER tipine benzer bir tiptir. NUMBER tipine göre işlem performanı avantajı vardır ve NUMBER
tipine göre daha az yer kaplar.
NATURAL, NATURALN, POSITIVE, POSITIVEN, SIGNTYPE tipleri BINARY_INTEGER tipinin alt
tipleridir.
NATURAL ve POSITIVE tipleri sadece pozitif sayıları taşırlar. Dolayısıyla işaretsiz tiplerdir diyebiliriz. NATURAL tipinin POSITIVE tipinden tek farkı 0 (sıfır) değerini de alabilmesidir. NATURALN
ve POSITIVEN tiplerinin NATURAL ve POSITIVE tiplerinden tek farkı null değer taşıyamamalarıdır. NATURAL, POSITIVE, NATURALN ve POSITIVEN tiplerinin taşıyabileceği en büyük değer
231 – 1’dir. SIGNTYPE ise sadece -1, 0 ve 1 değerlerini taşıyabilir.
Örnek 1: BINARY_INTEGER Tanımlama
1DECLARE
2 bix BINARY_INTEGER;
3
nx NATURAL;
4
nnx NATURALN;
5
px POSITIVE;
6
pnx POSITIVEN;
7
stx SIGNTYPE;
8BEGIN
9
bix := -55;
10
nx := null;
11
nnx := 0;
12
px := 7;
13
pnx := 88;
14
stx = -1;
15
END;
BINARY_FLOAT ve BINARY_DOUBLE
Java ve C#’taki IEEE 754 standardındaki ondalıklı tiplerdir. BINARY_FLOAT bir değer sonuna
eklenen ‘f’ harfiyle (1.004f), BINARY_DOUBLE bir değer sonuna eklenen ‘d’ harfiyle (3,05478d)
ayrıştırılır.
Örnek 2: BINARY_FLOAT ve BINARY_DOUBLE Tanımlama
1DECLARE
2 bfx BINARY_FLOAT;
3
bdx BINARY_DOUBLE;
4BEGIN
5
bfx := 10.054f;
6
bdx := 10.054d;
7
IF bfx = bdx
Oracle Üzerinde Programlama ve PL/SQL
8
THEN
9
DBMS_OUTPUT.PUT_LINE(‘Esit’);
10
ELSE
11
12
END IF;
13
END;
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
Örnek 2’deki 7 numaralı satırdaki kontrolden FALSE sonucu çıkacaktır. Bu sebeple akış 8 numaralı satırdan değil 10 numaralı satırdan devam edecektir ve DBMS Output penceresine “Esit
degil” yazacaktır.
NUMBER
PL/SQL’deki en genel sayısal tiptir. Hem tam sayıları hem de ondalıklı sayıları tutabilir. Değer
aralığı 1E-130 ile 10E125’tir. NUMBER tipinde bir değişkeni sadece NUMBER olarak tanımlayabileceğimiz gibi hassasiyet (precission) ve ölçek (scale) değerleriyle birlikte de tanımlayabiliriz.
Hassasiyet sayının toplam hane (dijit) sayısıdır, ölçek ise noktadan sonraki hane sayısıdır. Dolayısıyla hassasiyet için yazdığımız değer mutlaka ölçek için yazdığımız değerden büyük olmak
zorundadır. NUMBER tipinde bir değişkeni sadece hassasiyet değeri ile de tanımlayabiliriz. Bunun
anlamı ölçek değerinin yani ondalık hane sayısının 0 (sıfır) olmasıdır. En fazla 38 hanelik hassasiyet değeri ile tanımlanabilirken ölçek değeri -84 ile 127 arasında değişir. Ölçek değerinin negatif
olması tam sayının yuvarlanması anlamına gelir. Örneğin ölçek değeri -2 olan bir NUMBER değişkene 257 değeri 200 olarak atanacaktır.
DEC, DECIMAL, DOUBLE PRECISION, FLOAT, INTEGER, INT, NUMERIC, REAL ve SMALLINT
tipleri NUMBER tipinin alt tipleridir.
DEC, DECIMAL ve NUMERIC tipleri NUMBER gibi tanımlanırken alabileceği en büyük ölçek değeri
38’dir.
DOUBLE PRECISION ve FLOAT tiplerinde ondalıklı kısım 126 bitte tutulur, bu da yaklaşık 38
ondalıklı haneye karşılık gelir.
REAL tipinde ondalıklı kısım 63 bit’te tutulur, bu da yaklaşık 18 ondalıklı haneye karşılık gelir.
INTEGER, INT ve SMALLINT tiplerinde de en fazla hassasiyet seviyesi 38’dir. T-SQL’deki tam
sayısal tipler gibi düşünmek doğru değildir; çünkü PL/SQL’deki bu tiplerde ondalıklı kısım tanımlanabilir.
Örnek 3: NUMBER Tanımlama
1DECLARE
2 nx1 NUMBER;
3
nx2 NUMBER(3);
4
nx3 NUMBER(3,2);
5
nx4 NUMBER(3,-1);
6
ix1 INTEGER;
7
ix2 INTEGER(3,1);
8
dpx DOUBLE PRECISION;
9
fx FLOAT;
10
BEGIN
11
nx1 := 10;
12
nx2 := 267;
199
200
Bölüm 11
13
nx3 := 1.25;
14
nx4 := 254;
15
ix1 := 8;
16
ix2 := 4.7;
17
dpx := 16.874;
18
fx := 6.8;
19
DBMS_OUTPUT.PUT_LINE(‘nx4 : ’ || nx4);
20
IF fx = dpx
21
THEN
22
23
ELSE
24
25
END IF;
26
IF nx4 = 250
27
THEN
28
29
ELSE
30
31
END IF;
32
END;
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
DBMS_OUTPUT.PUT_LINE(‘nx4 = 250’);
DBMS_OUTPUT.PUT_LINE(‘nx4 <> 250’);
Örnek 3’deki kodun DBMS çıktısı;
nx4 : 250
Esit
nx4 = 250
şeklinde olacaktır. Bu örnekte nx4 değişkeninin tanımında ölçeğin -1 olmasından dolayı 254 değeri 250’ye dönüştürülecektir. Eğer ölçek -2 olsaydı 200’e dönüştürülecekti. 20 numaralı satırdaki
FLOAT tipinde bir değişkenle DOUBLE PRECISION tipinde bir değişkenin karşılaştırılmasında da
bu tipler arasında bir önceki örnekte kullandığımız BINARY_FLOAT ve BINARY_DOUBLE tiplerinden farklı olarak eşitlik olduğunu görebilirsiniz.
PLS_INTEGER
PLS_INTEGER tipinde de BINARY_INTEGER tipindeki gibi -231 ile 231 – 1 arasındaki tam sayılar
tutulabilir. PLS_INTEGER tipi hem NUMBER tipinden hem de BINARY_INTEGER tipinden daha
hızlı çalışır. Bunun NUMBER ve BINARY_INTEGER işlemleri yazılımsal olarak yaparken PLS_INTEGER tipinin donanımsal olarak yapmasıdır.
BINARY_INTEGER tipi eski versiyonlardan bu yana gelen bir tiptir. Eğer yeni bir uygulama geliştiriyorsanız PLS_INTEGER tipini kullanmak daha iyi olacaktır.
Örnek 4: PLS_INTEGER Tanımlama
1DECLARE
2 pix PLS_INTEGER;
3
bix BINARY_INTEGER;
4BEGIN
5
pix := 25;
Oracle Üzerinde Programlama ve PL/SQL
6
bix := 25;
7
IF pix = bix
8
THEN
9
DBMS_OUTPUT.PUT_LINE(‘Esit’);
10
ELSE
11
12
END IF;
13
END;
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
Örnek 4’ü çalıştırdığınızda PLS_INTEGER tipinde taşınan bir değerle BINARY_INTEGER tipinde
taşınan bir değer eğer aynıysa eşitlik sonucunu üreteceğini görebilirsiniz.
PL/SQL’de Alfanümerik Tipler
Alfanümerik tiplerde sayısal olarak yorumlanmayacak karakterler ve string tipler tutulur.
CHAR
Belli uzunlukta alfanümerik ifadeleri tutmak için kullanılır. En fazla uzunluğu 32767 karakterdir.
Eğer bir uzunluk tanımlanmazsa tek karakter tutar. CHARACTER veri tipini CHAR veri tipiyle aynı
şekilde kullanabilirsiniz.
Örnek 5: CHAR Tanımlama
1DECLARE
2 cx1 CHAR;
3
cx2 CHAR;
4
cx3 CHAR(4);
5
cx4 CHARACTER;
6BEGIN
7
cx1 := ‘A’;
8
cx2 := ‘a’;
9
cx3 := ‘ABCD’;
10
cx4 := ‘A’;
11
IF cx1 = cx2
12
THEN
13
14
ELSE
15
16
END IF;
17
IF cx1 = cx4
18
THEN
19
20
ELSE
21
22
END IF;
23
IF cx1 = SUBSTR(cx3, 1, 1)
24
THEN
19
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
DBMS_OUTPUT.PUT_LINE(‘Esit’);
201
202
Bölüm 11
20
ELSE
21
22
END IF;
23
END;
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
Örnek 5’i çalıştırdığınızda şu şekilde bir DBMS çıktısı ile karşılaşırsınız:
Esit degil
Esit
Esit
Bu örneğin DBMS çıktısından anlaşılacağı gibi “A” harfi ve “a” harfi birbirine eşit değildir. 23
numaralı satırda kullandığımız SUBSTR() fonksiyonu, adından da anlaşılabileceği gibi alfanümerik bir yapıdan istediğimiz bir parçayı almak için kullanılır. SUBSTR fonksiyonunun kullanımı
T-SQL’deki SUBSTRING() fonksiyonu gibidir. İlk argüman parça alınacak alfanümerik değer ya
da değişkendir. İkinci argüman, bu değer ya da değişkenin kaçıncı karakterinden itibaren parça
alınacağıdır. Üçüncü argüman, ikinci argümanda belirtilen karakter dahil olmak üzere kaç tane
karakter alınacağını gösterir. Eğer üçüncü argüman girilmezse, ilk argümanda belirtilen değer ya
da değişkenin, ikinci argümanda belirtilen karakterinden sonuna kadar tüm karakterleri alınır.
LONG ve LONG RAW
LONG ve LONG RAW tipleri T-SQL’deki LONG tipinden çok farklıdır. PL/SQL’de LONG ve LONG RAW
32760 byte’a kadar alfanümerik değer tutar. Dolayısıyla VARCHAR2 tipine benzerdirler. LONG
ve LONG RAW tipleri arasında veri tabanına INSERT ve SELECT ile yapılan işlemlerde ve veri
tutma biçimlerinde farklılıkları vardır.
Örnek 6: LONG ve LONG RAW Tanımlama
1DECLARE
2 lx1 LONG;
3
lrx1 LONG RAW;
4
lx2 LONG;
5
lx3 LONG;
6
lrx2 LONG RAW;
7
lx4 LONG(3);
8
lrx3 LONG RAW(3);
9BEGIN
10
lx1 := ‘ABC’;
11
lrx1 := ‘ABC’;
12
lx3 := ‘ABC’;
13
lx4 := ‘ABC’;
14
lrx3 = ‘ABC’;
15
IF lx1 = lrx1
16
THEN
17
18
ELSE
19
20
END IF;
21
lx2 := CONCAT(lx1, lrx1);
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
Oracle Üzerinde Programlama ve PL/SQL
22
DBMS_OUTPUT.PUT_LINE(lx2);
23
lx2 := CONCAT(lx1, lx3);
24
DBMS_OUTPUT.PUT_LINE(lx2);
25
lrx2 := CONCAT(lx1, lrx1);
26
DBMS_OUTPUT.PUT_LINE(lrx2);
27
END;
Örnek 6’yı çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
Esit degil
ABC0ABC
ABCABC
0ABC0ABC
15 numaralı satırda LONG tipindeki, tuttuğu değer “ABC” olan lx1 değişkeniyle LONG RAW tipindeki, tuttuğu değer “ABC” olan lrx1 değişkeni karşılaştırıldığında FALSE sonucu oluşur ve 18
numaralı satırdaki ELSE bloğuna düşer. Dolayısıyla LONG ve LONG RAW değişkenleri doğrudan
karşılaştırmak istediğimiz sonucu üretmez. 21 numaralı satırda LONG tipindeki lx1 ile lrx1 değişkenlerini CONCAT() fonksiyonuyla birleştirip LONG tipindeki lx2 değişkenine atadık. 22 numaralı satırda lx2 değişkeninin değerinin “ABC0ABC” olduğunu gördük. 23 numaralı satırda
LONG tipindeki lx2 değişkenine LONG tipindeki lx1 ve lx3 değişkenlerinin birleştirilmesi sonucu
oluşan değeri atadık ve 24 numaralı satırda lx2 değişkenininin değerinin “ABCABC” olduğunu
gördük. Benzer şekilde 25 numaralı satırda bu sefer LONG RAW tipindeki lrx2 değişkeninin içine
LONG tipindeki lx1 ve LONG RAW tipindeki lrx1 değişkenlerinin birleştirilmesi sonucu oluşan
değeri atadık ve 26 numaralı satırda sonucun “0ABC0ABC” olduğunu gördük. Dolayısıyla LONG
tipindeki değişkenlerle LONG RAW tipindeki değişkenleri bir arada kullanırken dikkatli olmakta
fayda vardır.
Örnek 7: LONG ve LONG RAW Tiplerinin CHAR ile Karşılaştırılması
1DECLARE
2 lx1 LONG(3);
3
lrx1 LONG RAW(3);
4
cx1 CHAR(3);
5BEGIN
6
lx1 := ‘ABC’;
7
lrx1 := ‘ABC’;
8
cx1 := ‘ABC’;
9
IF lx1 = lrx1
10
THEN
11
12
ELSE
13
14
END IF;
15
IF lx1 = cx1
16
THEN
17
18
ELSE
19
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
203
204
Bölüm 11
20
END IF;
21
IF cx1 = lrx1
22
THEN
23
24
ELSE
25
26
END IF;
27
END;
DBMS_OUTPUT.PUT_LINE(‘Esit’);
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
Örnek 7’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
Esit degil
Esit
Esit degil
Bu örnekten de anlaşılabileceği gibi CHAR tipindeki verilerle LONG tipindeki veriler karşılaştırılabilirken LONG RAW tipindeki verilerin doğrudan karşılaştırılması istediğimiz sonuçları vermeyebilir.
ROWID ve UROWID
T-SQL’de olmayan tiplerdir. ROWID ve UROWID herhangi bir tablodaki kaydın yeri hakkında bilgi
tutarlar. Bu bilgi fiziksel ve mantıksal olmak üzere 2 şekildedir. Fiziksel rowid herhangi bir tabloda
satır için ayırdedici bir özelliktir. Mantıksal rowid üzerinde index olan bir tablo için ayırdedicidir.
UROWID hem fiziksel hem de mantıksal rowid tutabilir. Eğer yeni bir uygulama yazıyorsanız ve
bu tip bir veriye ihtiyacınız varsa UROWID tipini tercih etmek daha iyi olacaktır. Örneğin ROWID ve
UROWID tiplerini tüm değerleri aynı olan 2 satırdan birini silerken kullanabilirsiniz.
Örnek 8: ROWID ve UROWID Tipleri
1DECLARE
2 rx1 ROWID;
3
urx1 UROWID;
4BEGIN
6
SELECT
7
rowid
8
INTO rx1
9
FROM Urun
10
11
SELECT
12
rowid
13
INTO urx1
14
FROM Urun
15
WHERE UrunId = 2;
16
DBMS_OUTPUT.PUT_LINE(rx1);
17
DBMS_OUTPUT.PUT_LINE(urx1);
18
IF rx1 = urx1
19
THEN
20
21
ELSE
WHERE UrunId = 2;
DBMS_OUTPUT.PUT_LINE(‘Esit’);
Oracle Üzerinde Programlama ve PL/SQL
22
DBMS_OUTPUT.PUT_LINE(‘Esit degil’);
23
END IF;
24
END;
Örnek 8’i çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
AAAM2eAABAAAO5aAAD
AAAM2eAABAAAO5aAAD
Esit
Bu örnekten ROWID tipindeki rx1 ve UROWID tipindeki urx1 değerlerinin esit olduğunu görebiliriz.
Bununla birlikte DBMS çıktısındaki “AAAM2eAABAAAO5aAAD” ifadeleri sizde farklı değerlerde
olacaktır. Bu karakter dizisi bir anlam taşır. İlk 6 karakter (örneğimizde “AAAM2e”) veri tabanı
segmentini ifade eder. Bu gruba nesne numarası (object number) denir. Sonraki 3 karakter (örneğimizde “AAB”) satırın bulunduğu fiziksel dosyayı ifade eder. Bu gruba dosya numarası (file number) denir. Sonraki 6 karakter (örneğimizde “AAAO5a”) veri dosyasının içindeki bloğu ifade eder.
Aynı tablespace içinde olan fakat farklı veri dosyasında olan 2 satır aynı blok numarasına sahip
olabilir. Bu gruba blok numarası (block number) denir. Son 3 karakter de (örneğimizde “AAD”)
blok içindeki satır numarasını ifade eder. Bu gruba satır numarası (row number) denir.
Örnek 9: ROWID ve UROWID Tipleri
1DECLARE
2 rx1 ROWID;
3
rx2 ROWID;
4BEGIN
6
SELECT
7
rowid
8
INTO rx1
9
FROM Urun
10
11
SELECT
12
rowid
13
INTO rx2
14
FROM Urun
15
WHERE UrunId = 3;
16
DBMS_OUTPUT.PUT_LINE(rx1);
17
DBMS_OUTPUT.PUT_LINE(rx2);
18
END;
WHERE UrunId = 2;
Örnek 9’u çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
AAAM2eAABAAAO5aAAD
AAAM2eAABAAAO5aAAA
Bu çıktıdan Urun tablosundaki UrunId değerleri 2 ve 3 olan satırların aynı segment’te, aynı veri
dosyasında, aynı blok içindeki farklı yerlerde olduğunu görebiliriz.
VARCHAR2
Değişken uzunluklu alfanümerik verileri tutmak için kullanılır. Verinin VARCHAR2 tipinde nasıl tutulduğu veri tabanının karakter setine göre değişiklik gösterir. En fazla 32767 karakter tutulabilir.
205
206
Bölüm 11
2000 byte’tan uzun değerlerde performans düşüşü yükselir. Bu sebeple 2000 byte’tan daha uzun
verileri tutarken bu durumu dikkate almakta fayda vardır.
STRING ve VARCHAR veri tipleri VARCHAR2 veri tipinin alt tipleridir. VARCHAR ile VARCHAR2 veri
tipleri aynıdır. VARCHAR veri tipinin varlık sebebi ileri sürümlerde farklı şekilde kullanılabilecek
ayrılmış bir tip yaratmaktır. Bu sebeple VARCHAR2 veri tipini kullanmak daha iyi olacaktır.
Örnek 10: VARCHAR2 Tipi ve Diğer Alfanümerik Tiplerle Karşılaştırma
1DECLARE
2 vx1 VARCHAR2(10);
3
cx1 CHAR(10);
4
sx1 STRING(10);
5
lx1 LONG(10);
6BEGIN
7
vx1 := ‘ABC’;
8
cx1 := ‘ABC’;
9
sx1 := ‘ABC’;
10
lx1 := ‘ABC’;
11
IF vx1 != cx1
12
THEN
13
14
ELSE
15
16
END IF;
17
IF vx1 != sx1
18
THEN
19
20
ELSE
21
22
END IF;
23
IF vx1 != lx1
24
THEN
25
26
ELSE
27
28
END IF;
29
END;
DBMS_OUTPUT.PUT_LINE(‘vx1 != cx1’);
DBMS_OUTPUT.PUT_LINE(‘vx1 = cx1’);
DBMS_OUTPUT.PUT_LINE(‘vx1 != sx1’);
DBMS_OUTPUT.PUT_LINE(‘vx1 = sx1’);
DBMS_OUTPUT.PUT_LINE(‘vx1 != lx1’);
DBMS_OUTPUT.PUT_LINE(‘vx1 = lx1’);
Örnek 10’u çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
vx1 != cx1
vx1 = sx1
vx1 = lx1
Bu örnekten görebileceğimiz gibi VARCHAR2 tipiyle CHAR tipini karşılaştırmak sakıncalıdır. Her ne
kadar LONG tipiyle karşılaştırmak eşit sonucunu verse de LONG tipi ile VARCHAR2 tipinini kapasitelerinin farklı olması sebebiyle bu tip bir karşılaştırmayı tercih etmemekte fayda vardır.
Oracle Üzerinde Programlama ve PL/SQL
PL/SQL’de Mantıksal Tipler
PL/SQL’de 1 tane mantıksal tip bulunmaktadır. Bu tip BOOLEAN tipidir. Mantıksal bir tip TRUE ya
da FALSE değerlerinden birini tutar.
BOOLEAN
PL/SQL’de BOOLEAN veri tipi TRUE ya da FALSE değerlerini tutar; ancak dikkat edilmesi gereken
nokta BOOLEAN bir veri tipini DBMS_OUTPUT.PUT_LINE() fonksiyonu ile yazdıramayız.
Örnek 11: BOOLEAN Veri Tipi
1DECLARE
2 bx BOOLEAN;
3BEGIN
4
bx := TRUE;
5
IF bx = TRUE
6
THEN
7
8
ELSIF bx = FALSE
9
THEN
10
11
ELSE
12
13
END IF;
14
END;
DBMS_OUTPUT.PUT_LINE(‘bx = TRUE’);
DBMS_OUTPUT.PUT_LINE(‘bx = FALSE’);
DBMS_OUTPUT.PUT_LINE(‘bx = null’);
Örnek 10’u çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
bx = TRUE
Bu örnekte 10 numaralı satırdaki ELSE bloğunu eklemimizin sebebi eğer bx değişkeni tanımlanmazsa ya da bx değişkenine null değeri atanırsa 11 numaralı satırdaki ELSE bloğuna girilecek ve
DBMS çıktısı olarak “bx = null” yazılacaktır.
PL/SQL’de Tarih ve Zaman Tipleri
Tarih ve zaman tipleri herhangi bir tarihi ya da saati tutar. PL/SQL’de pek çok tarihsel gösterim
şekli olmasına rağmen bu tipleri temel olarak inceleyeceğiz.
DATE
DATE veri tipi Saniye detayında tarih ve zaman verisi tutar.
Örnek 12: DATE Veri Tipi
1DECLARE
2 dx DATE;
3BEGIN
4
dx := SYSDATE;
5
DBMS_OUTPUT.PUT_LINE(dx);
6END;
Örnek 12’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
02-DEC-07
207
208
Bölüm 11
SYSDATE() fonksiyonu T-SQL’deki GETDATE() fonksiyonuna karşılık gelmektedir ve sistem tarih ve zamanını getirir. Bu noktadan itibaren INTERVAL yapısına geçebiliriz.
Örnek 13: INTERVAL YEAR TO MONTH
1DECLARE
2 BaslangicTarihi DATE;
3
BitisTarihi DATE;
4
ix INTERVAL YEAR(3) TO MONTH;
5
cYilFarki CHAR(3);
6
cAyFarki CHAR(2);
7
iYilFarki INT;
8
iAyFarki INT;
7BEGIN
8
BaslangicTarihi := ’01-JAN-00’;
9
BitisTarihi := SYSDATE;
10
DBMS_OUTPUT.PUT_LINE(‘Gun Farki: ’ || TO_
CHAR(BitisTarihi - BaslangicTarihi));
11
365);
iYilFarki := FLOOR((BitisTarihi - BaslangicTarihi) /
12
cYilFarki := TO_CHAR(iYilFarki);
13
iAyFarki := FLOOR(((BitisTarihi - BaslangicTarihi)
– iYilFarki * 365) / 30);
14
cAyFarki := TO_CHAR(iAyFarki);
15
ix := CONCAT(CONCAT(TRIM(iYilFarki), ‘-‘),
TRIM(iAyFarki));
16
17
END;
DBMS_OUTPUT.PUT_LINE(ix);
Örnek 13’ü çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
Gun Farki: 2892
+007-11
Bu örnekten görebileceğimiz gibi uygulamanın çalıştığı tarih (2 Aralık 2007) ile 1 Ocak 2000 tarihi
arasında 2892 gün vardır. 2892 gün de 7 yıl 11 aya karşılık gelmektedir. Bu örnekte TO_CHAR()
fonksiyonu herhangi bir tipi CHAR tipine çeviren fonksiyondur. BOOLEAN tipini CHAR tipine çeviremez. TO_CHAR() fonksiyonunu T-SQL’deki CONVERT() fonksiyonunun özelleşmiş bir hali olarak
düşünebiliriz. FLOOR() fonksiyonu burada, ondalıklı sayının ondalıklı kısmını atarak tam sayı
kısmını almamızı sağlar. Bu örnekten de görebileceğiniz gibi INTERVAL YEAR TO MONTH tipine
CHAR tipinde YIL-AY değerini alabilmektedir.
Örnek 14: INTERVAL YEAR TO MONTH
1DECLARE
2
ix1 INTERVAL YEAR(3) TO MONTH;
3
ix2 INTERVAL YEAR(3) TO MONTH;
4
ix3 INTERVAL YEAR(3) TO MONTH;
5
ix4 INTERVAL YEAR(3) TO MONTH;
6
dx DATE;
Oracle Üzerinde Programlama ve PL/SQL
7BEGIN
8
ix1 := INTERVAL ’10-7’ YEAR TO MONTH;
9
ix2 := INTERVAL ’10’ YEAR;
10
ix3 := INTERVAL ’7’ MONTH;
11
ix4 := ix2 + ix3;
12
DBMS_OUTPUT.PUT_LINE(ix4);
13
dx := SYSDATE;
14
dx := dx + ix4;
15
DBMS_OUTPUT.PUT_LINE(dx);
12
END;
Örnek 14’ü çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
+010-07
02-JUL-18
Bu örnekten görülebileceği gibi 11 numaralı satırda 2 INTERVAL YEAR TO MONTH toplanabilmektedir. 14 numaralı satırda da INTERVAL YEAR TO MONTH tipinin DATE tipiyle toplanabildiğini
görüyoruz. Bu örnekteki INTERVAL YEAR TO MONTH tipindeki değişkenler tanımlanırken YEAR
ifadesinin yanındaki 3 rakamı en fazla 3 haneli yıl değeri taşıyabileceğini gösterir ve en fazla 4
olabilir.
Benzer şekilde kullanabileceğimiz INTERVAL DAY TO SECOND tipi de mevcuttur.
DATE ve INTERVAL İşlemleri
1. Argüman
İşlem
2. Argüman
Sonuç Tipi
DATE
+
INTERVAL
DATE
DATE
-
INTERVAL
DATE
INTERVAL
+
DATE
DATE
DATE
-
DATE
INTERVAL
INTERVAL
+
INTERVAL
INTERVAL
INTERVAL
-
INTERVAL
INTERVAL
INTERVAL
*
NUMERIC
INTERVAL
NUMERIC
*
INTERVAL
INTERVAL
INTERVAL
/
NUMERIC
INTERVAL
TIMESTAMP
TIMESTAMP veri tipi DATE veri tipinin bir varyasyonudur. DATE tipi gibi kullanılabilir.
Örnek 15: TIMESTAMP Veri Tipi
1DECLARE
2 tx TIMESTAMP;
3BEGIN
4
tx := SYSDATE;
5
DBMS_OUTPUT.PUT_LINE(tx);
6
tx := ’05-JUL-07 10:42:35.313 PM’
7END;4
209
210
Bölüm 11
Örnek 15’i çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
02-DEC-07 12.00.00.000000000
6 numaralı satırdaki gibi TIMESTAMP tipine değer ataması yapılabilir.
Bütünleşik Tipler
Bütünleşik tipler herhangi bir basit tipten, referans tipinden ya da LOB tipinden türetilebilen dizilerdir.
Örnek 16: VARRAY Veri Tipi
1DECLARE
2 TYPE PIXA IS VARRAY(4) OF PLS_INTEGER;
3
px PIXA;
4BEGIN
5
px := PIXA(0, 0, 0, 0);
6
px(1) := 3;
7
px(2) := 4;
8
DBMS_OUTPUT.PUT_LINE(px(1));
9
DBMS_OUTPUT.PUT_LINE(px(2));
10
END;
Örnek 16’yı çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
3
4
Bu örnekte göreceğiniz gibi bir diziyi kullanmadan önce bir tip olarak tanımlamamız gerekmektedir. 2 numaralı satırda bu tanım yapılmaktadır. En genel şekilde tip tanımlaması şu şekildedir:
TYPE <yeni tip adı> IS VARRAY(<eleman sayısı>) OF <tip>
Burada yeni tip adı oluşturduğumuz dizi tipine verdiğimiz addır, tip ise mevcut tiplerden biridir. Dizi
indis değerleri 1’den başlar.
Bu örnekte gördüğümüzün dışında bütünleşik tip tanımları da söz konusudur.
Örnek 17: Bileşik Tipler
1DECLARE
2 TYPE TBLARRAY IS TABLE OF VARCHAR2(3);
3
TYPE TBLARRAY2 IS TABLE OF PLS_INTEGER INDEX BY PLS_
INTEGER;
4
TYPE TBLARRAY3 IS TABLE OF PLS_INTEGER INDEX BY
VARCHAR(3);
5
tx1 TBLARRAY;
6
tx2 TBLARRAY2;
7
tx3 TBLARRAY3;
8BEGIN
9
tx1 := TBLARRAY(‘’, ‘’, ‘’);
10
tx1(1) := ‘ABC’;
11
tx1(2) := ‘DEF’;
Oracle Üzerinde Programlama ve PL/SQL
12
DBMS_OUTPUT.PUT_LINE(tx1(1));
13
DBMS_OUTPUT.PUT_LINE(tx1(2));
14
tx2(1) := 10;
15
tx2(2) := 15;
16
DBMS_OUTPUT.PUT_LINE(tx2(1));
17
DBMS_OUTPUT.PUT_LINE(tx2(2));
18
tx3(‘abc’) := 20;
19
tx3(‘def’) := 25;
20
DBMS_OUTPUT.PUT_LINE(tx3(‘abc’));
21
DBMS_OUTPUT.PUT_LINE(tx3(‘def’));
22
END;
Örnek 17’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
ABC
DEF
10
15
20
25
Bu örnekte göreceğiniz gibi PL/SQL, herhangi bir genel amaçlı programlama diline göre bile zengin sayılabilecek seçenekler sunmaktadır. 2 numaralı satırda gördüğümüz tanımlama Örnek 16’ya
göre eleman sayısı tanımlamamaktadır. Böylece TBLARRAY tipinde tanımladığımız herhangi bir
değişkenin eleman sayısı sınır lı olmaktan çıkmıştır; ancak hala Örnek 16’daki gibi 9 numaralı satırda TBLARRAY tipinde tanımladığımız değişkene ilk değerlerini vermek durumundayız. TBLARRAY tipi PLS_INTEGER tipindeki değerlerden oluşan bir dizi tipidir. 3 numaralı satırda, TBLARRAY
tipine göre oluşturduğumuz farklılık INDEX BY ifadesidir. INDEX BY ifadesi dizi tipini tanımlarken
indis değerlerinin hangi tipte olduğunu tanımlamaya yarar. TBLARRAY2 tipinde ilk PLS_INTEGER
ifadesi, TBLARRAY2 tipinden oluşturulacak bir değişkenin PLS_INTEGER tipinde değerler tutacağını gösterirken, satırın sonundaki INDEX BY PLS_INTEGER ifadesi de değişkenin indis değerlerinin PLS_INTEGER ile gösterileceğini ifade eder. 14 ve 15 numaralı satırlarda gördüğünüz
gibi tx2 tipinin indisleri de değerleri de PLS_INTEGER tipindedir. Ayrıca bu tanımla artık dizinin ilk
değerlerini önceden vermek zorunluluğumuz ortadan kalktı. 4 numaralı satırdaki tip tanımında ise
3 numaralı satırdan sadece değişken indislerinin nasıl tutulacağı değişmiştir. TBLARRAY3 tipinde
tanımlanan bir dizinin indisleri VARCHAR2(3) tipinde olacaktır ve içinde PLS_INTEGER tipinde
değerler tutacaktır. Buna ait kullanımı da 18 ve 19 numaralı satırlarda görebilirsiniz. Herhangi bir
dizide dizinin ilk elemanına erişmek için FIRST, son elemanına erişmek için de LAST ifadelerini
kullanabiliriz. Bununla ilgili örneği Örnek 18’de görebilirsiniz:
Örnek 18: FIRST ve LAST
1DECLARE
2 TYPE TBLARRAY IS TABLE OF VARCHAR2(3);
3
TYPE TBLARRAY2 IS TABLE OF PLS_INTEGER INDEX BY PLS_
INTEGER;
4
TYPE TBLARRAY3 IS TABLE OF PLS_INTEGER INDEX BY
VARCHAR(3);
5
tx1 TBLARRAY;
6
tx2 TBLARRAY2;
211
212
Bölüm 11
7
tx3 TBLARRAY3;
8BEGIN
9
tx1 := TBLARRAY(‘’, ‘’, ‘’);
10
tx1(1) := ‘ABC’;
11
tx1(2) := ‘DEF’;
12
DBMS_OUTPUT.PUT_LINE(tx1(1));
13
DBMS_OUTPUT.PUT_LINE(tx1(tx1.LAST));
14
tx2(1) := 10;
15
tx2(2) := 15;
16
DBMS_OUTPUT.PUT_LINE(tx2(tx2.FIRST));
17
DBMS_OUTPUT.PUT_LINE(tx2(2));
18
tx3(‘abc’) := 20;
19
tx3(‘def’) := 25;
20
DBMS_OUTPUT.PUT_LINE(tx3(‘abc’));
21
DBMS_OUTPUT.PUT_LINE(tx3(tx3.LAST));
22
END;
Örnek 18’i çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
ABC
10
15
20
25
Bu örnekte 13 numaralı satırın çalışmasından sonucu oluşmaktadır; çünkü 9 numaralı satırda
dizinin 3. elemanını olarak tanımladık.
RECORD
RECORD tipi T-SQL’de olmayan bir tiptir. C#’taki struct gibi düşünülebilir.
Örnek 19: RECORD Tanımlama
1DECLARE
2 TYPE REC_URUN IS RECORD(ID INTEGER, AD
VARCHAR2(10));
3
rUrun REC_URUN;
4BEGIN
5
SELECT;
6
UrunId, UrunAdi
7
INTO rUrun
8
FROM Urun
9
WHERE ROWNUM = 1;
10
DBMS_OUTPUT.PUT_LINE(‘Urun ID: ’ || rUrun.ID || ‘
Adi: ’ || rUrun.AD);
11
END;
Oracle Üzerinde Programlama ve PL/SQL
Örnek 19’u çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
Urun ID: 1
Adi: Bisküvi
2 numaralı satırda INTEGER tipinde bir değer ve VARCHAR2 tipinde bir değer alan REC_URUN
adında bir RECORD oluşturduk. 3 numaralı satırda bu tipte bir değişken tanımladık. 5, 6, 7, 8 ve 9
numaralı satırlardan oluşan SELECT cümleciği ile rUrun değişkeninin içine ID ve AD bilgileri atadık. SELECT cümleciğinde T-SQL’de olmayan bir alan olan ROWNUM’ı kullanıdk. ROWNUM, SELECT
ifadesinin sonucunda oluşan kümenin sıra numarasını alan bir değerdir. Dolayısıyla ROWNUM =
1 olduğu için ilk satır verilerini RECORD’ın içine atmış durumdayız. 10 numaralı satırda da bu değerleri tek tek yazdırdık. RECORD, CURSOR ile birlikte kullanıldığında daha güçlü bir yapıyla karşı
karşıya kalacağız.
Referans Tipleri
Referans tipleri bir işaretçi aracılığıyla bellekte asıl veri bloğunun tutulduğu adresi gösteren veri
tipidir. Esnek tipler olışturabilmek açısından oldukça önemlidir.
REF CURSOR
REF CURSOR tipine geçmeden önce daha basit bir tip olan CURSOR tipinden bahsetmek gerekir. CURSOR tipi T-SQL’deki CURSOR’lara karşılık gelir; ancak kullanımında çok sayıda detay
vardır. Mantıksal olarak da T-SQL’deki CURSOR’larla aynı mantıkta çalışır.
Örnek 20: CURSOR Tanımlama
1DECLARE
2 CURSOR curUrun IS
3
SELECT
4
UrunId, UrunAdi
5
FROM Urun;
6
ID INTEGER;
7
AD VARCHAR2(10);
8BEGIN
9
OPEN curUrun;
10
LOOP
11
FETCH curUrun INTO ID, AD;
12
EXIT WHEN NOT curUrun%FOUND;
13
14
END LOOP;
15
CLOSE curUrun;
16
END;
DBMS_OUTPUT.PUT_LINE(ID || ‘ – ‘ || AD);
Örnek 20’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
1 - Bisküvi
2 - Çikolata
2, 3, 4 ve 5 numaralı satırlar CURSOR tanımını oluşturur. 3, 4 ve 5 numaralı satırlardaki SELECT
cümleciğinin sonucu curUrun adlı CURSOR içine satır satır atılacaktır; ancak bu işlem bu bölümde yapılmaz. Burada sadece CURSOR için tanım mevcuttur. 9 numaralı satırda CURSOR açıldıktan
sonra, bir sonraki konuda işleyeceğimiz LOOP döngüsü içinde CURSOR tanımına göre satır satır
işleme yapılacaktır. 11 numaralı satırda ilk staır CURSOR değişkenleri olan ID ve AD değişkenle-
213
214
Bölüm 11
rine alınır. 12 numaralı satır LOOP döngüsünün curUrun içinde satır bulunamadığında çıkması
için yazılmıştır. curUrun%FOUND ifadesi T-SQL’deki CURSOR için kullandığımız WHILE döngüsündeki @@FETCH_STATUS != -1 ifadesi ile aynı şekilde çalışır. 13 numaralı satırda CURSOR
değişkenleri DBMS çıktısı olarak yazılır. 15 numaralı satırda da CURSOR kapatılır. OPEN ile açılan
bir CURSOR belleğin etkin kullanımı açısından mutlaka CLOSE ile kapatılmalıdır.
Örnek 20: T-SQL’de CURSOR Tanımlama
1DECLARE @ID INT, @AD VARCHAR(10)
2 DECLARE curUrun INSENSITIVE CURSOR FOR
3
SELECT
4
UrunId, UrunAdi
5
FROM Urun
6
OPEN vurUrun
7
FETCH NEXT FROM curUrun INTO @ID, @AD
8
WHILE @@FETCH_STATUS != -1
9
BEGIN
10
PRINT CONVERT(VARCHAR, @ID) + ‘ – ‘ + @AD
11
FETCH NEXT FROM curUrun INTO ID, AD
12
END
13
CLOSE curUrun
14
DEALLOCATE curUrun
Örnek 20.1’de Örnek 20’deki PL/SQL ile kullanılan CURSOR yapısnın T-SQL karşılığını görebilirsiniz.
Örnek 21: CURSOR Değerlerinin RECORD İçine Atılması
1DECLARE
2
TYPE REC_URUN IS RECORD (ID INTEGER, AD VARCHAR2(10));
3
TYPE REC_URUN_ARR IS TABLE OF REC_URUN INDEX BY PLS_
INTEGER;
4
rUrun REC_URUN;
5
rUrunArr REC_URUN_ARR;
6 CURSOR curUrun IS
7
SELECT
8
UrunId, UrunAdi
9
FROM Urun;
10
ROWN PLS_INTEGER;
11
BEGIN
12
OPEN curUrun;
13
ROWN := 1;
14
LOOP
15
FETCH curUrun INTO rUrun;
16
EXIT WHEN NOT curUrun%FOUND;
17
rUrunArr(ROWN) := rUrun;
18
DBMS_OUTPUT.PUT_LINE(rUrunArr(ROWN).ID || ‘
– ‘ || rUrunArr(ROWN).AD);
Oracle Üzerinde Programlama ve PL/SQL
19
END LOOP;
20
CLOSE curUrun;
21
END;
Örnek 21’i çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
1 - Bisküvi
2 - Çikolata
2 numaralı satırda CURSOR için çalışan SELECT sorgusunun kayıt desenine uygun şekilde bir
RECORD oluşturduk. 3 numaralı satırda da CURSOR üzerinden REC_URUN tipindeki kayıtlarımızı
toplayacağımız değişken uzunluklu, PLS_INTEGER indisli, REC_URUN tipinde bir dizi tipi tanımladık. 4 numaralı satırda CURSOR’dan dönen her satırı tutacağımız kayıt değişkenini tanımladık. 5
numaralı satırda da bu kayıt değişkenlerinin hepsini toplayacağımız diziyi tanımladık. 10 numaralı
satırda REC_URUN_ARR tipindeki dizinin indisini tutmak için PLS_INTEGER tipinde bir değişken
tanımladık. 13 numaralı satırda dizi indisleri 1’den başladığı için ROWN değerini 1 yaptık. 15 numaralı satırda Örnek 20’ye göre farklı olarak CURSOR’dan dönen kaydı olduğu gibi REC_URUN tipindeki rUrun adlı kayıt değişkenine atadık. 17 numaralı satırda da REC_URUN_ARR tipindeki rUrunArr dizisinin ROWN numaralı indisindeki alana rUrun kaydını yerleştirdik. 18 numaralı satırda
rUrunArr(ROWN).ID ve rUrunArr(ROWN).AD ifadelerini rUrunArr dizisinin her elemanının
REC_URUN kayıt tipinde olmasından dolayı, kayıt deseninde tanımlı değişkenlerle kullanabildik.
Örnek 22: REF CURSOR Değerlerinin RECORD İçine Atılması
1DECLARE
2
TYPE REC_URUN IS RECORD (ID INTEGER, AD VARCHAR2(10));
3
TYPE URUN_CUR_TYPE IS REF CURSOR RETURN REC_URUN;
4
rUrun REC_URUN;
5
cUrunType URUN_CUR_TYPE;
6BEGIN
7
OPEN cUrunType FOR
8
SELECT
9
UrunId, UrunAdi
10
11
LOOP
12
FETCH cUrunType INTO rUrun;
13
EXIT WHEN NOT cUrunType%FOUND;
14
rUrun.AD);
DBMS_OUTPUT.PUT_LINE(rUrun.ID || ‘ – ‘ ||
15
END LOOP;
16
CLOSE cUrunType; 17
END;
FROM Urun;
Örnek 22’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
1 - Bisküvi
2 - Çikolata
2 numaralı satırda Örnek 21’deki gibi RECORD tipinde kayıt desenimizi tanımladık. 3 numaralı
satırda da REF CURSOR tipimizi tanımladık. 4 ve 5 numaralı satırlarda bu tiplere ait değişkenlerimizi oluşturduk. 7, 8, 9 ve 10 numaralı satırlarda URUN_CUR_TYPE adında REF CURSOR tipinde
215
216
Bölüm 11
REC_URUN tipinde değer döndüren CURSOR yapımızı hem tanımladık, hem de açtık. Bu yapı TSQL’deki CURSOR yapısına daha çok benzemektedir; ancak T-SQL’de RECORD yapısına benzer
yapılar olmadığı için bu örneğin bire bir T-SQL karşılığı yoktur. 12 numaralı satırda oluşturduğumuz REF CURSOR tipinin içindeki değeri REC_URUN tipinin içine yerleştirdik. 14 numaralı satırda
da o satır için rUrun adlı kayıttaki ID ve AD alanlarının değerlerini yazdırdık.
LOB (Large Object) Tipleri
Yapısal olmayan büyük verilerin tutulması için kullanışlı tiplerdir. En fazla tutabilecekleri veri miktarı 4GB’tır. Asıl verilerini işaretçi mantığıyla tutarlar.
BFILE
BFILE veri tipi, büyük verilerinin veri tabanı üzerinde değil işletim sisteminin üzerindeki dosya
sistemi üzerinde tutulmasını sağlayan bir tiptir. BFILE aslında bu fiziksel dosyaya ait adresi tutar.
BFILE tipindeki veri değiştirilemez. Kullanımı transaction mantığı çerçevesinde risklidir; çünkü
transaction ile çalışan bir tip değildir ve transaction’a dahil edilmezler. Replikasyon ile replike
edilemezler.
BLOB (Binary Large Object)
BLOB veri tipinin BFILE veri tipinden farkları, tuttuğu verinin veri tabanı dosyaları içinde tutulması
ve transaction’a dahil olması ve replike edilebilir olmasıdır. BLOB veri tipinde veri binary olarak
saklanır. Microsoft SQL Server 2005 ile birlikte gelen BLOB tipi gibidir.
CLOB (Character Large Object)
CLOB veri tipinin BLOB veri tipinden farkı tuttuğu verinin binary yerine alfanümerik olmasıdır. Diğer
özellikleri BLOB tipi gibidir. Microsoft SQL Server 2005 ile birlikte gelen CLOB tipi gibidir.
NCLOB
NCLOB veri tipinin CLOB veri tipinden farkı NCHAR tipinden oluşmasıdır. Bunun anlamı yerel alfabelerin de rahatlıkla kullanılabileceğidir.
PL/SQL’de Döngü Yapıları
LOOP Döngüsü
LOOP döngüsü normalde koşulsuz bir döngü tipidir. EXIT ifadesi işletilene kadar döngü tekrarlamaya devam eder. LOOP ile CURSOR konusunda da örnek görmüştük.
Örnek 23: LOOP Döngüsü
1DECLARE
2
ix PLS_INTEGER;
3BEGIN
4
ix := 1;
5
LOOP
6
IF ix != 5
7
THEN
8
ix := ix + 1;
9
DBMS_OUTPUT.PUT_LINE(ix);
10
ELSE
11
12
END IF;
13
END LOOP;
14
END;
EXIT;
Oracle Üzerinde Programlama ve PL/SQL
Örnek 23’ü çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
2
3
4
5
Bu örnekte dikkat etmemiz gereken en önemli nokta 4 numaralı satırda eğer ix değişkenine değer ataması yapmazsak 6 numaralı satırdaki karşılaştırmadan beklenmedik şekilde FALSE değeri
üretilmesidir. Bu sebeple LOOP döngü yapısını kullanırken kontrol değişkenine ilk değer atamasını yapmak önemlidir. 5 ile 13 numaralı satırlar arasında tanımlanan LOOP döngüsünden çıkmak
için bu blok içinde kod akışında mutlaka EXIT ifadesinin çalışması gerekir; aksi takdirde sonsuz
döngü oluşacaktır. Örneğimizde eğer ix değişkeninin değeri 5’e eşit olursa 10 numaralı satırdaki
ELSE bloğu çalışır ve EXIT ifadesi de böylece çalışmış olur ve LOOP döngüsü sonlandırılarak
program akışı 13 numaralı satırdan itibaren devam eder.
EXIT WHEN İfadesi
LOOP döngüsünde koşullu çıkışı sağlamak için kullanılan bir ifadedir. IF bloğu yerine kullanılabilir.
Örnek 24: LOOP Döngüsü ve EXIT WHEN İfadesi
1DECLARE
2
ix PLS_INTEGER;
3BEGIN
4
ix := 1;
5
LOOP
6
EXIT WHEN ix = 5;
7
ix := ix + 1;
8
END LOOP;
9END;
Örnek 24’ü çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
2
3
4
5
Bu örnekte LOOP döngüsü her döndüğünde 6 numaralı satırda EXIT WHEN ix = 5 ifadesiyle
karşılaşarak ix değerinin 5’e eşit olup olmadığını kontrol edecektir. Eğer ix 5’e eşitse EXIT ifadesi çalışacak ve program akışı 8 numaralı satırdan devam edecektir.
WHILE – LOOP Döngüsü
WHILE – LOOP döngüsü EXIT WHEN ifadesi ile kullanılan LOOP döngüsüne çok benzerdir. Bu
döngü tipinde WHILE ile tanımlanan koşul sağlandığı sürece döngü iterasyona devam eder.
Örnek 25: WHILE - LOOP Döngüsü
1DECLARE
2
3BEGIN
ix PLS_INTEGER;
217
218
Bölüm 11
4
ix := 1;
5
WHILE ix < 5
6
LOOP
7
8
END LOOP;
ix := ix + 1;
9END;
Örnek 25’i çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
2
3
4
5
Bu örnekte 5 numaralı satırdaki ix < 5 koşulu sağlandığı sürece program akışı 8 numaralı
satıra gelmez. Dolayısıyla koşul sağlanana kadar kaç defa çalışacağını bilmediğimiz yapılarda
kullanılması uygundur. EXIT ifadesinin olmaması sebebiyle koşullu çıkışın sağlanması semantik
olarak sağlandığı için LOOP döngüsüne tercih edilmelidir. WHILE ifadesinin yanındaki koşulun
tipi mutlaka BOOLEAN olmalıdır. 0 (sıfır) dışındaki tüm değerler TRUE, 0 (sıfır) FALSE’tur gibi bir
durum söz konusu değildir.
FOR – LOOP Döngüsü
FOR – LOOP döngüsü de WHILE – LOOP döngüsüne benzer yapıdadır; ancak en önemli farkı
koşula bağlı olmaktan çok iterasyon sayısının bilindiği yapılarda kullanılır. WHILE ile geçişkendir.
Örnek 26: FOR - LOOP Döngüsü
1BEGIN
2
FOR ix IN 2..5
3
LOOP
4
5
END LOOP;
DBMS_OUTPUT.PUT_LINE(ix);
6END;
Örnek 26’yı çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
2
3
4
5
Bu örnekte WHILE – LOOP döngüsüne göre kontrol ettiğimizde DECLARE bölümünde bir değişken tanımlamaya ihtiyacımız yoktur. 2 numaralı satırdaki FOR ix IN 2..5 ifadesi ile ix değişkeni otomatikman tanımlanmış olur. 2 numaralı satırın anlamı, 2’den 5’e kadar olan sayıları her
döngüde 1’er artırarak ix değişkenine atama yapmaktır.
Örnek 27: FOR - LOOP Döngüsü
1BEGIN
2
FOR ix IN REVERSE 2..5
3
LOOP
Oracle Üzerinde Programlama ve PL/SQL
4
DBMS_OUTPUT.PUT_LINE(ix);
5
END LOOP;
6END;
Örnek 27’yi çalıştırdığımızda aldığımız DBMS çıktısı şu şekildedir:
5
4
3
2
Bu örnekte 2 numaralı satırda IN ifadesinden sonra kullandığımız REVERSE ifadesi döngünün
2’den 5’e kadar 1’er artırarak değil, 5’ten 2’ye kadar 1’er eksilterek dönmesini sağlayacaktır ve
her seferinde ix değişkenine 5’ten itibaren 1’er eksilterek değer ataması yapacaktır.
Procedure Oluşturmak
PL/SQL’de procedure olışturmak T-SQL’den çok farklı değildir. PL/SQL’de Procedure’lar TSQL’deki SP (stored procedure)’ler gibi IN, OUT ve IN OUT yönlü parametrelere sahiptirler,
PL/SQL’deki procedure’larda RETURN yoktur, bunun yerine FUNCTION kullanılır.
Örnek 28: PL/SQL’de Procedure
1CREATE OR REPLACE PROCEDURE UrunYaz
2(
3
ID IN PLS_INTEGER,
4
AD IN VARCHAR2
5)
6AS
7
RowCount PLS_INTEGER;
8BEGIN
9
SELECT
10
COUNT(*) INTO RowCount
11
FROM Urun
12
WHERE UrunId = ID;
13
IF RowCount = 0
14
THEN
15
AD);
16
END IF;
17
END;
INSERT INTO Urun(UrunId, UrunAdi) VALUES(ID,
Örnek 28’deki kodu çalıştırdığınızda UrunYaz adında bir procedure SYSTEM schema’sı için login
olduğumuz veri tabanı üzerinde daha önceden yazılmamışsa yaratılacaktır, eğer daha önceden
varsa üstüne yazılacaktır. Bunu sağlayan 1 numaralı saturdaki CREATE OR REPLACE ifadesidir.
Bunun yerine sadece CREATE ya da REPLACE de kullanılabilir. 3 ve 4 numaralı satırlarda UrunYaz procedure’ının argümanlarıdır. 3 numaralı satırda ID adında, PLS_INTEGER tipinde, IN yani
dışarıdan gelen bir argüman tanımlanmıştır. 4 numaralı satırda AD adında, VARCHAR2 tipinde, IN
yönünde diğer argüman tanımlanmıştır. 7 numaralı satırda procedure’ın içinde kullanacağımız
RowCount adında, PLS_INTEGER tipinde bir değişken aynı ID’ye sahip tabloda başka kayıt
olup olmadığını kontrol etmek amacıyla, satır sayısını tutmak üzere tanımlanmıştır. 9, 10, 11 ve
219
220
Bölüm 11
12 numaralı satırlardali SELECT cümleciğiyle RowCount değerine UrunYaz procedure’ına ID
argümanıyla gelen değere sahip UrunId’li alanların sayısı atanmıştır. 13 numaralı satırda eğer
bu ID’ye sahip bir kayıt yoksa 15 numaralı satırdaki INSERT cümleciği çalışması için RowCount
değişkeninin 0 olup olmadığı kontrol edilmektedir. Eğer RowCount 0 ise INSERT çalışır, aksi
takdirde procedure sonlanır.
Bu procedure’ı çalıştırmak için yazmamız gereken kod Örnek – 29’daki gibidir:
Örnek 29: PL/SQL ile Procedure Çalıştırmak
1DECLARE
2
IDx PLS_INTEGER := 4;
3
ADx VARCHAR2(10) := ‘Gofret’;
4BEGIN
5
UrunYaz(ID => IDx, AD => ADx);
6END;
Örnek 29’da 2 ve 3 numaralı satırlarda UrunYaz procedure’ına argüman olarak göndereceğimiz
değerleri tanımladık. 5 numaralı satırda da UrunYaz procedure’ını bu değerlerle çalıştırdık.
Örnek 30: PL/SQL ile OUT Parametreli Procedure
1CREATE OR REPLACE PROCEDURE UrunYazOut
2(
3
ID IN PLS_INTEGER,
4
AD IN VARCHAR2,
5
EKLENDI OUT BOOLEAN
6)
7AS
8
RowCount PLS_INTEGER;
9BEGIN
10
SELECT
11
COUNT(*) INTO RowCount
12
FROM Urun
13
WHERE UrunId = ID;
14
IF RowCount = 0
15
THEN
16
AD);
INSERT INTO Urun(UrunId, UrunAdi) VALUES(ID,
17
EKLENDI := TRUE;
18
ELSE
19
20
END IF;
21
END;
EKLENDI := FALSE;
Örnek 30’da 5 numaralı satırda EKLENDI adında, BOOLEAN tipinde, OUT yönlü bir argüman tanımladık. Eğer 16 numaralı satırda INSERT işlemine gelinirse EKLENDI değeri TRUE olur; aksi
takdirde FALSE olur. Örnek – 31’de de UrunYazOut procedure’ının nasıl çalıştırıldığını görebilirsiniz.
Oracle Üzerinde Programlama ve PL/SQL
Örnek 31: PL/SQL ile Out Argümanlı Procedure Çalıştırmak
1DECLARE
2
IDx PLS_INTEGER := 4;
3
ADx VARCHAR2(10) := ‘Gofret’;
4
DURUM BOOLEAN;
5BEGIN
6
UrunYazOut(ID => IDx, AD => ADx, EKLENDI => DURUM);
7
IF DURUM = TRUE
8
THEN
9
DBMS_OUTPUT.PUT_LINE(‘Eklendi’);
10
ELSE
11
12
END IF;
13
END;
DBMS_OUTPUT.PUT_LINE(‘Eklenmedi’);
Örnek 31’de 4 numaralı satırda UrunYazOut procedure’ından OUT parametre (argüman) yoluyla
gelecek değeri tutmak için bir BOOLEAN değişken oluşturduk. 6 numaralı satırda da IN yönlü argümanlar gibi OUT yönlü argümanımızı da oluşturduk. 7 numaralı satırdan itibaren IF bloğundan
DURUM değişkeninin değerine göre DBMS çıktısına ‘Eklendi’ ya da ‘Eklenmedi’ yazacaktır.
Fonksiyon Oluşturmak
PL/SQL’de fonksiyonlar T-SQL’deki fonksiyonlara çok benzer özellikler gösterir. IN, OUT ve IN
OUT yönlü argümanlarla çalışırlar ve RETURN ifadesi ile bir değer döndürürler. C# ve Java’daki
dönmüş tipi void olmayan metotlar gibidir.
Örnek 32: PL/SQL’de Fonksiyon
1CREATE OR REPLACE FUNCTION UrunAdiOku
2(
3
ID IN PLS_INTEGER
4)
5RETURN VARCHAR2
6AS
7
AD VARCHAR2(10);
8BEGIN
9
SELECT
10
UrunAdi INTO AD
11
FROM Urun
12
WHERE UrunId = ID;
13
RETURN AD;
14
END;
Örnek 32’deki kodu çalıştırdığınızda UrunAdiOku adında fonksiyonumuz eğer daha önce yaratılmamışsa yaratılacaktır; aksi takdirde üstüne yazılacaktır. Procedure’lardaki gibi fonksiyonlarda
da CREATE ve REPLACE ifadeleri tek başlarına kullanılabilir.
221
222
Bölüm 11
Örnek 33: PL/SQL ile Fonksiyon Çalıştırmak
1DECLARE
2
IDx PLS_INTEGER := 4;
3
ADx VARCHAR2(10);
4BEGIN
5
ADx := UrunAdiOku(ID => IDx);
6
DBMS_OUTPUT.PUT_LINE(ADx);
7END;
Örnek 33’de 3 numaralı satırda VARCHAR2(10) tipinde tanımalanan ADx isimli değişken UrunAdiOku fonksiyonundan dönen değeri tutacak değişkendir. 5 numaralı satırda ADx değişkenine
UrunAdiOku fonksiyonundan dönen değerin ataması yapılmıştır. Bu atama sırasında tip uyumu
çok önemlidir. Eğer uyumsuz tipler kullanırsanız istenmeyen sonuçlarla karşılaşabilirsiniz. 6 numaralı satırda da ADx değişkenine atanan fonksiyon dönüş değeri DBMS çıktısına yazdırılır.
Download