
Merhaba arkadaşlar,
Bu yazımda her ne kadar Java 9, Java 10, Java 11 ve Java 12 versiyonları yayınlamış olsa da size mevcut Java projelerinde daha çok kullanılan veya geçiş yapılan Java 8’in bir önceki versiyon olan Java 7 ile arasındaki farklardan bahsedeceğim. Bu farklardan bahsederken başlık, kısa açıklama ve örnek kod şeklinde bir yol ile ilerleyeceğim. Haydi başlayalım.😊
- Base64 Sınıfı
Daha önceki versiyonlarda olması gerektiğine inandığım ve ihtiyaç duyulabilen bir sınıf olan Base64 sınıfı bu versiyonda geldi sonunda.Bu sınıf Encoder’lar ve Decoder’lar olan statik yöntemlerden oluşan bir sınıftır.
Java 8 de Basic, URL ve MIME olmak üzere 3 çeşit “Base64” kodlama türü vardır. Decode ve Encode işlemlerinde RFC 4648 ve RFC 2045 yöntemleri kullanılmaktadır.
import java.io.UnsupportedEncodingException; import java.util.Base64; public class Base64Ex { public static void main(String[] args) { try { // Basit Encode String encodedString = Base64.getEncoder().encodeToString("Hasan".getBytes("utf-8")); System.out.println("encodedString: " + encodedString); // Basit Decode byte[] decodedBytes = Base64.getDecoder().decode(encodedString); System.out.println("decodedString: " + new String(decodedBytes, "utf-8")); // URL Encode String urlEncodedString = Base64.getUrlEncoder() .encodeToString("http://www.google.com/xhtml".getBytes("utf-8")); System.out.println("urlEncodedString: " + urlEncodedString); // Url Decode byte[] urlDecodedBytes = Base64.getUrlDecoder().decode(urlEncodedString); System.out.println("urlDecodedBytes: " + new String(urlDecodedBytes, "utf-8")); // MIME Encode String mimeEncodedString = Base64.getMimeEncoder() .encodeToString("JSIDAHFAasjhdasdksıdsajdhs".getBytes("utf-8")); System.out.println("mimeEncodedString: " + mimeEncodedString); // MIME Decode byte[] mimeDecodedBytes = Base64.getMimeDecoder().decode(mimeEncodedString); System.out.println("mimeDecodedBytes: " + new String(mimeDecodedBytes, "utf-8")); } catch (UnsupportedEncodingException e) { System.out.println("Error: " + e.getMessage()); } } }
Output:
encodedString: SGFzYW4=
decodedString: Hasan
urlEncodedString: aHR0cDovL3d3dy5nb29nbGUuY29tL3hodG1s
urlDecodedBytes: http://www.google.com/xhtml
mimeEncodedString: SlNJREFIRkFhc2poZGFzZGtzxLFkc2FqZGhz
mimeDecodedBytes: JSIDAHFAasjhdasdksıdsajdhs
- Lambda Projesi
Java 8 için en çok beklenen geliştirmelerden biri olan Lambda Projesi ile Java’nın fonksiyonel programlamaya geçişi ve Java’da geliştirme kolaylığı amaçlanmıştır. Lambda ifadelerini genel olarak tanımlamak gerekirse, herhangi bir sınıfa ait olmadan iş yapabilen fonksiyonlardır. Tek soyut metotlu Interface’leri (arayüzleri) kısa yoldan tanımlamak için kullanılır. Lambda ifadeleri genel olarak aşağıdaki şekillerde ifade edilebilir.
Parametre listesi -> fonksiyon gövdesi
() -> { işlem++; };
param1 -> param1++;
(param1, param2) -> {
param2++;
param1++;
return param1 + param2;
};
Lambda ifadelerinin örnekleri ile beraber genel özellikleri;
- Parametre için tür bildiriminin gerekliliği sonlanmıştır.
public class LambdaEx1 { public static void main(String[] args) { // tur bildirimi yok Func fonk = (p1, p2) -> { return p1 + p2; }; int sum = fonk.topla(2, 2); System.out.println("sum = " + sum); } } interface Func { int topla(int param1, int param2); }
Output:
sum = 4
- İfademizde tek parametre ihtiyacında, parametre tarafında paranteze ihtiyaç yoktur. İfademizde parametre olmaması durumunda veya birden fazla parametre olması durumunda, parametre tarafında parantez ihtiyacı vardır.
public class LambdaEx2 { public static void main(String[] args) { // iki parametreli lambda Fonk fonk = (p1, p2) -> { return 2 * p1 + p2; }; // parametresiz lambda Sohbet sohbet = () -> { System.out.println("Merhabalar :]"); }; sohbet.merhabaDe(); int sum = fonk.toplam(4, 2); System.out.println("sum = " + sum); } } interface Fonk { int toplam(int param1, int param2); } interface Sohbet { void merhabaDe(); }
Output:
Merhabalar :]
sum = 10
- Fonksiyon gövdesinde tek bir işlem varsa süslü parantezlere gerek yoktur. Birden fazla işlem olması durumunda süslü parantez ihtiyacı vardır.
public class LambdaEx3 { public static void main(String[] args) { // suslu parantezsiz lambda Matematik carpma = (a, b) -> a * b; System.out.println("3 x 5 = " + carpma.islemYap(3, 5)); // suslu parantezli lambda Matematik mutlakMesafe = (a, b) -> { a = a > 0 ? a : -1 * a; b = b > 0 ? b : -1 * b; return a + b; }; System.out.println("-5 ile 9 arasındaki uzaklık: " + mutlakMesafe.islemYap(-5, 9)); } } interface Matematik { int islemYap(int a, int b); }
Output:
3 x 5 = 15
-5 ile 9 arasındaki uzaklık: 14
- Eğer Lambda ifademiz bir dönüş değeri olacak ise ve tek işlem ile bu değeri döndürebildiğinizde “return” ifadesini kullanmanıza gerek yoktur.
public class LambdaEx4 { public static void main(String[] args) { // return gerektirmeyen lambda Math cikarma = (a, b) -> a - b; System.out.println("4 - 9 = " + cikarma.islemYap(4, 9)); // return gerektiren lambda Math farkinKaresi = (int a, int b) -> { int fark = (a - b) > 0 ? (a - b) : (b - a); return fark * fark; }; System.out.println("(5 - 1)^2 = " + farkinKaresi.islemYap(5, 1)); } } interface Math { int islemYap(int a, int b); }
Output:
4 – 9 = -5
(5 – 1)^2 = 16
- Default ve Static Metot
Java 8 ile Interface’lere default ve static metot özelliği eklenmiştir. Mevcut kodu etkilemeden yeni yöntemlere sahip olma yeteneği için default metot kavramı geliştirilmiştir. Default metot, “override” edilmediği sürece default metot içerisinde belirtilen işlemlerin yapılmasını sağlayan metot tanımıdır. Static metot ise “override” edilmez ve sadece Interface’in adı ile ulaşılabilir.
public class DefaultStaticMethod { public static void main(String[] args) { //static metot double pi = Utils.getPI(); System.out.println(pi); Utils utils = new Utils() { }; //default metodu kullanma utils.yazdir("Merhaba !!"); //default metodu override etme Utils utils2 = new Utils() { @Override public void yazdir(String message) { System.out.println("Override Default Method Message: " + message); } }; utils2.yazdir("Hello"); } } interface Utils { // Default metot default void yazdir(String message) { System.out.println(message); } // Static metot static double getPI() { return 3.14; } }
Output:
3.14
Merhaba !!
Override Default Method Message: Hello
- Fonksiyonel Interface (Arayüz)
İçerisinde bir adet soyut metot bulunan Interface’ler için kullanılan isimdir. En bilindik olan Comparable Interface’dir. İçerisinde sadece “compareTo” metodu bulunur. Comparable Interface genellikle nesne içeren koleksiyon ve map’lerin sıralamasında zorunlu koşulan bir interface’dir. Fonksiyonel Interface’ler default ve static metot bulundurabilir ancak en fazla bir adet soyut metot bulundurur. Java 8 içerisinde birçok fonksiyonel arayüz mevcuttur. Fonksiyonel Interface’ler genellikle lambda ifadeleri ile tanımlanırlar. Fonksiyonel Interface’ler tanımlanırken @FunctionalInteface tag’i kullanılmayabilir ama bu tag tanımlanırsa ilgili Interface’de tek soyut metot olmasını sağlar. İkinci soyut metot eklenince hata verir.
import java.util.Arrays; import java.util.List; import java.util.Objects; public class FunctionalInterfaceEx { public static void main(String args[]) { List<Integer> list = Arrays.asList(0, 1, -2, 3, 4, 5, 6, 7, 8, 9); // Cift sayılari yaz eval(list, n -> n % 2 == 0); } public static void eval(List<Integer> list, TestEt testEt) { for (Integer n : list) { // Ve sifirdan buyukse yaz if (testEt.ve(t -> t > 0).test(n)) { System.out.print(n + " "); } } } } interface TestEt { boolean test(Integer value); default TestEt ve(TestEt digerTest) { Objects.requireNonNull(digerTest); return (t) -> test(t) && digerTest.test(t); } }
Output:
4 6 8
- Metot Referansları
Metot referansları, bizi ‘::’ operatörünü ile tanıştırdı. Bu operatör bize metotlara sadece isimleriyle ulaşmamızı sağlar. Buradaki temel mantık, eğer referans edilecek metot, aldığı değerler ve döndüğü değer noktalarında eşleşiyorsa, ‘::’ operatörü kullanılabiliyor. Hangi metotlar referans olarak kullanılabilir dersek;
- Statik bir metot kullanılabilir,
import java.util.Arrays; import java.util.List; import java.util.Locale; public class MethodReferenceEx1 { static List<String> names = Arrays.asList("Hasan", "Cihan", "Dursun"); public static void main(String[] args){ // static metod kullanildi names.forEach(StringFunc::upper); } } class StringFunc { public static void upper(String s) { s = s.toUpperCase(Locale.forLanguageTag("tr")); System.out.println(s); } }
Output:
HASAN
CİHAN
DURSUN
- Nesnenin metotları kullanılabilir,
import java.util.Arrays; import java.util.List; import java.util.Locale; public class MethodReferenceEx2 { static List<String> names = Arrays.asList("Ümmühan", "Gamze", "Gülzada"); public static void main(String[] args){ StringFunct func = new StringFunct(); // static olmayan metod kullanildi names.forEach(func::lower); } } class StringFunct { public void lower(String s) { s = s.toLowerCase(Locale.forLanguageTag("tr")); System.out.println(s); } }
Output:
ümmühan
gamze
gülzada
- Yapıcılar (“Construcor”) new anahtarı sayesinde referans olarak kullanılabilir,
public class MethodReferenceEx3 { public static void main(String[] args) { Sumable sumable = Sum::new; sumable.getSum(-1); sumable.getSum(6); } } //constructor i kullanabilmek icin ayarlanmis fonsiyonel interface interface Sumable { Sum getSum(Integer val); } //constructor i kullanilacak sinif class Sum { public Sum(Integer value) { if (value > 0) System.out.println("Sumable Value: " + value); else { System.out.println("Not Sumable Value: " + value); } } }
Output:
Not Sumable Value: -1
Sumable Value: 6
- Optional Sınıfı
“Optional” sınıfı genel olarak yazılımcıların çok muzdarip olduğu “NullPointerException” hatasının kontrolü için yazılan “null” kontrolü metotlarına alternatif olarak sunulmuştur. “Guava” içerisindeki Optional sınıfı ile benzerlik göstermektedir.
import java.util.Optional; public class OptionalEx { public static void main(String args[]) { Integer val1 = null; Integer val2 = new Integer(10); //deger null olabilir Optional<Integer> a = Optional.ofNullable(val1); //deger null olursa hata firlat Optional<Integer> b = Optional.of(val2); //kontrol sonuclari yazdir System.out.println("a != null : " + a.isPresent()); System.out.println("b != null : " + b.isPresent()); //deger null ise -1 ata Integer value1 = a.orElse(new Integer(-1)); //optionaldaki degeri al Integer value2 = b.get(); System.out.println("sum = " + (value1 + value2)); } }
Output:
Not Sumable Value: -1
Sumable Value: 6
- Nashorn JavaScript
“Nashorn”, mevcut “Rhino” javascript motoru yerine kullanılmak üzere çok daha gelişmiş bir javascript motoru olarak tanıtıldı. Nashorn, kodu doğrudan bellekte derlediği ve bayt kodunu JVM’ye ilettiği için 2 ila 10 kat daha iyi performans sağlar.
import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class Nashorn { public static void main(String args[]) { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn"); String name = "Murat"; Integer result = null; try { nashorn.eval("print('" + name + "')"); result = (Integer) nashorn.eval("4 * 31"); System.out.println(result.toString()); } catch (ScriptException e) { System.err.println("Error executing script: " + e.getMessage()); } } }
Output:
Murat
124
- Yeni Date/Time API
Java 8’den önce kullanılan “Date” ve “Time” sınıfına alternatif olarak sunulmuş API’lerdir. “Date” ve “Time” sınıfına alternatif aranmasının temel sebebinin,bu sınıfların daha önce “thread safe” olmamaları idi diyebilirim. Saat dilimi yönetmek ve bazı tarih işlemlerini gerçekleştirmek pek kolay yapılamıyordu.
Java 8 ile gelen “Date” ve “Time” API sınıfları şöyledir;
LocalDate:
LocalDate setDate = LocalDate.of(2017, Month.MARCH, 6); LocalDate nowDate = LocalDate.now(); System.out.println("setDate: " + setDate); System.out.println("nowDate: " + nowDate);
Output:
setDate: 2017-03-06
nowDate: 2019-04-07
LocalTime:
LocalTime sampleTime = LocalTime.of(22, 15); LocalTime nowTime = LocalTime.now(); System.out.println("sampleTime: " + sampleTime); System.out.println("nowTime: " + nowTime);
Output:
sampleTime: 22:15
nowTime: 14:24:43.514
LocalDateTime:
LocalDateTime currentTime = LocalDateTime.now(); System.out.println("Current DateTime: " + currentTime);
Output:
Current DateTime: 2019-05-06T14:42:24.388
ZonedDateTime:
ZonedDateTime sampleZoneDateTime = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]"); System.out.println("sampleZoneDateTime: " + sampleZoneDateTime); ZonedDateTime nowZoneDateTime = ZonedDateTime.now(); System.out.println("nowZoneDateTime: " + nowZoneDateTime); ZoneId id = ZoneId.of("Europe/Paris"); System.out.println("ZoneId: " + id); ZoneId currentZone = ZoneId.systemDefault(); System.out.println("CurrentZone: " + currentZone);
Output:
sampleZoneDateTime: 2007-12-03T10:15:30+05:00[Asia/Karachi]
nowZoneDateTime: 2019-04-07T14:28:24.631+03:00[Asia/Istanbul]
ZoneId: Europe/Paris
CurrentZone: Asia/Istanbul
Period:
//suan LocalDate date1 = LocalDate.now(); //bir ay ileri al ve yaz LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS); System.out.println("Next month: " + date2); //periyodu bul Period period = Period.between(date2, date1); System.out.println("Period: " + period);
Output:
Next month: 2019-05-07
Period: P-1M
Duration:
//suan LocalTime time1 = LocalTime.now(); //2 saat ileri LocalTime time2 = time1.plus(2, ChronoUnit.HOURS); Duration duration = Duration.between(time1, time2); //sureyi bul System.out.println("Duration: " + duration);
Output:
Duration: PT2H
Clock:
Clock clock = Clock.systemDefaultZone(); Clock clock1 = Clock.offset(clock, Duration.ofHours(5)); System.out.println("5 saat ileri " + clock1.instant()); Clock clock2 = Clock.offset(clock, Duration.ZERO); System.out.println("suan " + clock2.instant()); Clock clock3 = Clock.offset(clock, Duration.ofHours(-10)); System.out.println("10 saat geri " + clock3.instant());
Output:
5 saat ileri2019-04-07T16:43:04.865Z
suan 2019-04-07T11:43:04.876Z
10 saat geri 2019-04-07T01:43:04.876Z
TemporalAdjusters:
LocalDate date1 = LocalDate.now(); System.out.println("suan: " + date1); LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY)); System.out.println("ilk Sali : " + nextTuesday); LocalDate firstInYear = LocalDate.of(date1.getYear(), date1.getMonth(), 1); LocalDate secondSaturday = firstInYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)).with(TemporalAdjusters.next(DayOfWeek.SATURDAY)); System.out.println("ikinci Cumartesi : " + secondSaturday);
Output:
suan: 2019-04-07
ilk Sali : 2019-04-09
ikinci Cumartesi : 2019-04-13
- Stream API
Stream API’yi genel olarak, toplu işlemler için kullanılan, bir kaynaktan gelen nesne dizisi olarak tanımlayabiliriz.
Stream API’sinin genel özellikleri olarak şunları diyebiliriz;
- Yapılan işlem üzerine kaynağı alır ve işlemi yapar. Kaynağı saklamaz.
- Kaynak olarak diziler, koleksiyonlar ve I/O kaynaklarını destekler.
- Stream API “foreach”, “limit”, “find”, “filter”, “match” vb. listenin tümünde işlem yapılması gereken işlemleri destekler.
- Stream API’de çoğu işlem Stream’in kendisini döndürür. Böylece sonuçlar üzerinde tekrar işlem yapılıp aktarılabilir hale gelir. Bu işlemlere ara işlemler de denir. İşlevleri kaynağı almak, işlemek ve sonucu döndürmektir. “collect()” yöntemi, Stream’in çıktısını belirlemek için en sona yazılan işlemdir. Genelde Collectors ile beraber kullanılır.
- Stream API döngüleri, sağlanan kaynak öğelerin iteratörleri üzerinden dahili olarak gerçekleştirir.
Ardışık (“stream()”) ve paralel (“parallelStream()”) olmak üzere 2 farklı şekilde Stream çevrimi vardır.
Stream API de çok kullanılan fonksiyonlara örnek verecek olursak;
foreach:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class StreamApiEx1 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.addAll(Arrays.asList("AaD", "BbCd", "intELLIJ", "QweRTy", "EclipSE")); //dizideki stringleri kucult list.stream().forEach(item -> System.out.print(item.toLowerCase() + " ")); } }
Output:
aad bbcd intellij qwerty eclipse
map:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamApiEx2 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.addAll(Arrays.asList(-1, 1, 2, 4, 6, 8)); //dizideki degerlerin kupunu al ve yaz list = list.stream().map(item -> item * item * item).collect(Collectors.toList()); list.forEach(item -> System.out.print(item + " ")); } }
Output:
-1 1 8 64 216 512
filter:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamApiEx3 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); //cift sayilari bul list = list.stream().filter(item -> item % 2 == 0).collect(Collectors.toList()); list.forEach(s -> System.out.print(s + " ")); } }
Output:
0 2 4 6 8 10
limit:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamApiEx4 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.addAll(Arrays.asList(9, 1, 5, 3, 4, 2, 6, 7, 8, 0, 10)); // ilk 5 eleman icindeki tek sayilari bul list = list.stream().limit(5).filter(item -> item % 2 == 1).collect(Collectors.toList()); list.forEach(System.out::print); } }
Output:
9153
sorted:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamApiEx5 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.addAll(Arrays.asList("za-", "az-", "dz+", "yp+")); //sirala list = list.stream().sorted().collect(Collectors.toList()); list.forEach(System.out::print); } }
Output:
az-dz+yp+za-
match:
import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class StreamApiEx6 { public static void main(String[] args) { Predicate<String> p1 = s -> s.startsWith("S"); Predicate<String> p2 = s -> s.length() < 4; Predicate<String> p3 = s -> s.endsWith("z"); List<String> list = Arrays.asList("Logan", "Magneto", "Rogue", "Storm"); // herhangi biri S ile baslıyor mu? boolean b3 = list.stream().anyMatch(p1); System.out.println(b3); // hepsinin uzunlugu 4 ten kucuk mu? boolean b4 = list.stream().allMatch(p2); System.out.println(b4); // hicbiride z ile bitmez dogru mu? boolean b5 = list.stream().noneMatch(p3); System.out.println(b5); } }
Output:
true
false
true
**** Not: Predicate java.util.function paketi altındaki bir fonksiyonel Interface’dir ve tek soyut metodu testtir.
find:
import java.util.Arrays; import java.util.List; public class StreamApiEx7 { public static void main(String[] args) { List<String> list = Arrays.asList("Rogue", "Magneto", "Logan", "Storme"); //herhangi e ile biten deger String f1 = list.stream().filter(s -> s.endsWith("e")).findAny().get(); System.out.println(f1); // ilk a iceren deger String f2 = list.stream().filter(s -> s.contains("a")).findFirst().get(); System.out.println(f2); } }
Output:
Rogue
Magneto
- Java Ondalık Gösterimi ve Exception Handling
Java 8’de “try” – “catch” – “finally” kullanımında yeni bir düzenleme yapıldı. Finally’de socket veya scanner gibi kapatma işlemi gerektiren işlemlerde Java 8 bunu kendi otomatik olarak halledilebiliyor.
Örnek:
/*Java 7*/ Scanner scanner = null; try { scanner = new Scanner(new File("test.txt")); while (scanner.hasNext()) { System.out.println(scanner.nextLine()); } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (scanner != null) { scanner.close(); } } /*Java 8*/ try (Scanner scanner = new Scanner(new File("test.txt"))) { while (scanner.hasNext()) { System.out.println(scanner.nextLine()); } } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); }
Java 8’de büyük rakam tanımlamalarında gösterim açısından kolaylık olması için ‘_’ işareti ile ayrım yapabiliyoruz. Bu işaretin sayının değeri ile ilgili bir müdahalesi olmuyor sadece daha anlaşılır gösterimi sağlıyor. Örnek:
Integer sayi = 3_536_456; Double değer = 3.149_58_98_00;
Evet arkadaşlar maalesef yazımızın sonuna geldik.☹ Sizin için elimden geldiğince her konuya değinmeye çalıştım. Eğer Java 8’e henüz geçmediyseniz, mutlaka geçmenizi öneririm. Geçtiyseniz, çevrenizi de yönlendireceğinize eminim. 😊
Yazımı, naçizane tavsiyelerimi paylaşarak sonlandırmak isterim.
- Öncelike java.util.function paketi altındaki fonksiyonel interface’lere bakmanızı tavsiye ederim.
- “new Date()”i yavaş yavaş elinizden bırakın ve “LocalDatetime” veya “LocalDate” sınıflarına teslim olun. 😊
- Java’dan asla vazgeçmeyin.
İyi çalışmalar arkadaşlar..
Hasan Dayan
Yazılım Geliştirme Uzmanı
Github linki:
https://github.com/egem-github/egemsoftBlog/tree/master/Java8Features/src/com/egemsoft
Kaynaklar:
https://en.wikipedia.org/wiki/Java_version_history
https://github.com/AlicanAkkus/java8
https://www.tutorialspoint.com/java8/java8_overview.htm
https://www.javatpoint.com/java-8-method-reference
http://devnot.com/2017/java-8-hakkinda-bilmeniz-gerekenler/