HackerRank — Java Static Initializer Block
Static değişken, metod ve blok nasıl tanımlanır? Java Static Initializer Block sorusunun çözümü
HackerRank üzerindeki Java problemlerini çözüyoruz. Bu onuncu problem. Eğer diğer problem çözümlerini okumadıysanız önce onlara bakmanızı tavsiye ederim, hepsinin toplu hali:
Önce problemi anlayalım sonra da çözümüne geçelim. Problemi anlama kısmını okuduktan sonra problemi çözmeyi denemenizi sonra da buradaki çözümle karşılaştırmanızı şiddetle tavsiye ederim :)
Problemin linki 👇
Problemi anlayalım
Bu problemde static kavramı üzerine duracağız. Static değişkenler yazabildiğimiz gibi static metodlar ve direkt static blok da oluşturabiliriz.
Static yapılar(değişkenler ve blok) sınıfın nesnesinden bağımsız program çalıştığında bir defa çalışırlar/oluşturulurlar. Genelde değişmeyen final değerler static değişken olarak tanımlanır. Static-final değişken tanımı aşağıdaki gibi yapılır, final değişkenler atama yapıldıktan sonra değiştirilemezler:
public static final int CAPACITY = 10;
Final olmadan static değişken de tanımlayabiliriz, final olmadığı için sonradan da değiştirebiliriz:
public static int capacity = 10;
Static metod tanımını aşağıdaki gibi yapabiliriz. Static metodlar sınıfın nesnesinden bağımsız da çağrılabilir.
private static void initializeClassVariable() {
// kod
}
Değişken ve metodun yanında static blok da oluşturabiliriz. Static bloklar bulunduğu sınıf için bir defa çağrılır. Sınıfın constructor’dan önce çalışır.
static {
// kod
}
Bazı son notlar:
- Static blok bir sınıf içerisinde birden çok olabilir. Yazıldıkları sırayla çağrılırlar.
- Static metod ya da blok içerisinde dışarıdan değişken kullanılacaksa o değişkenlerin de static olması gerekir.
- Static değişken, blok ve metodlar kodun herhangi bir yerinde olabilir. Ama clean code mantığına göre sınıfın başlangıcında olması güzel bir pratik olarak kabul edilir.
- Static blokların içerisinde yazılan kod blokunu static bir metod olarak tanımlamak güzel bir pratik olarak kabul ediliyor. Böylelikle static blok dışında da aynı işlemleri yapmak gerekirse static metod kullanılabilir.
Problem Beklentisi
HackerRank üzerinde bize aşağıdaki kod sağlanıyor. Bu problemde main metodunda değişiklik yapmayacağız. Main metodunun dışında static tanımlamalar yapacağız.
public static void main(String[] args){
if(flag){
int area=B*H;
System.out.print(area);
}
}
Problemde bir paralelkenarın kısa ve uzun kenarını input olarak alacağız. Bu iki inputun değer sınır kontrolünü yapıp buna göre sınır dışıysa “java.lang.Exception: Breadth and height must be positive
” print edilecek, kontrolden geçerse de main metoddaki flag’e “true” atanacak ve sonucun print edilmesi sağlanacak.
B ve H inputları “-100≤B≤100” ve “-100≤H≤100” şartına uygun olarak girilecek.
- B ve H pozitif sayılarsa “B*H” sonucu print edilecek
- B veya H pozitif bir sayı değilse
java.lang.Exception: Breadth and height must be positive
print edilecek
Örnek Input 1:
1
3
Örnek Output 1:
3
Örnek Input 2:
-1
2
Örnek Output 2:
java.lang.Exception: Breadth and height must be positive
Problem Çözümü
Bu problemde iki çözüm sunabilirim. İkinci çözümde mantık ve çalışma zamanı olarak farklı bir durum yok, sadece best pratice uygulayarak refactor ettim.
Birinci çözüm:
public class Solution {
static boolean flag = false;
static int B;
static int H;
static{
Scanner sc = new Scanner(System.in);
B= sc.nextInt();
H= sc.nextInt();
sc.close();
if(B<=0 || H<=0)
{
System.out.println(
"java.lang.Exception: Breadth and height must be positive");
}
else{
flag = true;
}
}
public static void main(String[] args){
if(flag){
int area=B*H;
System.out.print(area);
}
}
}
Burada static metod tanımlamamızın sebebi, main’i değiştirmeden main’den önce çalışacak blok oluşturmanın tek yolu static blok oluşturmak. Static blok içerisinde iki input alıyoruz. Inputları depolamak için B ve H adında iki değişkenimiz var. Static blok içerisinde kullanmak için onların da static olması gerekiyor. If ile “B≤0 || H≤0” kontrolünü yaparak sınırı aşan bir durum varsa flag değişkenini değiştirmeden exception print ediyoruz. Kontrolü geçtiği durumda ise flag değerini true yapıyoruz. Static blok çalışması bittiğinde main metod çalışıyor. Main metod içinde flag değişkeni true ise B*H sonucunun print edileceğini göreceğiz.
İkinci çözümde birden çok best pratice uyguluyoruz:
public class Solution {
private static final String ERROR_MESSAGE =
"java.lang.Exception: Breadth and height must be positive";
private static int breadth;
private static int height;
private static boolean flag = false;
static {
initializeDimensions();
}
private static void initializeDimensions() {
try (Scanner scanner = new Scanner(System.in)) {
breadth = scanner.nextInt();
height = scanner.nextInt();
if (breadth <= 0 || height <= 0) {
throw new IllegalArgumentException(ERROR_MESSAGE);
}
flag = true;
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
if (flag) {
int area = breadth * height;
System.out.print(area);
}
}
}
- Static blok içindeki kodu ayrı bir static metod haline getirip tanımladım. Bunu özellikle tekrar çalıştırmanız gereken bir işlemse yapmanız öneriliyor. Aynı zamanda yapılan işlemi direkt tanımlamak için de ayrı metod yapmak mantıklı.
- Error mesajının değişmeyen bir yapısı olduğu için final olarak sabit bir değişkende tanımladım.
- initializeDimensions() içerisinde try-catch ile olası bir scanner hatasının olma olasılığını ele aldık. Bu problemde buna yönelik bir test case beklemiyoruz ama normal şartlarda bunu eklerdim diyip ekledim :)
- try-catch yapısında try(…) yapısıyla scanner oluşturulmasını buraya eklediğim için try yapısı bittiğinde scanner otamatik kapanıyor, tekrardan scanner.close() yapmamıza gerek kalmıyor. Bunu file işlemlerinde de bu şekilde yapabiliriz.
- Exception mesajı için throw exception daha profesyonel durduğu için bu şekilde kullandım.
- Aslında “flag” ismi HackerRank’ten tanımlı gelmese “isValid” gibi boolean olduğunu belirten bir isim seçerdim.
“Java Static Initializer Block” problemini de çözmüş olduk! Bol kodlu ama bug’sız günler dilerim :)
Tüm problemlerin çözümleri 👇
Bu yazı için kullandığım kaynak: “https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html”