You are on page 1of 111

Java 8 Ebook

Rahman Usta

indekiler
nsz ......................................................................................................................... xi
1. Lambda Expression nedir? Nasl kullanrm? ............................................................. 1
1.1. Lambda nedir? .............................................................................................. 1
1.2. Javascript ile Lambda Basit Giri ................................................................ 1
1.3. Lambda Java 8 ncesinde nasld? ................................................................ 2
1.4. Java 8 ve Lambda ifadeleri ............................................................................ 3
2. Lambda ifadeleri ve Fonksiyonel arayzler ................................................................ 5
2.1. Functional Interfaces ..................................................................................... 5
3. Tarih ve Saat ilemleri ............................................................................................. 9
3.1. LocalDate ..................................................................................................... 9
3.2. LocalTime ................................................................................................... 10
3.3. LocalDateTime ............................................................................................ 11
3.4. ZoneId ........................................................................................................ 12
3.5. ZonedDateTime ........................................................................................... 13
4. Consumer Arayz ................................................................................................. 15
4.1. Java 8 ncesi .............................................................................................
4.2. Java 8 sonras ............................................................................................
4.3. Lambda deyimleri aklldr ............................................................................
4.4. Consumer arayz nerede kullanlyor? ........................................................
4.5. Lambda deyimlerini Metod Referanslar ile kullanabiliriz. ................................
5. Lambda rnekleri ...................................................................................................
5.1. Consumer Arayz ......................................................................................
5.2. BiConsumer Arayz ...................................................................................
5.3. Function Arayz ........................................................................................
5.4. UnaryOperator Arayz ...............................................................................
5.5. BiFunction Arayz .....................................................................................
5.6. BinaryOperator Arayz ...............................................................................
5.7. Predicate Arayz .......................................................................................
5.8. BiPredicate Arayz ....................................................................................
5.9. Supplier Arayz .........................................................................................
6. Notasyonlar ve Tekrarl Notasyonlar ........................................................................
6.1. Notasyonlar ve Alanlar ................................................................................

15
16
16
17
17
19
19
19
20
20
21
21
21
22
22
25
27

6.2. Notasyonlara Eriim .....................................................................................


6.3. Notasyonlarn Tekrarl Kullanlmas ...............................................................
7. Method Reference ..................................................................................................
7.1. Bir metodu referans vermek .........................................................................

28
29
31
32

iii

Java 8 Ebook

8. Default Methods .....................................................................................................


8.1. Varsaylan Metoda Giri ...............................................................................
8.2. Varsaylan metodlarda akma ....................................................................
8.3. Varsaylan metodlar ve Fonksiyonel arayzler ...............................................
8.4. Varsaylan metodlar ve JDK .........................................................................
9. Stream API ............................................................................................................
9.1. Stream nesnesi nasl elde edilir? ..................................................................
9.1.1. Collection API ile ..............................................................................

37
37
39
41
42
45
46
46

9.1.2. New I/O ile .......................................................................................


9.1.3. IntStream, DoubleStream, LongStream ile ..........................................
9.2. Stream API rnekleri ...................................................................................
9.2.1. forEach ............................................................................................
9.2.2. filter .................................................................................................
9.2.3. distinct .............................................................................................
9.2.4. sorted ..............................................................................................
9.2.5. limit ..................................................................................................
9.2.6. count ................................................................................................
9.2.7. collect ..............................................................................................
9.2.8. map .................................................................................................
9.2.9. reduce ..............................................................................................
9.2.10. map & reduce .................................................................................
9.3. Parallel Stream ...........................................................................................
9.4. Lazy & Eager operasyonlar ..........................................................................
10. Java 8 ve JVM Dilleri ...........................................................................................
10.1. JVM Dilleri ................................................................................................
10.2. Java Scripting API .....................................................................................
10.3. ScriptEngine ..............................................................................................
10.4. Nashorn JavaScript Motoru ........................................................................
11. Java 8 Optional Yenilii ........................................................................................
11.1. Optional Oluturmak ..................................................................................
11.2. #ifPresent - Varsa yap, yoksa yapma ..........................................................
11.3. #map - Dntrme ...................................................................................
11.4. #filter - Filtreleme ......................................................................................
11.5. #orElse - Varsa al, yoksa bunu al ...............................................................

47
48
48
48
49
49
50
50
50
51
52
53
54
56
57
59
59
61
61
62
63
63
64
65
65
65

11.6. #orElseGet - Varsa al, yoksa ret ...............................................................


11.7. #orElseThrow - Varsa al, yoksa frlat ..........................................................
12. Java 8 Embedded ................................................................................................
12.1. JavaFX Extension ......................................................................................

66
66
69
71

iv

Java 8 Ebook

12.2. Nashorn Extension .................................................................................... 72


12.3. Java 8 ME vs Java 8 Embedded ................................................................ 72
13. CompletableFuture ile Asenkron Programlama ....................................................... 75
13.1. Syncronous vs. Asyncronous ..................................................................... 75
13.2. CompletableFuture#allOf ............................................................................ 77
13.3. CompletableFuture#anyOf .......................................................................... 78
13.4. CompletableFuture#supplyAsync ................................................................ 79
13.5. lk yol, join() metodu kullanmak............................................................ 80
13.6. kinci yol, thenAccept* metodu kullanmak.............................................. 81
13.7. CompletableFuture#runAfterBoth* ............................................................... 81
13.8. CompletableFuture#runAfterEither* ............................................................. 82
13.9. CompletableFuture#handle* ....................................................................... 82
14. Java ME 8 Embedded ve Raspberry PI ................................................................. 85
14.1. Java ME 8 ile Raspberry PI zerinde LED yakma ........................................ 86
14.2. Donanmsal Gereksinimler ......................................................................... 86
14.2.1. Raspberry PI .................................................................................. 86
14.2.2. Bread Board ................................................................................... 86
14.2.3. SD Kart .......................................................................................... 87
14.2.4. Adaptr .......................................................................................... 87
14.2.5. Wifi adapter .................................................................................... 87
14.2.6. Kablo, Led, GPIO Extension Board .................................................. 88
14.2.7. HDMI Kablosu ................................................................................ 89
14.2.8. Klavye ve Maus .............................................................................. 89
14.3. Yazlmsal Gereksinimler ............................................................................ 89
14.4. Raspbian OS Kurulmas ............................................................................. 91
14.4.1. Devrenin Kurulmas ......................................................................... 91
14.5. Java ME 8in Raspberry PIye Yklenmesi .................................................. 93
14.6. Java MEnin altrlmas .......................................................................... 95
14.7. Device Managera Rapberry PI Tantmak .................................................... 95
14.8. Java ME 8 Embedded Projesinin Oluturulmas ........................................... 97
14.8.1. Adm 1 ........................................................................................... 97
14.8.2. Adm 2 ........................................................................................... 98
14.8.3. Adm 3 ........................................................................................... 98
14.9. Uygulamann Yazlmas ............................................................................. 99
14.10. Projeye Aygt Tantmak .........................................................................
14.11. Uygulama zinlerini Tanmlamak ..............................................................
14.12. Uygulamann altrlmas .....................................................................
A. Bu kitap nasl yazld? ..........................................................................................

101
102
103
105

nsz
Java 8 ve yeniliklerini ieren bu kitap ile, Java programlama dilinin en yeni zelliklerini
renebilirsiniz.
Java 8 Ebook kodcu.com
iermektedir.

'da Rahman Usta

tarafndan kaleme alnan Java 8 yazlarn

1
http://kodcu.com
2
http://kodcu.com/author/rahmanusta/

xi

Blm 1. Lambda Expression nedir?


Nasl kullanrm?
Merhaba arkadalar;
Bugn sizlerle Java 8 (Project Lambda) ile Java ortamna katlan Lambda ifadelerinden
(Lambda expression) bahsetmek istiyorum.

1.1. Lambda nedir?


Programlama dili erevesinde Lambda, anonim tekil grevler olarak deerlendirilebilir.
Lambda deyimleri (Lambda fonksiyonlar da denebilir), referans verilebilir ve tekrar tekrar
kullanlabilirdir. Genel kullanm asndan Lambda fonksiyonlar, dier bir fonksiyona argman
olarak iletilebilirdir. Bylece, bir tarafta tanmlanan i birimi, dier bir i biriminde koturulabilir
olmaktadr. Burada dikkat ekilecek unsur, bir i biriminin dier bir uygulama birimine referans
olarak eritirilebilirliidir.

1.2. Javascript ile Lambda Basit Giri


Javascript dilinde Array snfnn prototype alannda forEach isimli bir i birimi (fonksiyon)
bulunmaktadr. forEach fonksiyonu, parametre olarak bir anonim Javascript fonksiyonunu
kabul etmektedir. forEach fonksiyonuna, parametre olarak tanmlanan anonim fonksiyon,
forEach fonksiyonu ierisinde koturulmaktadr. Bu sayede i mant, dier fonksiyona
paslanm olmaktadr.
rnek 1:
var dizi = [1,2,3,4,5]; // Bir javascript dizisi
// Anonim fonksiyon her bir eleman ktlyor.
dizi.forEach(function(e){ //

(1)

console.log("Eleman: ",e);
});

Yukarda (1) numaral ksmdaki anonim fonksiyon yani lambda fonksiyonu, forEach
metodu ierisinde koturulmaktadr. forEach metodu ierisindeki benzer yaklam, kendi
fonksiyonumuz ile oluturalm.

Lambda Java 8
ncesinde nasld?
var fonk= function(a,b,callback){
// Lambda fonksiyonu "callback" burada koturulur.
return callback(a,b)*2; //

(2)

}
var result = fonk(2,3,function(a,b){ // (1)
// Bu Lambda fonksiyonu 2 argman toplar.
return a+b;
});
console.log("Sonu ..: ",result); // Sonu : (2+3)*2 = 10

Tekrar ederek, Lambda fonksiyonlar iin referans verilebilir i birimleri denebilir. Bu yaklam
bir ok programlama dilinde farkl biimlerde yer alabilir, anlalabilirlik asndan ilk nce
Javascript rnei vermeyi tercih ettim.

1.3. Lambda Java 8 ncesinde nasld?


Lambda birimleri (referans verilebilir i birimleri), Java 8 evvelinde anonim snflar ile
tanmlanabilmekteydi. rnek 2nin benzeri Java 8 evvelinde nasl yazlyordu?
ncelikle bir i birimi tipi gerekli, bu i birimi 2 argman kabul etmeli ve bir deer dndrmelidir.
mant anonim olarak tanmlanaca iin, abstract snflar veya arayzler kullanlabilir.
rnek 3
public interface Anonim{
public int call(int a, int b);
}

Anonim arayz szlemesi, int trnden 2 deer alr ve bir int deer dndrr. Dikkat
ederseniz sadece szlemenin maddesi tanmland, i mant anonim olarak gelitirici
tarafndan tanmlanacak.
public class LambdaApp {
public static void main(String[] args) {
LambdaApp app = new LambdaApp();
// rnek 2 (1) gibi
app.fonk(2, 3, new Anonim() {

Java 8 ve Lambda ifadeleri

@Override
public int call(int a, int b) {
return a + b;
}
});
}
// rnek 2 (2) gibi
public int fonk(int a, int b, Anonim anonim) {
return anonim.call(a, b) * 2;
};

Anonim i birimi burada tanmlanyor


Anonim i birimi burada koturuluyor

1.4. Java 8 ve Lambda ifadeleri


LambdaApp snfnn (1) numaral ksmndaki anonim i birimi, Javascript dilindeki karlna
gre u anda ok daha kompleks. 6 komut satr yer igal ediyor. Fakat bu fonksiyonun yapt
tek i var, 2 argman almak ve toplayp geri dndrmek. Bu anonim birimi sanyorum u
biimde temsil edebiliriz.
fn(a,b) -> (a+b);

Grld zere tek bir satrda ayn ii gren anonim i birimini yani lambda ifadesini yazdk.
Ayn rnei imdi Java 8 Lambda deyimi ile yazalm.
public interface Anonim{
public int call(int a, int b);
}
public class LambdaAppJava8 {
public int fonk(int a, int b, Anonim anonim) {
return anonim.call(a, b) * 2;
};
public static void main(String[] args) {

Java 8 ve Lambda ifadeleri

LambdaAppJava8 app = new LambdaAppJava8();


app.fonk(2, 3, (a, b) -> a + b); // Dikkat (1)
}
}

Grld zere 6 satrlk anonim snf kullanmn, tek satra drm olduk.
1

Lambda ifadeleri, Java 8 versiyonunun en arpc yeniliklerinden biri. (Bkz. Project Lambda ).
Sizler de Java 8 kullanmak istiyorsanz https://jdk8.java.net/ adresinden sisteminize
kurabilirsiniz.
Bol Javal gnler dilerim.

http://openjdk.java.net/projects/lambda/

Blm 2. Lambda ifadeleri ve


Fonksiyonel arayzler
Merhaba arkadalar;
Bugn sizlerle fonksiyonel arayzlerden ( Functional Interfaces ) ve Lambda ifadeleri
(Lambda Expressions) ile olan ilikisinden basetmek istiyorum.

2.1. Functional Interfaces


Tek bir soyut metodu bulunan arayzlere fonksiyonel arayz denir. ki veya deil,
yalnzca bir tane soyut metodu olmal. Peki neden 1 dersek sebebinin Lambda ifadelerine
dayandn sylemek isterim.
rnein;
yle bir Lambda ifademiz olsun;
fn(x,y) -> 2*x + y

Bu Labmda deyimini rnein Javascript gibi bir dil ile temsil etmek isteseydik yle yazabilirdik;
function(x , y) {
return 2*x+y;
}

Peki fn(x,y) 2*x + y Lambda ifadesini Java programlama dilinde nasl yazabiliriz?
Java 8 gelitirilirken, gelitirim takm kendilerine bu soruyu sormu ve yant olarak fonksiyonel
arayzler kullanarak ihtiyac karlamlar.
yle ki; Bir Lambda ifadesi, Java derleyicisi tarafndan, bir Java arayznn (tek bir soyut
metodu olmal) nesnel karlna (implementation) dntrlmektedir.
rnein, fn(x,y) 2*x + y Lambda ifadesi, aadaki fonksiyonel arayze
dntrlebilirdir. nk fonksiyon x ve y adnda iki parametre almakta ve 2*x + y ile tek bir

Functional Interfaces

deer dndrmektedir. Tabi burada x ve y nin tipleri ne? dersek, herhangi bir matematiksel
tip olabilir. Biz burada sabit bir tip (int gibi) verebilir, veya jenerik tiplemeler de yapabiliriz. Fakat
u anlk bununla yetinelim.
@FunctionalInterface // Opsiyonel
interface Foo{
int apply(int x, int y);
}

imdi bu Lamda ifadesini uygulamamzda kullanalm.


rnek 1:
Lambda ifadeleri atama srasnda kullanlabilir.
Foo foo = (x,y) -> (2*x+y);
int sonuc = foo.apply(3,4);
System.out.println("Sonu: "+sonuc); // kt: 10
// veya
Foo foo = (x, y) -> Math.pow(x,y);
int sonuc = foo.apply(3,2);
System.out.println("Sonu: "+sonuc); // kt: 3*3 = 9

rnek 2:
Lambda ifadeleri, metod parametrelerinde de tanmlanabilir.
class Bar{
public int calculate(Foo foo, int x, int y){
return foo.apply(x,y);
}
}
Bar bar = new Bar();

Functional Interfaces

int sonuc = bar.calculate( (x,y) -> (2*x+y) , 3, 4 );


System.out.println("Sonu: "+sonuc); // kt: 10

Java programlama dilinde fonksiyon ifadesi pek kullanlmaz, onun yerine metod ifadesi
kullanlr. Java metodlar tek bana birer eleman deildir, dier bir dil elemannn (snf,
enum, interface ..) dahilinde tanmlanrlar. Javascript gibi dillerde ise fonksiyonlar tek bana
birer elemandr, dier bir dil elemannn iinde olmak zorunluluu yoktur. Bu sebeple
Java ortamnda, bir Lambda ifadesinden bir fonksiyona/metoda/i birimine dnm iin
fonksiyonel arayzler kullanlmaktadr.
Tekrar grmek dileiyle..

Blm 3. Tarih ve Saat ilemleri


Java 8 ierisinde zaman temsili iin yeni bir Date-Time API gelitirildi. Java programlama
dilinde zamansal ilemler iin JSR 310: Date and Time API artnamesi yer almaktadr. Java 8
ile birlikte yeniden dzenlenen bu artname, yepyeni zellikler sunmaktadr. Yeni gelitirilen
Date-Time APInin referans implementr ThreeTen projesidir.
Yeni Date-Time API ile kolay kullanm, anlalrlk, thread-safety gibi hususlarda iyiletirmeler
karmza kyor. Bu yeni API ye dair bileenler (snf, arayz, enum vs.) java.time paketi
altnda yer almaktadr. imdi sizlerle java.time paketi ierisinde yer alan bileenler ile ilgili
kolay anlalr rnekler paylamak istiyorum.
java.time paketindeki snflarn genel olarak kurucu metodu private eriim belirleyicisine
sahiptir, bu sebeple new anahtar ifadesiyle oluturulamazlar. Onun yerine now, of , from, parse
gibi metodlarla yeni nesneler oluturulabilmektedir. java.time paketi ierisindeki zamansal
snflar immutable dir. Bu sebeple bir nesne oluturulduktan sonra ierisindeki veriler kesinlikle
dzenlenemezler. Bu da mevcut snflar thread-safety hale getirmektedir. ( Bkz. Thread safety
& immutability). Bu yazmzda LocalDate , LocalTime , LocalDateTime , ZoneId ve
ZonedDateTime snflarnn kullanmn irdeleyeceiz.

3.1. LocalDate
LocalDate snf ile tarihsel zaman temsil edilir. rnein: 10/10/2010 tarihini LocalDate
ile temsil edebiliriz.
rnekler
"of" metodu ile LocalDate nesnesi oluturulabilir.
LocalDate.of(1988, 07, 16); // 1988-07-16
LocalDate.of(1988, Month.JULY, 16) // 1988-07-16 (Month enum)

"now" metodu ile o ann tarihi elde edilir.


LocalDate now = LocalDate.now(); // 2014-04-05

"with*" metodu ile eldeki bir LocalDate iin gn, ay, yl alanlar dzenlenebilir. LocalDate
snf immutable dir. Bu sebeple with metodu farkl bir LocalDate nesne dndrr. O anki
nesneyi dzenlemez.

LocalTime

LocalDate now = LocalDate.now(); // 2014-04-05


now.withYear(2016); // 2016-04-05
now.withMonth(8).withDayOfMonth(17); // 2014-08-17
now
.with(ChronoField.YEAR, 2012)
.with(ChronoField.MONTH_OF_YEAR, 8)
.with(ChronoField.DAY_OF_MONTH,3); // 2012-08-03

"plus*" metodu ile eldeki bir LocalDate iin gn, ay, yl alanlar artrlabilir. LocalDate snf
immutabledir. Bu sebeple plus metodu farkl bir LocalDate nesne dndrr. O anki nesneyi
dzenlemez.
now
.plusWeeks(2)
.plusDays(3)
.plusYears(3)
.plusDays(7); //
now
.plus(2, ChronoUnit.WEEKS)
.plus(3, ChronoUnit.YEARS)
.plus(3, ChronoUnit.DECADES); //

"minus*" metodu ile eldeki bir LocalDate iin gn , ay , yl alanlar azaltlabilir.


LocalDate snf immutabledir. Bu sebeple minus metodu farkl bir LocalDate nesne
dndrr. O anki nesneyi dzenlemez.
now.minusDays(5).minusMonths(2); //
now
.minus(2, ChronoUnit.WEEKS)
.minus(3, ChronoUnit.YEARS)
.minus(33, ChronoUnit.DAYS); //

3.2. LocalTime
LocalTime snf ile saatsel zaman temsil edilir. rnein: 20:11 , 18:15:55 saatlerini
LocalTime ile temsil edebiliriz. LocalTime ile saat, dakika, saniye, salise temsil edilebilir.
rnekler

10

LocalDateTime

LocalTime now= LocalTime.now();


LocalTime time= LocalTime.of(18, 20, 55); // 18:20:55
time.getHour(); // 18
time.getMinute(); // 20
time.getSecond(); // 55
LocalTime.NOON; // 12:00
LocalTime.MIDNIGHT; // 00:00
LocalTime.parse("10:05"); // 10:05
time
.plusSeconds(45)
.minusSeconds(5)
.minus(5, ChronoUnit.SECONDS); // 18:20:35

3.3. LocalDateTime
LocalDateTime snf ile hem tarihsel hem saatsel zaman temsil edilir. rnein: 10/10/2010
15:22:33 zamann LocalDateTime ile snfsal olarak temsil edebiliriz.
rnekler
LocalDateTime now = LocalDateTime.now();
LocalDateTime dateTime =
LocalDateTime.of(2014, Month.JANUARY, 3, 4, 5, 45);
dateTime.getYear(); // 2014
dateTime.getMonth(); // JANUARY
dateTime.getDayOfMonth(); // 3
dateTime.getHour(); // 4
dateTime.getMinute(); // 5
dateTime.getSecond(); // 45
// LocalDateTime2LocalDate ve LocalDateTime2LocalTime
LocalDate date = dateTime.toLocalDate();
LocalTime time = dateTime.toLocalTime();
dateTime
.minusDays(3)
.plusYears(3)
.plusMinutes(3)

11

ZoneId

.minusWeeks(5)
.plusSeconds(2)
.plus(3, ChronoUnit.DECADES)
.minus(3, ChronoUnit.DECADES);

3.4. ZoneId
ZoneId snf, dnya zerindeki saat dilimlerinin Java tarafl nesnel karln temsil iin
oluturulan yeni bir Java 8 bileenidir.
Java 8 iin tm saat dilimlerinin listelenmesi iin ZoneId snfnn getAvailableZoneIds
metodu kullanlabilmektedir. rnein aadaki kod, tm saat dilimlerini sral olarak
listelemektedir.
Set<String> zones = ZoneId.getAvailableZoneIds();
zones.stream().sorted().forEach(System.out::println);

Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa

America/Argentina/Tucuman
America/Argentina/Ushuaia
America/Aruba
America/Asuncion

Asia/Istanbul
Asia/Jakarta
Asia/Jayapura

Etc/GMT+12
Etc/GMT+2
Etc/GMT+3

Europe/Isle_of_Man
Europe/Istanbul
Europe/Jersey

O anki allan makinadaki saat dilimi iin ZoneId snfnn systemDefault metodu
kullanlabilir.

12

ZonedDateTime

ZoneId.systemDefault(); // Europe/Athens

JVM varsaylan saat dilimini mevcut iletim sistemi zerinden almaktadr. Eer istenirse
mevcut Java sanal makinesinin varsaylan saat dilimi -Duser.timezone=<Time Zone>
ifadesiyle dzenlenebilmektedir.
-Duser.timezone=Europe/Istanbul

gibi.

3.5. ZonedDateTime
ZonedDateTime snf aslnda saat dilimi kattrlm LocalDateTime snfdr desek yeridir.
LocalDateTime snfndan fark genel olarak temsil ettii zaman saat dilimi ierir olarak
sunmasdr.
rnekler
ZonedDateTime.now();
/* 2014-04-05T16:33:16.320+03:00[Europe/Athens] */
ZoneId istanbul = ZoneId.of("Europe/Istanbul");
ZonedDateTime.now(istanbul);
// 2014-04-05T16:33:16.330+03:00[Europe/Istanbul]
// Japonyada tarih/saat ka?
ZonedDateTime.now(ZoneId.of("Japan"));
// 2014-04-05T22:33:16.331+09:00[Japan]

Bir ZonedDateTime nesnesi LocalDateTime ,


karlklarna dntrlebilmektedir.

LocalDate

ve

LocalTime

LocalDateTime localDateTime = japan.toLocalDateTime();


/* 2014-04-05T22:33:16.331 */
LocalDate localDate = japan.toLocalDate(); // 2014-04-05
LocalTime localTime = japan.toLocalTime(); // 22:33:16.331

Kaynaklar
[1] http://www.threeten.org/ [2] http://java.dzone.com/articles/introducing-new-date-and-time
[3] http://docs.oracle.com/javase/tutorial/datetime/index.html

13

ZonedDateTime

Tekrar grmek dileiyle..

14

Blm 4. Consumer Arayz


Daha nceki yazlarmzda Lambda ifadelerinden ve Fonskiyonel arayzlerden bahsetmitik.
imdi ise, java.util.function paketi altnda yer alan ve gml olarak bulunan
fonksiyonel arayzlere deineceiz.
java.util.function paketi altnda, farkl amalar iin bulunan hazr arayzler bulunmaktadr.
Java 8 ierisinde Lambda deyimlerinin kullanlabilir klnmasnda, java.util.function paketi
1
altndaki arayzler kullanlmaktadr. Bu fonksiyonel arayzlere java.util.function adresinden
grebilirsiniz.
Bu
yazmzda
ise,
fonksiyonel
arayzlere
giri
dncesiyle
java.util.function.Consumer arayznden ve nasl kullanldndan bahsedeceiz.
Consumer arayz accept isimli tek bir metoda sahiptir. Bu fonksiyonun bulunu amac,
tketim operasyonlarnda kullanlmasdr. Tketimden kast edilen ise, metoda girdi olmas
fakat kt olmamasdr. Metod girdisinin tipi ise jenerik olarak T harfi ile temsil edilmitir. T
yerine, istee gre herhangi bir Java tipi gelebilir. Biz String tipini kullanacaz.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}

Consumer arayz, yukarda grld zere bir fonksiyonel arayzdr. Bir arayzn,
fonksiyonel olarak nitelenebilmesi iin, tek bir soyut metoda sahip olma art vardr. Zaten bu
sayede, fonksiyonel arayzler Lambda deyimlerine yknebilmektedirler.

4.1. Java 8 ncesi


Java 8 ncesine gre Consumer arayz trnden bir nesneyi anonim bir snf ile oluturulm.
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String msg) {
System.out.println(msg);
1

http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

15

Java 8 sonras

}
};
consumer.accept("Merhaba Dnya");

Grld zere bir anonim snf oluturduk ve accept metodunu tkettik.

4.2. Java 8 sonras


Java 8 sonras iin anonim fonksiyonlar yerine Lambda deyimlerini kullanabilmekteyiz.
rnein yukardaki anonim snf aadaki yer alan Lambda deyimi ile yer deitirebiliriz.
Consumer<String> consumer = (String msg) -> {
System.out.println(msg);
};
consumer.accept("Merhaba Dnya");

Lambda deyimlerinde odaklanmas gereken nokta, fonksiyonel arayzn tek metodunun sahip
olduu metod girdi tipi, says,sras ve metod kt tipidir. Bu sayede kod satr olarak tasaruf
edilmektedir.

4.3. Lambda deyimleri aklldr


Lambda fonksiyonlarnda tanmlanan metod girdi tanmlamalarnda, istenirse tip
tanmlamasndan feragat edilebilir. Yani yukardaki Lambda deyimini aadaki gibi yazabiliriz.
Consumer<String> consumer = (msg) -> {
System.out.println(msg);
};
consumer.accept("Merhaba Dnya");

Grld gibi, (String msg) tanmlamasn (msg) yapabildik. Sol tarafta zaten String tip bilgisi
yer aldndan, compiler metod girdisinin tipini buradan elde edecektir. Tip tanmlamalarndan
feragat ettiimiz gibi parantezden de kurtulabiliriz.
Consumer<String> consumer = e -> {
System.out.println(e);
};

16

Consumer arayz
nerede kullanlyor?
consumer.accept("Merhaba Urans");

4.4. Consumer arayz nerede kullanlyor?


JDK 8 in ekirdeinde java.util.function arayzleri halihazrda kullanlmaktadr. rnein
Iterable arayznn ierisinde forEach metodunda Consumer arayz kullanlmaktadr.
public interface Iterable<T> {
...
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
...
}

forEach metodu, nce null kontrol yapmakta ve ardndan, dngsel olarak mevcut veri tipi
zerinde veri tketimi yapmaktadr. imdi bu metodu kullanan basit bir rnek yazalm.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(consumer);
// veya
names.forEach(e -> {
System.out.println(e);
});

Bu rnek ierisinde her bir isim bilgisi tek tek konsol ekranna ktlanmaktadr.

4.5. Lambda deyimlerini Metod Referanslar ile


kullanabiliriz.
Java 8 evvelinde bir metodu referans olarak kullanma ans bulunmuyordu. Fakat Java 8
ile birlikte Java metodlarn referans olarak kullanabiliyoruz. rnein, elimizde halihazrda
aadaki gibi bir listele metodu bulunsun.

17

Lambda deyimlerini Metod


Referanslar ile kullanabiliriz.
public class App{
public static void listele(String e) {
System.out.println(e);
}
}

Dikkat edilirse bu metodun girdi ve kt normu, Consumer#accept metodunun girdi ve kt


biimiyle birebir ayndr. Bu sebeple, listele metodu metod referans olarak Consumer tipi iin
kullanlabilirdir.
Consumer<String> consumer= App::listele;
consumer.accept("Merhaba Dnya");

Bir metodu referans olarak kullanabilmek iin


ifadesi kullanlmaktadr. imdi metod referans kullanmn rnek olarak forEach metodu
zerinde deneyelim.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(App::listele);

App#listele metodunun bir benzerinin yazlm zaten PrintStream snf ierisinde var.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(System.out::print);
// veya
names.forEach(System.out::println);

imdilik bu kadar, tekrar grmek dileiyle.

18

Blm 5. Lambda rnekleri


java.util.function paketi altnda bir ok fonksiyonel arayz bulunmaktadr. Bu
arayzlerin temel amac, farkl tipteki Lambda ifadelerine temel oluturmaktr.

5.1. Consumer Arayz


@FunctionalInterface
public interface Consumer<T> {
void accept(T t); // t-> {}
}

T tipindeki parametreyi alr ve tketir/iler. Geriye deer dndrmez (void). T burada herhangi
bir snf tipi olabilir.
Consumer Arayz rnek
Consumer<String> consumer = word -> {
System.out.println(word); // Merhaba Dnya
};
consumer.accept("Merhaba Dnya");

5.2. BiConsumer Arayz


@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u); // (t,u) -> {}
}

T ve U tiplerinde iki parametre alr ve bu parametreleri tketir. Geriye deer dndrmez.


BiConsumer Arayz rnek
BiConsumer<String, Integer> biConsumer = (name, age) -> {

19

Function Arayz

System.out.println(name+":"+age); // Alinin ya:25


};
biConsumer.accept("Ali'nin ya",25);

5.3. Function Arayz


@FunctionalInterface
public interface Function<T, R> {
R apply(T t); // t-> r
}

T tipinde bir parametre alr, iler ve R tipinde bir deer dndrr.


Function Arayz rnek
Function<Integer, Integer> function = t -> Math.pow(t,2);
Integer result = function.apply(5);
System.out.println(result); // 25

5.4. UnaryOperator Arayz


@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
}

Function trndendir. Eer T ve R tipleri ayn trden ise, ismi UnaryOperator olur.
UnaryOperator Arayz rnek
UnaryOperator<Integer> unaryOperator = a -> Math.pow(a,5);
Integer result = unaryOperator.apply(2);
System.out.println(result); // 32

20

BiFunction Arayz

5.5. BiFunction Arayz


@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u); // (t,u) -> r
}

T ve U tiplerinde iki parametre alr, R tipinde deer dndrr. T, U ve R herhangi bir snf tipi
olabilir. Function#apply tek parametre alrken Bi* iki parametre alr.
BiFunction Arayz rnek
BiFunction<Integer, Integer, String> biFunction = (a, b) -> "Sonu:" + (a + b);
String result = biFunction.apply(3,5);
System.out.println(result); // Sonu: 8

5.6. BinaryOperator Arayz


@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
}

BiFunction trndendir. T, U ve R ayn tipte ise BinaryOperator kullanlabilir.


BinaryOperator Arayz rnek
BinaryOperator<Integer> binaryOperator = (a, b) -> a + b;
Integer result = binaryOperator.apply(3,5);
System.out.println(result); // 8

5.7. Predicate Arayz


@FunctionalInterface
public interface Predicate<T> {

21

BiPredicate Arayz

boolean test(T t); // t-> true/false


}

T tipimde bir parametre alr, arta bal olarak true/false deer dndrr.
Predicate Arayz rnek
Predicate<Integer> predicate = a -> (a > 0);
boolean pos = predicate.test(5); // true
boolean neg = predicate.test(-5); // false

5.8. BiPredicate Arayz


@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u); // (t,u) -> true/false
}

T ve U tiplerinde iki parametre alr, arta bal olarak true/false dndrr.


BiPredicate Arayz rnek
BiPredicate<Integer, Integer> biPredicate = (a, b) -> (a > b);
boolean bigger = biPredicate.test(5,4); // true
boolean lower = biPredicate.test(5,7); // false

5.9. Supplier Arayz


@FunctionalInterface
public interface Supplier<T> {
T get(); // () -> t
}

Hi parametre almaz, T tipinde bir deer dndrr. Factory pattern iin uygundur.

22

Supplier Arayz

Supplier Arayz rnek


Supplier<List> supplier = () -> new ArrayList<>();
List<String> liste = supplier.get();
liste.add("Ali");
liste.add("Veli");
liste.add("Selami");

Tekrar grmek dileiyle

23

24

Blm 6. Notasyonlar ve Tekrarl


Notasyonlar
Notasyonlar (Annotations) Java 5den beri Java ortamnda kullanlan bileenlerdir.
Notasyonlar genel olarak bir bileene zellik katma veya konfigrasyon amal olarak
kullanlmaktadr. Bu yazda notasyonlarn genel zelliklerinden ve Java 8 Repeated
Annotations yeniliinden bahsedilecektir.
Notasyonlar @ iaretiyle
tanmlanabilmektedir.

balayan

arayzlerdir

ve

notasyonlar

iinde

alanlar

rnein;
@Single Notasyonu
public @interface Single {
String value();
}

Notasyonlar eitli alanlara uygulanabilmektedir. Bu alanlar;


Nereye uygulanabilir?

Aklama

TYPE

Snf, arayz, soyut snf balarna

METHOD

Metod balarna

FIELD

Global alan balarna

PARAMETER

Metod parametrelerine

CONSTRUCTOR

Constructor bana

ANNOTATION_TYPE

Notasyonlarn bana

PACKAGE

Paket deklarasyonu bana

Hangi notasyonun nereye veya nerelere uygulanabilecei, notasyonu yazan tarafndan


belirtilmektedir. Bu belirtim ilemi ise @Target isimli notasyon ile salanmaktadr.
rnek 1
@Target({ElementType.METHOD})

25

public @interface Single {


String value();
}

@Single notasyonunun uygulanabilirlik alan METHOD olarak tanmland iin, @Single


notasyonu sadece metod balarnda kullanlabilir. Dier alanlarda kullanlamaz, kullanlmaya
kalklrsa derleme zamannda hata alnr.
Uygulama 1
@Single // Buraya konamaz
public class App {
@Single // Buraya konabilir
public void doIt() {
}
}

rnek 2
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Single {
String value();
}

imdi ise @Single notasyonu hem metod balarna hem de snf, arayz, soyut snf gibi
bileenlerin balarna eklenebilir.
Uygulama 2
@Single // Artk buraya da konabilir
public class App {
@Single // Buraya uygulanamaz :(
String message = "Merhaba Dnya";
@Single // Buraya konabilir
public void doIt() {

26

Notasyonlar ve Alanlar

}
}

@Target notasyonu ile yaplan aslnda, notasyonun uygulanabilirlik alann, yani yetki
alann belirlemektir. rnein Uygulama 2'de uygulanabilirlik alan olarak METHOD ve
TYPE belirlenmitir. Bu sebeple sadece bununla ilgili ksmlara @Single notasyonu
uygulanabilir.Mesela rnekte olduu gibi global alanlara uygulanamaz. Eer buraya da
uygulanabilir olmas istenirse FIELD enum bileeni @Target notasyonuna eklenmelidir.

6.1. Notasyonlar ve Alanlar


Notasyonlar konfigrasyon amacyla kullanlrken, barndrd deiken alanlarndan
faydalanlmaktadr. Bu alanlarn tipi, ismi ve gerekirse varsaylan deeri tanmlanabilmektedir.
Fakat bu alanlarda tip snrlamas vardr, bu tipler unlar olabilir;
String
Temel tipler
Class
Bir Enum tipi
Dier bir notasyon tipi
Yukardaki tiplerin dizi tipleri
@Single notasyonunu dnrsek String trnde value adnda tek bir alana sahiptir.
Deer atamas ise deklerasyon annda () ierisinde yaplmaktadr.
rnein;
@Single(value="Merhaba Dnya")
public interface Hello {
}

Notasyonlar iin value alannn zel bir anlam vardr. Eer baka bir alana deer atamas
yaplmayacaksa value yazlmasa bile bu deer atamas value alanna yaplmaktadr.
rnein;
@Single("Merhaba Dnya")

27

Notasyonlara Eriim

public interface Hello {


}

Denktir @Single(value="Merhaba Dnya")

6.2. Notasyonlara Eriim


Notasyonlarn nereye uygulandklar ve ierisinde barndrdklar veriler derleme zamannda
(compile time) veya alma zamannda (runtime) elde edilebikmektedir. Fakat bir notasyona
hangi zamanlarda eriilebilecei @Retention isimli notasyon ile belirtilmelidir. Retention
(tutma) politikasnn 3 tipi vardr.
SOURCE
Notasyonlar derleme zamannda yok saylr.
CLASS
Notasyonlar derleme zamannda snf ierisinde bulundurulur, fakat alma zamannda
bulunmas zorunlu deildir. Varsaylan hal budur.
RUNTIME
Notasyonlar alma zamannda eriilmek zere snf ierisinde bulundurulur. alma
zamannda eriim Java Reflection API ile yaplr. Sk kullanlan hal budur.
Not
Rastgele 10 notasyon belirleyip, @Retention notasyonunu incelediinizde %90 zeri
arlkta tutma politikasnn RUNTIME olarak yaplandrldn grebilirsiniz.
rnein;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Single {
String value();
}

Metod ve Snflarn bana uygulanabilir.


alma zamannda bu notasyona eriilebilir.
Yukarda @Target ve @Retention notasyonlaryla yaplandrlm kullanma hazr bir
@Single notasyonunu gryoruz.

28

Notasyonlarn
Tekrarl Kullanlmas

6.3. Notasyonlarn Tekrarl Kullanlmas


Java 8 ncesinde bir notasyon, iki kere ayn yerde kullanlamamaktayd.
Hatal kullanm rnei;
@Single("Merhaba")
@Single("Jupiter")
public class App {

rnein @Single notasyonu yukardaki gibi ayn alanda kullanlamaz. Bu snrllk Java 8
ncesinde ikincil bir notasyon zerinden almaktayd.
rnein;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Multiple {
Single[] value();
}

Multiple notasyonu Single tipli diziler barndrabilen bir value alanna sahiptir. Artk
Multiple notasyonu zerinden birden fazla @Single notasyonu uygulanabilirdir.
Doru kullanm rnei;
@Multiple(value = {
@Single("Merhaba"),
@Single("Jupiter")
})
public class App {

NOTE : Notasyonlarda dizi tipli alanlara atamamalar, { } arasnda virgl , ile ayrlm olarak
yaplmaktadr.
Java 8 ile birlikte bu snrllk ortadan kalkmtr. Bu snrll ortadan kaldrmak iin
@Repeatable notasyonundan faydalanlmaktadr.

29

Notasyonlarn
Tekrarl Kullanlmas
@Repeatable(Multiple.class) // Dikkat
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Single {
String value();
}

@Repeatable notasyonu tekrarlayacak notasyona uygulanmaktadr. @Repeatable


ntoasyonunun value alanna ise, sarmalayc notasyonun snf tipi tanmlanmaldr. Bu yolla
tekrarl notasyonlar alt alta, yan yan istendii kadar tanmlanabilmektedir.
rnein;
@Single("Merhaba")
@Single("Urans")
public class App {
public static void main(String[] args) {
Class<App> app = App.class;
Single[] notz = app.getAnnotationsByType(Single.class);
for (Single not : notz) {
System.out.println(not.value());
// Merhaba
// Urans
}
}
}

App snfnn snf tipini alr.


App snfna uygulanm tm Single tipli notasyonlar bulur.
Tm uygulanm Single notasyonlarn dolar.
O anki Single notasyonunun value() alann ktlar.
Tekrar grmek dileiyle.

30

Blm 7. Method Reference


Java programlama dilinde metodlar, snflarn iinde bulunan i birimleridir.
Metodlara eriimin ise statik olup olmadna gre iki eriim biimi vardr. Statik
metodlara snf zerinden eriilebilirken, statik olmayan metodlara nesne zerinden eriim
salanabilmektedir.
Java 8 ile beraber metod birimleri, bir lambda ifadesine, dolaysyla bir fonksiyonel arayze
karlk olarak referans verilebilmektedir.
Lambda ifadeleri yazlrken, tek metoda sahip arayzn (fonksiyonel arayz) metod girdi ve
kts baz alnmaktadr. Eer daha nce yazdnz bir metodun girdi ve kts, bir fonksiyonel
arayz metodunun girdi ve ktsna birebir uyuyorsa, o metod bir lambda deyimi yerine
kullanlabilmektedir.
rnein;
Consumer arayz T trnde tek bir parametre alr. Metod dn void 'dir.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t); // t-> {}
}

Yukardaki Consumer arayz trnden bir nesneyi, e {} lambda deyimiyle


oluturabiliriz.
Consumer<String> consumerWithLambda = e-> {
};

Lambda ifadeleri yazarken metod girdi ve ktsna odaklandmza gre, lambda deyimiyle
birebir rten metodlar, lambda deyimleri yerine kullanabilir miyiz? Bunu aadaki metod
zerinden dnelim.
public void herhangiBirMetod(String e){
}

31

Bir metodu referans vermek

Yani herhangiBirMetod metodunun imzasyla Consumer<String> arayznn accept


metodunun imzas birbiriyle ayndr. herhangiBirMetod , String trnden tek bir parametre
almaktadr, metod dn ise void 'dir. Bu uyum neticesinde eer istenirse, bu metodun
referans ile Consumer<String> trnden bir nesne oluturulabilir.

7.1. Bir metodu referans vermek


Java programlama dilinde bir metodun nasl referans verilecei metodun statik olup
olmadna gre deimektedir. Bir metodun referans olarak verilebilmesi iin ise :: ikilisi
kullanlr.
Statik metodlarda Statik metodlar snfa ait bileenlerdir. Bu yzden eriim kurulurken dahili
olduu snf zerinden eriim kurulur.
rnein;
Consumer<String> consumerWithMetRef = <ClassName>::herhangiBirMetod;

Statik olmayan metodlarda Statik olmayan metodlar nesneye ait bileenlerdir. Bu sebeple
nesnenin referans zerinden eriilmelidirler.
rnein;
Consumer<String> consumerWithMetRef = <ObjectRef>::herhangiBirMetod;

rnek 1 imdi birka rnek ile metod referanslar deneyimleyelim. Aada


"Ali" , "Veli" , "Selami" verilerini ieren bir List nesnesi bulunmaktadr. Bu nesnenin
ise, forEach isimli metodu bulunmaktadr. Bu nesnenin kabul ettii parametre ise
Consumer<String> trndendir.
List<String> names= Arrays.asList("Ali,Veli,Selami");
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});

Srayla konsole ktlar.


imdi bu rnei Lambda ifadesiyle yeniden aadaki gibi yazabiliriz.

32

Bir metodu referans vermek

List<String> names= Arrays.asList("Ali,Veli,Selami");


names.forEach(s->{
System.out.println(s);
});

Lambda ifadesi, satr says baznda kodu iyice ksaltt. imdi bu ayn ii metod referans
kullanarak yapalm.
public class App{
static List<String> names= Arrays.asList("Ali,Veli,Selami");
// Statik metod
public static void herhangiBirMetod(String s){
System.out.println(s);
}
// Non-statik metod
public void digerBirMetod(String s){
System.out.println(s);
}

public static void main(String[] args){


names.forEach(App::herhangiBirMetod);
// veya
App app=new App();
names.forEach(app::digerBirMetod);
// veya
names.forEach(System.out::println);
}
}

Statik metodu referans vermek


Non-statik metodu referans vermek
Dier bir rnek

33

Bir metodu referans vermek

rnek 2 Collections#sort metodu ile bir dizi nesneyi sralamak istiyoruz diyelim.
Bu sralamay, metodun 2. parametresinde Comparator trnden bir nesne ile kontrol
edebiliriz.
List<Integer> numbers = Arrays.asList(5, 10, 1, 5, 6);
Collections.sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});

Fonksiyonel
olarak
Comparator
arayz
java.util.BiFunction arayz birebir ayndr.

ve

imdi anonim olarak oluturulan Comparator trnden nesneyi Lambda ifadeleriyle yeniden
yazalm.
List<Integer> numbers = Arrays.asList(5, 10, 1, 5, 6);
Collections.sort(numbers, (o1, o2) -> o1 - o2)

imdi ise Lambda deyimi yerine metod referans kullanarak bu ii yapalm.


public Integer sirala(Integer o1, Integer o2){
return o1 - o2;
}
public void birMetod(){
List<Integer> numbers = Arrays.asList(5, 10, 1, 5, 6);
Collections.sort(numbers, this::sirala);
}

Lambda yerine metod referans


Metod referans kullanmak var olan i mantn kolay bir biimde referans vermeye olanak
salamaktadr.

34

Bir metodu referans vermek

Tekrar grmek dileiyle.

35

36

Blm 8. Default Methods


Java 8 ile beraber varsaylan metod zellii bir dil zellii olarak Javaya katld. Varsaylan
metodlarn literatrde birok farkl isim ile anlmaktadr. Bunlar;
Default method
Defender method
Virtural extension method
Java 8 evvelinde arayz bileenlerinde dilin tasarm asndan sadece soyut metodlar
bulunabilmekteydi. Somut yani gvdeli metodlar bulunamamaktayd. Aada doru ve yanl
kullanmlara birer rnek grmekteyiz.
Doru bir kullanm rnei
public interface Arac {
void gazla();
}

Soyut, gvdesiz metod, doru kullanm.


Yanl bir kullanm rnei
public interface Arac {
void gazla() {
// bla bla bla
};
}

Somut, gvdeli metod, yanl kullanm.

8.1. Varsaylan Metoda Giri


Java 8 ile birlikte bir arayz bileeninde bir yada daha fazla sayda defender method
tanmlanabilmektedir. Varsaylan metodlar default anahtar kelimesiyle tanmlanmaktadr.
rnein;
public interface Arac {

37

Varsaylan Metoda Giri

default void gazla(){ // Defender method


System.out.println("Ara:

alyor..");

}
void dur(); // Soyut metod
}

numaral ksmdaki gazla() metodu default anahtar ifadesi araclyla bir


varsaylan metoda dntrlmtr. Varsaylan metodlar arayzlere i mant
yerletirmeye msade eden zel metodlardr.
numaral ksmda ise olaan biimde gvdesiz bir metod bulunmaktadr.
Varsaylan metoda sahip bir arayzden treyen alt snflar, arayzn sahip olduu tm
defender metodlar tketebilmektedir.
Arac trnden Minibus snf
public class Minibus implements Arac {
@Override
public void dur() {
System.out.println("Minibs duruyor..");
}

rnein yukarda yer alan Minibus snf Arac`arayz trnden bir snftr.
Bu sebeple, Minibus snf trnden nesneler `Arac arayz ierisindeki
gazla() metodunu koturabilecektir.
Minibus minibus=new Minibus();
minibus.gazla();
minibus.dur();

Arac iindeki gazla() varsaylan metodu koturuluyor.


Minibus iindeki dur() metodu koturuluyor.
Ara: alyor..
Minibs duruyor..

38

Varsaylan
metodlarda akma
Yukarda grld zere, normalde Minibus snf ierisinde gazla()
bulunmamasna ramen, Arac arayz iindeki defender metodu koturabildi.

metodu

8.2. Varsaylan metodlarda akma


Eer bir Java snf, ayn isimde varsaylan metoda sahip birden fazla arayz uygularsa,
derleme zamannda hata ile karlalr.
Ayn isimde varsaylan metodlara sahip iki arayz
public interface Arac {
default void gazla(){
System.out.println("Ara:

alyor..");

}
void dur();
}
public interface Tasit {
default void gazla(){
System.out.println("Tat: alyor..");
}
}

rnein (1) numarada Arac , (2) numarada da Tasit arayzleri gazla() adnda
varsaylan metodlara sahiptir.
imdi bu iki tr birden uygulayan bir Otobus snf yazalm.
akma durumu rnei
public class Otobus implements Arac, Tasit {
@Override
public void dur() {
System.out.println("Ara duruyor..");
}
}

Otobus snf bu haliyle derlendiinde aadaki derleme hatas alnacaktr.


akma durumu hata mesaj

39

Varsaylan
metodlarda akma
Error:(6, 8) java: class com.kodcu.def.Otobus inherits unrelated defaults for
gazla() from types com.kodcu.def.Arac and com.kodcu.def.Tasit

nk ortada Otobus snfnn hangi gazla() metodunu koturacana dair bir ikilem
vardr. JVM ikilem durumlarn hi sevmez, ona bir seim ansz sunmalyz. Bu akma
durumu, varsaylan metodu Otobus snf iinde yeniden dzenlenerek ( @Override ederek)
giderilebilmektedir.
akma durumunun giderilmesi - 1
public class Otobus implements Arac, Tasit {
@Override
public void dur() {
System.out.println("Ara duruyor..");
}
@Override
public void gazla() {
System.out.println("Otobs alyor..");
}
}

Otobus snfna gazla() metodu ekleyerek yeniden dzenlendiinde artk akma


durumu giderilmi durumdadr. Snf bu haliyle Otobs
alyor.. mesajn
ktlayacaktr.
Fakat burada farkl bir ihtiya daha gze batmaktadr. Bu durumda Arac veya Tasit
arayzleri iindeki akan gazla() metodlar nasl alt snflarda kullanlabilir?
te bu noktada <arayz-ad>.super.<metod-ad>()
varsaylan metodlar akma olmadan koturulabilmektedir.
akma durumunun giderilmesi - 2
public class Otobus implements Arac, Tasit {
@Override
public void dur() {
System.out.println("Ara duruyor..");
}
@Override
public void gazla() {

40

biimi ile arayzlerdeki

Varsaylan metodlar ve
Fonksiyonel arayzler

Arac.super.gazla();
/* veya */
Tasit.super.gazla();
}
}

Arac arayznn gazla() metodunu koturur


Tasit arayznn gazla() metodunu koturur

8.3. Varsaylan metodlar ve Fonksiyonel arayzler


Fonksiyonel arayzler, tek bir gvdesiz metoda sahip zel arayzlerdir. Eer bir Java
arayznn iinde birden fazla sayda soyut metod varsa, bu arayzler fonksiyonel arayz
olamamaktadr. Fonksiyonel arayzlerin en nemli zellii, Lambda ifadesi olarak temsil
edilebilmesidir.
Arayzler iinde tanmlanan varsaylan metodlar ise, bir arayzn fonksiyonel olabilmesini
etkilememektedir. nk yazlan Lambda deyimleri, arayz iindeki tek bir soyut metoda
odakl olarak dntrlmektedir.
public interface Arac {
default void gazla(){
System.out.println("Ara:

alyor..");

}
void dur();
}

rnein yukardaki Arac arayzn fonksiyonel arayz olabilirlii asndan deerlendirelim.


Arac snfnn fonksiyonel arayz olabilmesi iin tek bir soyut metoda sahip olmas
gerekmektedir. Arac arayz iindeki dur() metodu soyuti gvdesiz bir metod olduu iin
bir fonksiyonel arayzdr. gazla() metodu ise bir varsaylan metod olduundan fonksiyonel
olabilirlie bir etkisi yoktur. Bu noktada, Arac arayz bir fonksiyonel arayz olduundan
Lambda deyimi olarak yazlabilecektir. Tabi ki Lambda deyimi, dur() isimli soyut metod
dikkate alnarak yazlmaldr.

Arac otobus = ()-> System.out.println("Otobs duruyor..");


otobus.gazla();

41

Varsaylan metodlar ve JDK

otobus.dur();

Ara: alyor..
Otobs duruyor..

Yukarda (1) numarada yazl Lambda deyimi, dur() metoduna karlk olarak tanmlanmtr.
Bu sebeple Arac arayz trnden bir nesne oluturmaktadr.

8.4. Varsaylan metodlar ve JDK


JDK
1.8
ierisinde
baz
noktalarda
varsaylan
metodlar
java.util.Collection arayznde bunu fazlaca grmekteyiz.
public interface Collection<E> extends Iterable<E> {
...
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
...
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}

42

kullanlmaktadr.

Varsaylan metodlar ve JDK

Collection snf iindeki removeIf , stream , parallelStream ve spliterator


metodlar varsaylan metodlardr. Bu sebeple Collection trnden tm nesneler bu
varsaylan metodlar miras alarak tketebilmektedir.
Collection arayznde olduu gibi Iterable arayznde de varsaylan metod
bulunduunu grebiliyoruz.
@FunctionalInterface
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}

Iterable#forEach varsaylan metodu sayesinde Iterable trnden tm veri tipleri, bu


metodu ortak olarak tketebiliyor.
Tekrar grmek dileiyle..

43

44

Blm 9. Stream API


Java 8 ierisinde ynsal verileri kolay ilemek asndan Stream API yenilii getirilmitir.
Stream API ynsal veriler zerinde almaktadr. Ynsal veri deyince ilk akla gelen
hi phesiz diziler ( byte[] , String[] gibi ) ve Java Collection API bileenleridir
( List , Set gibi)
Stream API, bu gibi ynsal veriler zerinde eitli sk kullanlan operasyonlar kolay, zl ve
verimli bir biimde koturmaya olanak tanmaktadr. Bu operasyonlardan en sk kullanlanlar
aadaki gibidir.
Metod

Aklama

filter

Filtreleme

forEach

iterasyon

map

Dntrme

reduce

ndirgeme

distinct

Tekilletirme

sorted

Sralama

limit

Aralk alma

collect

Tre dnm

count

Sayma

Bu operasyonlar ve daha fazlas java.util.stream.Stream arayz iinde bulunmaktadr.


Stream arayznn sadeletirilmi hali aadaki gibidir.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
LongStream mapToLong(ToLongFunction<? super T> mapper);
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>>
mapper);

45

Stream nesnesi
nasl elde edilir?
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream>
mapper);
Stream<T> distinct();
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
Stream<T> peek(Consumer<? super T> action);
Stream<T> limit(long maxSize);
Stream<T> skip(long n);
void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);
Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count();
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
Optional<T> findFirst();
Optional<T> findAny();
}

9.1. Stream nesnesi nasl elde edilir?


Stream trnden nesneler eitli yollarla elde edilebilmektedir.

9.1.1. Collection API ile


Collection arayz trnden treyen tm nesneler, stream() veya parallelStream() metodlarn
ararak Stream<E> trnden bir nesne elde edebilmektedir.
public interface Collection<E> extends Iterable<E> {

46

New I/O ile

...
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
...
}

stream() metodu ile elde edilen Stream nesnesi yapaca ilemleri ardl olarak yaparken,
parallelStream() metoduyla elde edilen Stream nesnesi, baz operasyonlar paralel olarak
koturabilmektedir.
rnein;
List<String> names = Arrays.asList("Ali","Veli","Selami");
Stream<String> stream = names.stream();
Stream<String> parallelStream = names.parallelStream();

Collection trnden bir nesne


Ardk stream
Paralel stream

9.1.2. New I/O ile


Java ierisindeki baz I/O snflar zerinden Stream nesneleri elde edilebilmektedir.

Path dir = Paths.get("/var/log");


Stream<Path> pathStream = Files.list(dir);

/var/log dizinine denk gelen bir Path nesnesi


Files#list metodu zerinden bir Stream<Path> nesnesi

47

IntStream, DoubleStream,
LongStream ile

9.1.3. IntStream, DoubleStream, LongStream ile


Stream arayz BaseStream arayznden tremektedir. Stream arayzne benzer
biimde IntStream, DoubleStream ve LongStream arayzleri de BaseStream arayznden
tremektedir.
Stream arayz trnden nesneler tm veri tipleriyle almak iin oluturulan bir arayzken,
buradaki eleman ise, sadece snf bandaki tip ile zel olarak almak iin oluturulan
arayzlerdir.
rnein;
IntStream intOf = IntStream.of(1, 2, 3);
IntStream intRange = IntStream.range(1, 10);
DoubleStream doubleOf = DoubleStream.of(1.0, 3.5, 6.6);
LongStream longOf = LongStream.of(3, 5, Long.MAX_VALUE,9);
LongStream longRange = LongStream.range(1, 100);

(1,2,3) ieren IntStream nesnesi


(1,,10) arasn ieren IntStream nesnesi
(1.0, 3.5, 6.6) ieren DoubleStream nesnesi
(3, 5, Long.MAX_VALUE,9) ieren LongStream nesnesi
(1,,100) arasn ieren LongStream nesnesi

9.2. Stream API rnekleri


Bu ksmda eitli Stream API metodlar ile kk uygulamalar yer almaktadr.

9.2.1. forEach
Stream ierisindeki ynsal veriyi tek tek tketmek iin yaplandrlmtr. Consumer arayz
trnden bir parametre bekler.
List<String> names =
Arrays.asList("Ali","Veli","Selami","Cem","Zeynel","Can","Hseyin");
Stream<String> stream = names.stream();
stream.forEach(name -> {

48

filter

System.out.println(name);
});
// veya stream.forEach(System.out::println);

9.2.2. filter
Stream ierisindeki ynsal veri zerinde szme ilemi yapar. Predicate arayz trnden bir
parametre ile filtreleme ilemini yapar.
List<String> names =
Arrays.asList("Ali", "Veli", "Selami", "Cem", "Zeynel", "Can", "Hseyin");
Stream<String> stream = names.stream();
Predicate<String> predicate = name -> name.length() < 4;
Stream<String> filtered = stream.filter(predicate);
filtered.forEach(System.out::println);

Stream nesnesi elde ediliyor.


Predicate sorgusu hazrlanyor
Szme ilemi yaplyor, yeni bir Stream nesnesi sunuluyor.
Listeleniyor. [Ali, Cem, Can]
Stream nesneleri tek kullanmlktr. Stream nesnesinin ou metodu
yeni bir Stream nesnesi sunmaktadr. Bu sebeple tm operasyonlar
zincirlemeli olarak yaplabilmektedir.
rnein;
names
.stream()
.filter(name -> name.length() == 4)
.forEach(System.out::println);

9.2.3. distinct
Bir Stream ierisinden tekrarl veriler karlmak isteniyorsa distinct metodundan
faydalanlabilir.

49

sorted

IntStream stream = IntStream.of(1, 1, 2, 3, 5, 8, 13, 13, 8);


stream
.distinct()
.forEach(System.out::println);

IntStream nesnesi
[1,2,3,5,8,13]

9.2.4. sorted
Stream ierisindeki ynsal verinin sralanm Stream nesnesini dndrr.

IntStream stream = IntStream.of(13, 1, 3, 5, 8, 1, 13, 2, 8);


stream
.sorted()
.forEach(System.out::println);

IntStream nesnesi
[1,1,2,3,5,8,8,13,13]

9.2.5. limit
Bir Stream yn ierisindeki ilk N veri barndran yeni bir Stream nesnesi sunmaktadr.

LongStream range = LongStream.range(1, 10000);


range
.limit(10)
.forEach(System.out::println);

(1,,10000) arasn ieren bir Stream


lk 10 veri : [1,,10]

9.2.6. count
Stream ierisindeki eleman saysn hesaplar.

50

collect

IntStream range = IntStream.range(1, 10);


IntStream rangeClosed = IntStream.rangeClosed(1, 10);
System.out.println(range.count());
System.out.println(rangeClosed.count());

9
10

9.2.7. collect
Stream trnden nesneler, yn verileri temsil eden zel nesnelerdir. Fakat Stream biimi bir
veri yaps sunmamaktadr. collect metodu arlkl olarak , Stream nesnelerini baka biimdeki
bir nesneye, veri yapsna dntrmek iin kullanlmaktadr.
Stream#collect metodu Collector trnden bir parametre kabul etmektedir. Bu parametre
ile istendik tre dnm salanmaktadr. Collector trnden arayzler, Collectors
snfnn eitli statik metodlaryla elde edilebilmektedir.
List<String> names =
Arrays.asList("Ali", "Veli", "Selami", "Veli", "Selami", "Can", "Hseyin");
List<String> list = names.stream().collect(Collectors.toList());
Set<String> set = names.stream().collect(Collectors.toSet());
Long count = names.stream().collect(Collectors.counting());
String collect = names.stream().collect(Collectors.joining(" - "));
Map<Integer, List<String>> integerListMap =
names.stream().collect(Collectors.groupingBy(name -> name.length()));

Stream nesnesinden List nesnesi retir.


List["Ali", "Veli", "Selami", "Veli", "Selami", "Can", "Hseyin"]
Stream nesnesinden Set nesnesi retir.
Set["Ali", "Veli", "Selami","Can", "Hseyin"]
Stream nesnesinin eleman saysn retir.
7

51

map

Stream nesnesini birletirir.


Ali - Veli - Selami - Veli - Selami - Can - Hseyin
Stream nesnesini isim uzunluuna gre gruplar.

Tablo 9.1. Map<Integer, List<String>> nesnesinin temsili tablo


grnm
Key

Value

Ali
Can
Veli

Veli
Selami

Selami
7

Hseyin

9.2.8. map
Stream iindeki ynsal olarak bulunan her bir veriyi dntrmeye olanak tanr. Dntrm
ilemi Stream ierisindeki her bir e iin ayr ayr yaplmaktadr. Stream#map metodu
Function trnden bir parametre beklemektedir.
rnek 1; Bir List<String> iindeki her bir enin harflerini bytelim.
List<String> names = Arrays.asList("Ali", "Veli", "Selami", "Cem");
Stream<String> stream = names.stream();
Stream<String> upperStream= stream.map(name -> name.toUpperCase());
List<String> upperNames = upperStream.collect(Collectors.toList());

Stream<String> nesnesi elde ediliyor


Her bir ismin harfleri bytlyor
List["AL","VEL","SELAM","CEM"]
rnek 2; 1,5 aras saylarn karelerini hesaplayalm.
IntStream

52

reduce

.rangeClosed(1, 5)
.map(n -> n*n)
.forEach(System.out::println);

[1, 4, 9, 16, 25]

9.2.9. reduce
Bir Stream ierisindeki verilerin teker teker ilenmesidir. Teker teker ileme srecinde, bir
nceki admda elde edilen sonu bir sonraki adma girdi olarak sunulmaktadr. Bu sayede
ylml bir hesaplama sreci elde edilmi olmaktadr.
Stream#reduce metodu ilk parametrede identity
BinaryOperator trnden bir nesne kabul etmektedir.

deeri, ikinci parametrede ise

reduce ileminde bir nceki hesaplanm deer ile sradaki deer bir ileme tabi tutulmaktadr.
leme balarken bir nceki deer olmad iin bu deer identity parametresinde
tanmlanmaktadr.
rnek 1; 1,2,3,4,5 saylarnn toplamn hesaplayalm.
int result = IntStream
.of(1, 2, 3, 4, 5)
.reduce(0, (once, sonra) -> {
System.out.format("%d - %d %n", once, sonra);
return once + sonra;
});

Toplama ileminde 0 etkisiz eleman olduu iin, identity deeri 0 seildi.


Uygulama altrldnda 15 sonucu elde edilir. reduce iindeki Lambda ifadesinde ise
aadaki kt elde edilir.
0 - 1
1 - 2
3 - 3
6 - 4
10 - 5

nce hesaplanm deeri, Sonra ise sradaki deeri temsil etmektedir. Bir admda kan
hesaplamann sonucu, bir sonraki admda (satrda) nce stununa sunulmaktadr.

53

map & reduce

nce

Sonra

Hesaplama

0+1 #

1+2 #

3+3 #

6+4 #

10

10+5 = 15

rnek 2; 1,2,3,4,5 saylarnn arpmn hesaplayalm.


// Lambda ile
int result = IntStream
.of(1, 2, 3, 4, 5)
.reduce(1, (once, sonra) -> once*sonra);
// veya Method reference ile
result = IntStream
.of(1, 2, 3, 4, 5)
.reduce(1, Math::multiplyExact);

9.2.10. map & reduce


map ve reduce ilemleri birlikte kullanm ok fazla tercih edilen iki operasyondur. Bu
operasyonlar nemli klan ise, bu iki operasyonun datk sistemler iin ok uygun
olmasdr. Piyasada Map & Reduce ilemlerini datk mimarilerde kullanan birok teknoloji
bulunmaktadr. Tabiki Java 8 ile kullandmz map & reduce ikilisi tek JVM zerinde kotuu
iin datk deildir.
rnein;
Hazelcast
Hadoop
MongoDB gibi.
rnek 1; Elimizde Person snf trnden 5 nesne bulunsun. Bu 5 nesne iinden tm kiilerin
yalarnn ortalamasn hesaplamak isteyelim. Byle bir senaryo iin map & reduce metodlarn
birlikte tercih edebiliriz.
public class Person {
private String name;

54

map & reduce

private Integer age;


// getter, setter ve constructor metodlar
}

Person p1 = new Person("Ahmet", 12);


Person p2 = new Person("Ali", 20);
Person p3 = new Person("Aye", 30);
Person p4 = new Person("Murat", 51);
Person p5 = new Person("Zeynep", 60);
List<Person> personList = Arrays.asList(p1, p2, p3, p4, p5);
personList
.stream()
.map(p -> p.getAge())
.map(Double::valueOf)
.reduce(0, (a, b) -> (a + b)/2);

Person listesi
Stream nesnesi elde ediliyor
Nesnenin ya alanna gre mapping yaplyor.
Integer Double dnm
Ortalamalar hesaplanyor
rnek 2; Person listesinde baz kiilerin ya alanlar null deer iersin. Bu durumda alma
zamannda nullpointerexception istisnas elde edilecektir. Bu gibi bir durumda filtreleme
yapsn ilemimize ekleyebiliriz.
Person p1 = new Person("Ahmet", 12);
Person p2 = new Person("Ali", null);
Person p3 = new Person("Aye", 30);
Person p4 = new Person("Murat", null);
Person p5 = new Person("Zeynep", 60);
List<Person> personList = Arrays.asList(p1, p2, p3, p4, p5);
personList
.stream()
.filter(Objects::nonNull) // Dikkat !!
.map(p -> p.getAge())
.map(Double::valueOf)

55

Parallel Stream

.reduce(0, (a, b) -> (a + b)/2);

9.3. Parallel Stream


Stream arayz iindeki metodlardan ardk iletilmesi gerekmeyenler, istenirse, CPU
zerinde paralel olarak koturulabilmektedir. Bu sayede CPU ekirdeklerini tam verimli olarak
kullanmak mmkn olmaktadr.
Stream API ierisinde paralel Stream elde etmek olduka kolaydr.
rnein
List<Integer> ints = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15);
Stream<Integer> stream = ints.stream();
Stream<Integer> parallelStream = ints.parallelStream();

Collection#stream() metoduyla ardl (sequential) , Collection#parallelStream() metoduyla da


paralel Stream nesnesi elde edilmektedir. Elde edilen paralel Stream nesnesiyle koturulan
ilemler paralel olarak koabilmektedir.
Ayn zamanda bir ardl Stream nesnesinden paralel Stream nesnesi elde edilebilmektedir.
Bunun iin Stream#parallel metodu kullanlmaktadr.
rnein;
List<Integer> ints = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15);
Stream<Integer> stream = ints.stream(); // Ardl
Stream<Integer> parallelStream = stream.parallel(); // Paralel

Ayn zamanda bir paralel Stream nesnesinden ardl Stream nesnesi de elde edilebilmektedir.
Bunun iin Stream#sequential metodu kullanlmaktadr.
rnein;
List<Integer> ints = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15);
Stream<Integer> parallelStream = ints.parallelStream(); // Paralel
Stream<Integer> stream = stream.sequential(); // Ardl

rnek Aada bir dizi saysal ifadeyi filtreleyen, sralayan ve ktlayan bir kod paras
grmekteyiz. Ayrca bu ilemlerin paralel Stream nesnesiyle yaplmak istendiini gryoruz.

56

Lazy & Eager operasyonlar

List<Integer> ints = Arrays.asList(1, 5, 3, 7, 11, 9, 15, 13);


ints
.parallelStream() // Paralel Stream
.filter(Objects::nonNull) // null deilse
.filter(n -> n > 0) // pozitif say ise
.sorted() // srala
.forEach(System.out::println); // ktla

Bu rnekte filter ve sorted paralel olarak koturulabilirdir. Fakat forEach metodu doas gerei
eleri ardk ktlamaldr. te tam da bu admda elimizdeki paralel Stream nesnesi ardl
Stream nesnesine dntrlmektedir ve ardndan forEach ilemini koturmaktadr.
Yani elimizde paralel Stream nesnesi varsa, bu zincirlemeli ilemin her admnda paralel
koturma yaplaca anlamn tamamaktadr.

9.4. Lazy & Eager operasyonlar


Literatrde Lazy bir ilemin ge, telenmi olarak yaplmas iken, Eager ise yaplacak ilemin
emir verilir verilmez yaplmasn temsilen kullanlr.
Stream API ierisindeki baz operasyonlar Lazy bazlar ise Eager olarak koturulmaktadr.
Lazy davranl olan zincirli grevler, bir Eager operasyona gelene kadar koturulmamaktadr.
List<Integer> names = Arrays.asList(1,2,3,6,7,8,9);
Stream<Integer> stream = names
.stream()
.filter(Objects::nonNull)
.filter(n->n%2==1)
.map(n->n*2);

rnein yukardaki liste zerinde yaplmak istenen 2 filter ve 1 map ilemi Lazy
ilemlerdir. Kod paras bu haliyle altrldnda ne bir filtreleme ne de bir dntrme
ilemi yaplacaktr. Burada yaplan sadece Stream nesnesini hazrlamaktr. Lazy ilemler
gerekmedike ileme konulmamaktadr.
List<Integer> names = Arrays.asList(1,2,3,6,7,8,9);
Stream<Integer> stream = names
.stream()
.filter(Objects::nonNull)

57

Lazy & Eager operasyonlar

.filter(n->n%2==1)
.map(n->n*2)
stream.forEach(System.out::println); // Dikkat !!

Lazy
Lazy
Lazy
Eager
Fakat bu hazrlanan Stream nesnesi, yukardaki gibi bir Eager operasyonla karlarsa,
nceki zincirlerde biriken Lazy ilemleri de harekete geirecektir. Yani (4) numaradaki ilem,
(1)(2)(3) numaral ilemlerin tetikleyicisi konumundadr.
Tekrar grmek dileiyle..

58

Blm 10. Java 8 ve JVM Dilleri


Java Sanal Makinesi (JVM), Java 7 ile balayan Da Vinci Machine

projesiyle, zellikle

dinamik tipli dilleri JVM zerinde alabilir klmaktadr.


Sun Microsystemin ilk admlarn att bu proje, Oracle firmasyla beraber de nem verilen
bir konu olmaya devam etmektedir. JVM ierisinde statik tipli dilleri altrabilmenin birden
fazla amac bulunmaktadr. Bunlar;
JIT (Just in Time) Compiler ile yksek performans sunmak
2

Birok dilin altrlmasyla JVMi Polyglot bir ortam haline getirmek


Farkl dil ve ekosistemleri Java ekosistemine yaknlatrmak
Farkl dil ekosistemlerinin gcn JVMde birletirmek

10.1. JVM Dilleri


Halihazrda Java Sanal Makinesi zerinde birok programlama dili altrlabilmektedir. Bu
diller Tablo 10.1, JVM Dilleri Tablosunda olduu gibidir;

Tablo 10.1. JVM Dilleri Tablosu


Dil

Uygulayc ktphane

Ada

JGNAT

BBx

BBj is a superset of BBx, PRO/5, and Visual PRO/5.

C to Java Virtual Machine compilers

CFML

Adobe ColdFusion
Railo
Open BlueDragon

Common Lisp

Armed Bear Common Lisp


CLforJava

JavaScript

Rhino

1
http://openjdk.java.net/projects/mlvm/
2
http://en.wikipedia.org/wiki/Polyglot_(computing)

59

JVM Dilleri

Dil

Uygulayc ktphane
Nashorn

Pascal

Free Pascal
MIDletPascal

Perl 6

Rakudo Perl 6

Prolog

JIProlog
TuProlog

Python

Jython

REXX

NetRexx

Ruby

JRuby

Scheme

Bigloo
Kawa
SISC
JScheme

Tcl
Kaynak: List of JVM languages

Jacl
3

Tablo 10.1, JVM Dilleri Tablosunda listelenen programlama dilleri JVM bnyesinde
koturulabilmektedir. Baz diller yorumlama uslyle koturulurken, bazlar ise bayt koda
dntrldkten sonra koturulmaktadr. Fakat, JavaScript haricindeki dillere karlk bir
uygulayc ktphaneyi projenize eklemeniz gerekmektedir.
rnein JVM zerinde Ruby dili ile uygulama gelitirmek istiyoranz, JRuby bamlln Java
projenize eklemelisiniz.
JRuby Maven Dependency
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby</artifactId>
<version>1.7.16</version>
</dependency>

Dier listeli diller iin de benzer biimde gereken bamllk Java projenize eklenmelidir.
3

60

http://en.wikipedia.org/wiki/List_of_JVM_languages

Java Scripting API

Fakat, JavaScript programlama dili iin olay biraz farkl bir durumda. nk, Java 7
Rhino, Java 8 ise Nashorn isimli JavaScript motorlarn gml olarak JVM ierisinde
bulundurmaktadr. Bu Java ekosisteminin JavaScript diline ne kadar nem verdiini ayrca
gstermektedir.

10.2. Java Scripting API


Java programlama dili, tm bu listeli dilleri koturabilmek iin ortak arayzlerin bulunduu
4
bir API sunmaktadr. Java Scripting API bileenleri javax.script paketi ierisinde
bulunmaktadr.
javax.script paketi olduka basit arayz ve snflar iermektedir.Bunlardan en nemlisi
ScriptEngine arayzdr.

10.3. ScriptEngine
ScriptEngine trnden nesneler, ScriptEngineManager#getEngineByName metodu
zerinden esiz bir takma isim ile elde edilmektedir. Bu nesneler ile, String trnden
kod bloklar koturulabilmekte, ayrca Java ile iletiim kurulabilmektedir. rnein, Nashorn
JavaScript motoru iin "nashorn" veya "rhino" takma adlar, Ruby iin ise "jruby"
takma ad kullanlmaktadr.
rnein;
...
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
ScriptEngine engine = engineManager.getEngineByName("rhino");
ScriptEngine engine = engineManager.getEngineByName("jruby");
ScriptEngine engine = engineManager.getEngineByName("jython");
...

Java 8 iin JavaScript motoru


Java 7 iin JavaScript motoru
Ruby iin JRuby motoru
Python iin Jython motoru
4

http://docs.oracle.com/javase/8/docs/api/javax/script/package-summary.html

61

Nashorn JavaScript Motoru

10.4. Nashorn JavaScript Motoru


Nashorn, Java 8 iin zel olarak sfrdan gelitirilen bir JavaScript motorudur. Nashorn, Rhino
JavaScript motoruna gre 5 kat daha fazla performans sunmaktadr.
Nashorn JavaScript motoru EcmaScript 5 standardn desteklemekte ve tm testlerini
baaryla gemi bulunmaktadr.
JVM dillerinden Java Scripting API destekleyenler, ScriptEngine#eval metodu ile kod
bloklarn koturma imkan elde etmektedir. Bu sayede ortak arayz bileenleri zerinden Java
harici diller JVM zerinde koturulabilmektedir.
Nashorn Engine rnei
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
engine.eval("function topla(a,b){ return a + b; }");
String sonuc=(String)engine.eval(topla(3,5););
System.out.println(sonuc); // 8

Nashorn Engine elde ediliyor.


topla isimli JavaScript fonksiyonu tanmlanyor.
topla fonksiyonu Nashorn ile koturuluyor, ve sonucu elde ediliyor.
Siz de Java Scripting API destekleyen dier dilleri JVM ekosisteminde koturabilirsiniz.
Tekrar grmek dileiyle..

62

Blm 11. Java 8 Optional Yenilii


Bir Java gelitiricisinin korkulu ryas NullPointerException istisnalaryla uramaktr.
null deer ile karlamak, ona kar nlem almak herzaman iin can skc olmutur. Bu can
skcl ortadan kaldrmak iin Java 8 ierisinde Optional snf getirilmitir. Optional
yaps daha evvelden farkl dil ortamlarnda bulunan bir zelliktir.
Optional trnden nesneler, null olma ihtimali olan alanlar kolay ynetmek iin
oluturulmutur.

11.1. Optional Oluturmak


Bir Optional nesnesi, Optional snfnn eitli statik metodlaryla oluturulmaktadr.
Bunlar empty , of ve ofNullable 'dir.
empty
Taze bir Optional nesnesi oluturur.
of
Bir nesneyi Optinal ile sarmalar. Parametre olarak null deer kabul etmez.
ofNullable
Bir nesneyi Optinal ile sarmalar. Parametre olarak null deer kabul eder.
rnein

Optional<Double> empty = Optional.empty();


Optional<String> of = Optional.of("Merhaba Dnya");
Optional<String> ofNull = Optional.of(null);
Optional<Integer> ofNullable = Optional.ofNullable(null);

Deer iermeyen Opt


String trnden deer ieren Opt
Optional#of null kabul etmez. stisna frlatr.
Optional#ofNullable null kabul eder. stisna frlatmaz.

63

#ifPresent - Varsa
yap, yoksa yapma

11.2. #ifPresent - Varsa yap, yoksa yapma


Eer bir Optional ierisinde sadece veri varsa ( null deilse) bir iin yaplmas isteniyorsa
#ifPresent metodu kullanlabilir. #ifPresent metodu Consumer<T> fonksiyonel
arayz trnden bir nesne kabul etmektedir.
rnein bir saynn karesini almaya alalm. Kullanlan deiken null deerini referans
ediyorsa NullPointerException istisnas alnacaktr.
Integer numara = null;
Double karesi = Math.pow(numara , 2);
System.out.println("Sonu: " + karesi);

Exception in thread "main" java.lang.NullPointerException


Bu istisna iin if deyimiyle kar nlem alnabilir.
Integer numara = null;
if(numara != null) {
Double karesi = Math.pow(numara , 2);
System.out.println("Sonu: " + karesi);
}

Fakat if deyimiyle birlikte ! , == , != ifadelerini kullanmak akc bir gelitirim


deneyimi sunmaz. Ayrca bu durum hata yaplmasna daha aktr. Bunun yerine
Optional#ifPresent metodunu kullanabiliriz.
Integer numara = null;
Optional<Integer> opt = Optional.ofNullable(numara);
opt.ifPresent(num -> {
Double karesi = Math.pow(num , 2);
System.out.println("Sonu: " + karesi);
});

64

#map - Dntrme

11.3. #map - Dntrme


Optional nesnelerinin sarmalad veriler zerinde dntrm yaplabilmektedir. Bir
nceki rnei bu ekilde yeniden yazabiliriz.
Integer numara = null;
Optional<Integer> opt = Optional.ofNullable(numara);
opt
.map(num->Math.pow(num,2))
.ifPresent(System.out::println);

11.4. #filter - Filtreleme


Optional nesnelerinin sarmalad veriler zerinde szme ilemi de yaplabilmektedir.
rnein aadaki kod paras yerine;
String message = null;
if (message != null)
if (message.length() > 5)
System.out.println(message);

Aadaki Optional karln kullanabiliriz.


String message = null;
Optional<String> opt = Optional.ofNullable(message);
opt
.filter(m -> m.length() > 5)
.ifPresent(System.out::println);

11.5. #orElse - Varsa al, yoksa bunu al


orElse metodu daha ok ternary ( l ) art ihtiyac olduu durumlarda ihtiya duyulabilir.
Daha akc bir gelitirim deneyimi sunar.
numara null deilse numaray dndr, null ise 0 dndr.
Integer numara = null;

65

#orElseGet - Varsa
al, yoksa ret

int result = (numara != null) ? numara : 0;

Yukardaki l art orElse ile birlikte kullanabiliriz.


Integer numara = null;
Optional<Integer> opt = Optional.ofNullable(numara);
int result = opt.orElse(0);

11.6. #orElseGet - Varsa al, yoksa ret


Bu metod orElse metoduna ok benzer, fakat orElseGet metod parametresi olarak
Supplier fonksiyonel arayz trnden nesne kabul eder.
List<String> names = Arrays.asList("Ali","Veli","Selami");
Optional<List<String>> opt = Optional.ofNullable(names);
names = opt.orElseGet(()-> new ArrayList());
names = opt.orElseGet(ArrayList::new);

Lambda ile
Metod referans ile

11.7. #orElseThrow - Varsa al, yoksa frlat


Optional nesnesi bir deeri ieriyorsa ( null olmayan) o deeri dndrr, null ise de
salanan istisna nesnesini frlatr. orElseThrow metodu Supplier trnden bir nesne
kabul eder.
Integer numara = null;
Optional<Integer> opt = Optional.ofNullable(numara);
int result = opt.orElseThrow(RuntimeException::new);

Varsa dndrr, yoksa yeni bir RuntimeException istisnas frlatr.

66

#orElseThrow Varsa al, yoksa frlat


1

Java 8 yeniliklerini Java 8 Ebook ile renebilirsiniz.


Tekrar grmek dileiyle.

http://kodcu.com/java-8-ebook/

67

68

Blm 12. Java 8 Embedded


Java 8 Embedded, Java alma ortamn (JRE), snrl bellek imkanlarna sahip gml
cihazlarda, az bellek tketimli olarak sunmay amalayan dncenin rndr.
Java alma ortam, farkl ilemci ailesi ve farkl iletim sistemi ailelerine gre ayrca
hazrland iin platform bamszln sunmaktadr. rnein bugn x86 mimarili bir ilemci
iin Windows , Mac ve Linux trevi iletim sistemlerinde hem alma ortamn hem
gelitirme ortamn kullanabiliyoruz. Ha keza, ARM 6/7 ilemci ailesine sahip makinelerde
Java alma (JRE) ve gelitirme ortamn (JDK) kullanabiliyoruz.
Gml sistemlerde ARM mimarili ilemciler ok fazla tercih ediliyor. rnein elinizdeki akll
telefonun ARM ailesinden bir ilemci olma olasl ok ok yksek. Poplerlii olduka yksek
olan bir gml cihaz Raspberry PI' de ARM ailesinden bir ilemci kullanyor.

ekil 12.1. Raspberry PI


Gml cihazlarn kendine has snrllklar bulunuyor. Bu snrllklarn en banda ise bellek
snrll geliyor. ARM ilemci ailesine gre yaplandrlm full bir JRE, disk ortamnda yaklak
olarak 47 mb yer tutuyor. 47 MB gze ok gzkmeyebilir, ama, rnein 64 MB bir bellee
sahip gml cihaz iin 47 MB ok fazla! te tam da bu noktada Java 8 Embedded devreye
giriyor.
Java 8 Embedded, Java alma ortamn (JRE), gml cihazlar iin ksmi modlerlik ile
boyut olarak drmeyi amalamaktadr. Bu amala Java 8 Embedded gelitirim ihtiyalarna
gre 3 tip JRE profili sunmaktadr. Bir de full profili katarsak toplamda 4 profil var.

69

Java 8 Embedded, compact 1 , compact 2 ve compact 3 profillerini sunmaktadr.


Bu profillerde, en ok ihtiya duyulabilecek spesifik Java paketleri gruplandrlarak boyut
bakmndan klme salanmaktadr.
Buna ilaveten, standart bir JRE iin iki JVM modu bulunmaktadr. Bunlar client ve
server mode dur. Bu iki seenekte alma ortamna gre JIT Compiler baznda
ayrtrma yaplmaktadr. Java 8 Embedded iin ise varsaylan olarak client ve server
modu haricinde minimal modu gelmektedir. minimal modda bellek tketimi minimize
edilmektedir. Fakat bu modda azami %5 'lik bir performans dm makul karlanmaktadr.
Birbirini ierir biimde yaplandrlan Compact profiller, sk tercih edilecei dnlen
paketler baznda gruplandrlmtr. Bu gruplamay aadaki ekilden grebilmekteyiz.

ekil 12.2. Full JRE > compact 3 > compact 2 > compact 1
rnein gml sisteminizde en temel Java paketlerini kullanacaksanz compact 1 profilini
semek size avantaj salayacaktr. compact 1 profilinde hazrlanan JRE yaklak 9.5
MBdir. Profiller aras boyutsal kyaslamaya dair grafii aada gryoruz.

70

JavaFX Extension

ekil 12.3. Compact profile karlatrmalar

12.1. JavaFX Extension


JavaFX eklentisi kullanldnda, gml cihaznzda JavaFX kullanmak iin gerekli paketler
Embedded JRE iine dahil edilmektedir. Elbette, oluan ktlarn boyutlar artmaktadr
(Yaklak 10M kadar daha).

> jrecreate -p compact1 -x fx:controls --dest ejdk-compact1-javafx


> jrecreate -p compact2 -x fx:controls --dest ejdk-compact2-javafx
> jrecreate -p compact3 -x fx:controls --dest ejdk-compact3-javafx

ejdk-compact1-javafx dizininde compact1 profilli JavaFX ieren JRE oluturur.


ejdk-compact2-javafx dizininde compact2 profilli JavaFX ieren JRE oluturur.
ejdk-compact3-javafx dizininde compact3 profilli JavaFX ieren JRE oluturur.

71

Nashorn Extension

ekil 12.4. Compact profile karlatrmalar (JavaFX dahil)

12.2. Nashorn Extension


Java 8 ile birlikte gelen Nashorn JavaScript motoru, bir eklenti olarak rettiiniz ejre iine
dahil edilebilmektedir. Bu sayee JVM iinde JavaScript dilinde yazlan uygulamalar altrma
imkan elde edilmektedir. Nashorn eklentisi ejre ktsna yaklak 1MB ilave etmektedir.
> jrecreate -p compact1 -x nashorn --dest ejdk-compact1-nashorn
> jrecreate -p compact2 -x nashorn --dest ejdk-compact2-nashorn
> jrecreate -p compact3 -x nashorn --dest ejdk-compact3-nashorn

ejdk-compact1-nashorn dizininde compact1 profilli Nashorn ieren JRE


oluturur.
ejdk-compact2-nashorn dizininde compact2 profilli Nashorn ieren JRE
oluturur.
ejdk-compact3-nashorn dizininde compact3 profilli Nashorn ieren JRE
oluturur.
-x parametresiyle JavaFX eklentisi belirtildiinde, JavaFX retilen
JRE iine dahil edilmektedir. -x parametresi fx:controls ,
sunec , sunpkcs11 , locales , charsets , nashorn deerlerini
kabul etmektedir. Birden fazlasn ayn anda kullanmak iin ( , )
kullanlabilmektedir.

12.3. Java 8 ME vs Java 8 Embedded


Java Me ile Java Embeddedin birbirine kartrlmas olduka olas. Java ME, gml
cihazlarda Java sanal makinesinin (JVM) ok ok kk bellek tketerek almasna olanak

72

Java 8 ME vs
Java 8 Embedded
salayan zel bir Java alma ortamdr. Java 8 Me ile gml cihazlarn donanmsal
birimlerini kontrol etmek mmkndr. rnein bir gml cihazn giri/k pinlerini,
Watchdog Timer gibi bileenlerini kullanabilirsiniz. Java ME iinde bunlar kullanabilmek iin
zel paket ve snflar yer almaktadr.
Tekrar grmek dileiyle.

73

74

Blm 13. CompletableFuture ile


Asenkron Programlama
CompletableFuture snf, Java 8 ierisinde asenkron operasyonlar iin zelletirilen bir
snftr. Java ortamnda Java SE ve Java EE teknolojilerinde bir ok asenkron programlama
imkan halihazrda gelitiricilere sunulmaktadr. CompletableFuture snf ise, asenkron
programla ihtiyalarna ok daha genel zmler getirmektedir.

13.1. Syncronous vs. Asyncronous


Eer bir uygulamann aknda, bir grevin balamas dier grevin bitiine bal ise,
buna senkron programlama; Eer bir grevin balamas dier grevin balamasna engel
olmuyorsa da asenkron programlama kavramlar ortaya kmaktadr. Java programlama dili
asenkron programlamaya ou noktada imkan salamakla birlikte, dilin genel yatknl ou
dil gibi senkron programlama ynndedir. Fakat, rnein JavaScript gibi bir dili incelediinizde,
asenkronitinin dilin diyaznn ne derece etkilediini gzlemleyebilirsiniz.
rnein, elimizde fetchFromDatabase ve saveFiles metodlar olduunu varsayalm.
lk metodun koturulma sresi 5, dierinin ise 3 saniye alyor olsun.
private List<String> fetchFromDatabase(){
...
Thread.sleep(5000);
...
}
private List<byte[]> readFiles(){
...
Thread.sleep(3000);
...
}

imdi bu iki metodu peisra koturalm.


fetchFromDatabase();
readFiles();

Bu iki grevin tamamlanma sresi ne kadar olacak?

75

Syncronous vs. Asyncronous

Cevap: Math.sum(5,3) = 8
Java dilinin genel doas gerei bu iki i srasyla iletilecektir. Fakat dikkat edilirse, yaplan iki
i birbirinden tamamen bamszdr. Biri DBden veri ekiyor, dieri ise dosyalama sisteminden
dosya okuyor. Dolaysyla, bu ilerden birinin balamas iin dier iin tamamlanmas
beklenmek zorunda deil.
Bu iki metodun asenkron olarak almas iin geleneksel okilemcikli programlama ile
harici asenkron i kollar oluturulabilir. Fakat, burada geleneksel yntemlerin dnda
CompletableFuture nesnesi zerinden gitmekte fayda gryorum.
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
...
}

CompletableFuture snf Future ve CompletionStage arayzleri trnden jenerik


bir snf. CompletableFuture trnden nesneler, nesnenin yaplandrcs zerinden veya
CompletableFuture 'nin eitli statik metodlaryla oluturulabilmektedir.
CompletableFuture ile doas senkron komak olan bir ii, asenkron koar hale
getirebilirsiniz. Aslnda yaplan i, senkron koan iin arka plana itilerek koturulmas ve
mevcut program aknn kesintiye uratlmamasdr. CompletableFuture nesneleri,
ekstra olarak tanmlanmad srece tek bir ForkJoin Thread havuzu ile ilerini asenkron
olarak arka planda koturmaktadr.
imdi
yukardaki
senkron
rnei
asenkron
CompletableFuture#runAsync metodu kullanlabilir.

hale

getirelim.

Bunun

iin

public static CompletableFuture<Void> runAsync(Runnable runnable) {


...
return f;
}

CompletableFuture#runAsync metodu Runnable trnden bir grev snf kabul


etmektedir, arndan CompletableFuture trnden bir nesne dndrmektedir. Parametre olarak
iletilen Runnable nesnesi, arkaplanda asenkron olarak koturulmaktadr.
Runnable arayz tek bir soyut metoda sahip olduu iin, Lambda
fonksiyonu olarak temsil edilebilir. () { }

76

CompletableFuture#allOf

CompletableFuture<Void> futured1 = CompletableFuture.runAsync(() -> {


fetchFromDatabase();
});
CompletableFuture<Void> futured2 = CompletableFuture.runAsync(() -> {
saveToFile();
});
futured1.join();
futured2.join();

Yukardaki (1) ve (2) numaral iler bu noktadan sonra arkaplanda ForkJoin thread havuzu
iinde koturulmu olacak. Bylece (2) numaral i, (1) numaral i koturulmaya balatldktan
hemen sonra almaya balayacak, dierinin ie koyulmasn bloke etmeyecek.
Peki imdi bu iki asenkron grevin tamamlanma sresi ne kadar olacak?
Cevap: Math.max(5,3) = 5
Burada iki i birden hemen hemen ayn anda balayaca iin, iki iin toplamda tamamlanma
sresi yaklak olarak en fazla sren grev kadar olacaktr.
CompletableFuture#join metodu, asenkron olarak koturulan
grev tamamlanana kadar, uygulama aknn mevcut satrda askda
kalmasn salar. Yani (3) ve (4) satrlarndan sonraki satrlarda,
yukardaki iki iin birden tamamlanm olduunu garanti edebiliriz.

13.2. CompletableFuture#allOf
Birden fazla CompletableFuture nesnesini birletirir. Ancak herbir i birden tamamlandnda,
CompletableFuture nesnesi tamamland bilgisine sahip olur.
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
...
}

rnein;

77

CompletableFuture#anyOf

CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {


...
Thread.sleep(5000);
...
System.out.println("lk grev tamamland..");
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
...
Thread.sleep(15000);
...
System.out.println("Dier grev tamamland..");
});
CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2);
System.out.println("Bir arada iki derede.");
allOf.join();
System.out.println("Bitti.");

Yukarda iki tane asenkron i koturulmaktadr. Bir tanesi 5, dieri ise 15 saniye srmektedir.
Eer asenkron koan uygulama aknda, bu iki i bitene kadar bir noktada beklemek
istiyorsak, CompletableFuture#allOf dan faydalanabiliriz. Uygulama aknn askda
bekletilmesi ise CompletableFuture#join metodu ile salanmaktadr.
kt
Bir arada iki derede. // 0. saniyede
lk grev tamamland.. // 5. saniyede
Dier grev tamamland.. // 15. saniyede
Bitti. // 15. saniyede

13.3. CompletableFuture#anyOf
Birden fazla CompletableFuture nesnesini birletirir. Herhangi bir grev tamamlandnda,
CompletableFuture nesnesi tamamland bilgisine sahip olur.
rnein;
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {

78

CompletableFuture#supplyAsync

...
Thread.sleep(5000);
...
System.out.println("lk grev tamamland..");
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
...
Thread.sleep(15000);
...
System.out.println("Dier grev tamamland..");
});
CompletableFuture<Void> anyOf = CompletableFuture.anyOf(future1, future2);
System.out.println("Bir arada iki derede.");
anyOf.join();
System.out.println("Bitti.");

kt
Bir arada iki derede. // 0. saniyede
lk grev tamamland.. // 5. saniyede
Bitti. // 5. saniyede
Dier grev tamamland.. // 15. saniyede

13.4. CompletableFuture#supplyAsync
CompletableFuture#supplyAsync
metodu
CompletableFuture#runAsync
metodu gibidir. Fakat koma sonucunda geriye bir sonu dndrebilmektedir. Bir i sonunda
geriye hesaplanm bir deer dndrmeye ihtiya duyulduu noktada kullanlabilir.
rnein, /var/log dizinindeki tm dosya ve klasrlerin listesini hesaplatmak istiyoruz
diyelim.
CompletableFuture<List<Path>> future = CompletableFuture.supplyAsync(() -> {
Stream<Path> list = Stream.of();
try {
list = Files.list(Paths.get("/var/log"));
} catch (IOException e) {

79

lk yol, join()
metodu kullanmak
e.printStackTrace();
}
return list.collect(Collectors.toList());
});

Bu ihtiyac Files#list metodu ile salayabiliriz. Files#list metodu tanmlanan


dizindeki tm dizin ve dosyalar bir Path listesi olarak sunmaktadr. Dizindeki dosya ve dizin
saysna gre bir sonucun elde edilmesi belirli bir zaman gerektirebilir.
CompletableFuture#supplyAsync metodu Supplier trnden bir nesne
kabul ettii iin bir Lambda fonksiyonu olarak temsil edilebilirdir. ()
T
CompletableFuturein ou metodu ilerini asenkron olarak arkaplanda koturmaktadr. Bu
sebeple mevcut uygulamann akn askda brakmamaktadr.
Bir CompletableFuturein i bitimindeki sonucunu elde etmenin iki yntemi bulunmaktadr.

13.5. lk yol, join() metodu kullanmak


join() metodu, asenkron olarak iletilen grev tamamlanana kadar uygulama akn
askda tutmaktadr. tamamlandnda ise varsa sonu deerini dndrmektedir.

CompletableFuture<List<Path>> future = CompletableFuture.supplyAsync(() -> {


Stream<Path> list = Stream.of();
try {
list = Files.list(Paths.get("/var/log"));
} catch (IOException e) {
e.printStackTrace();
}
return list.collect(Collectors.toList());
});

// Varsa dier iler bu arada yaplabilir

List<Path> liste = future.join();

80

kinci yol, thenAccept*


metodu kullanmak

// join() tamamlanana kadar buraya eriim devam etmez

bitiminde elde edilen sonu listesi

13.6. kinci yol, thenAccept* metodu kullanmak


thenAccept metodu ile callback stilinde asenkron ilerin sonular elde edilebilir.
thenAccept metodu Consumer<T> trnden bir nesne kabul etmekte ve sonucu onun
zerinden sunmaktadr.
CompletableFuture<List<Path>> future = CompletableFuture.supplyAsync(() -> {
Stream<Path> list = Stream.of();
try {
list = Files.list(Paths.get("/var/log"));
} catch (IOException e) {
e.printStackTrace();
}
return list.collect(Collectors.toList());
});
future.thenAccept( (List<Path> paths) -> {
// liste burada
});

Yukardaki thenAccept ile, CompletableFuture nesnesine bir hook tanmlanm olur.


bitiminde sonu elde edildii zaman bu metod otomatik olarak iletilir. Sonu parametre olarak
gelitiriciye sunulur.

13.7. CompletableFuture#runAfterBoth*
ki asenkron i birden tamamlandnda bir Runnable trnden nesneyi koturmay salar.
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();

81

CompletableFuture#runAfterEither*

}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
return 10;
});
future1.runAfterBoth(future2,()->{
System.out.println("kisi birden bitti"); // 5. saniyede
});

13.8. CompletableFuture#runAfterEither*
ki asenkron iden herhangi biri tamamlandnda bir Runnable trnden nesneyi
koturmay salar.
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
return 10;
});
future1.runAfterEither(future2,()->{
System.out.println("kisinden biri tamamland.."); // 0. saniyede
});

13.9. CompletableFuture#handle*
CompletableFuture#handleAsync
metodu
bir
nceki
asenkron
grevin
sonucunu ilemek ve ardndaki grevlere paslamak iin yaplandrlmtr.
CompletableFuture#handleAsync ile, birbirini besleyen zincirler eklinde asenkron i
aklar yazlabilir.
rnein, iki asenkron iten birini, dierini besler eklinde yaplandralm.
Grev 1
Asenkron olarak bir dizindeki tm dosya ve dizinler bulunsun

82

CompletableFuture#handle*

Grev 2
Bulunan dizinlerin boyut bilgisi asenkron olarak hesaplansn
Grev 3
Dosya yolu ve boyut bilgisi asenkron olarak listelensin.

CompletableFuture.supplyAsync(() -> {
Stream<Path> list = Stream.of();
try {
list = Files.list(Paths.get("/var/log"));
} catch (IOException e) {
throw new RuntimeException(e);
}
return list.collect(Collectors.toList());
}).handleAsync((paths, throwable) -> {
Map<Path, Long> pathSizeMap = new HashMap<>();
try {
for (Path path : paths) {
long size = Files.size(path);
pathSizeMap.put(path, size);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return pathSizeMap;
}).thenAccept(map -> {
for (Map.Entry<Path, Long> entry : map.entrySet()) {
System.out.printf("%s | %d bytes %n",entry.getKey(),entry.getValue());
}
});

Dosya ve dizinleri liste olarak dndrr


Elde ettii listeden her bir dizinin boyutunu hesaplar, bir Map nesnesi olarak sunar.
En son retilen Map nesnesinden dosya yolu ve boyutunu birbir ktlar.

83

CompletableFuture#handle*

CompletableFuture snfnn Javada asenkron programlamay hi olmad kadar


kolaylatrdn syleyebilirim.
Tekrar grmek dileiyle.

84

Blm 14. Java ME 8 Embedded ve


Raspberry PI
Gml sistem teknolojilerinde hi phesiz Raspberry PI nemli bir r at. Boyutunun
kk ama zelliklerinin ok olduu bu kk elektronik board, gml sistemlere olan ilgi ve
alakay da arttrd.
Gml sistemler tarafnda byle bir durum var iken, Java tarafnda da Java programlama dili
ve ortamnn 8. versiyonu Java SE 8 piyasaya srld. Java ME (Mobile Edition) ise,
uzunca bir sredir suskundu. Fakat getiimiz gnlerde Java ME 8 srm Oracle tarafnda
1
yaynland. (Bkz. java-me-8-released ) Bu srm ile artk, Raspberry PI gibi eitli gml
sistem aygtlarnda Java ME 8 kullanlabilmektedir.
u anda Java ME 8in destekledii platformlar aadaki gibidir;
Raspberry Pi Model B on Debian Linux
Freescale FRDM-K64F on mbed
Qualcomm IoE platform based on QSC6270T and Brew MP
Java ME 8, gml cihazlarda dk bellek tketimi ve gml sistemlere odakl gelitirilmi
eitli APIleri ile karmza kyor. Bunlar;
JSON API
Async HTTP API
OAuth 2.0 API
JSR 75 ( File Connection API)
JSR 120 ( Wireless Messaging API)
JSR 172 ( Web Services API)
JSR 177 (Security and Trust Services API)
JSR 179 (Location API)
1

https://terrencebarr.wordpress.com/2014/04/30/java-me-8-released/

85

Java ME 8 ile Raspberry


PI zerinde LED yakma
JSR 280 ( XML API)
Ayrca Java ME ile altnz gml sistemin donanmsal birimlerini ynetebiliyoruz.
rnein; GPIO , I2C , SPI , UART

14.1. Java ME 8 ile Raspberry PI zerinde LED yakma


Bir programlama dili retilirken genelde ilk adm Hello

World ifadesini konsola

ktlamaktr. Gml sistemlerin Hello World ' ise, bir LEDi yakmaktr. Biraz daha
detaylandrrsak, cihazn GPIO (Genel amal giri k) pinlerini ynetmektir.
Gml sistemlerde genel olarak bir pin, hem giri hem de k olarak kullanlabilmektedir.
ahsm Raspberry PI Model B Revision 1 sahibiyim ve onda 8 adet GPIO pini
bulunuyor. Bu pinleri hem giri, hem de k olarak kullanabilmekteyiz.

14.2. Donanmsal Gereksinimler


Yapacamz uygulamada, merkezde Raspberry PI olmak zere eitli donanmsal aragerece ihtiyacmz olacak. Bunlar aadaki gibi detaylandrabiliriz;

14.2.1. Raspberry PI
Raspberry PI Model B (Revision 1 veya Revision 2). Bende eski olan Revision 1 bulunuyor.
Revision 2de GPIO pin saysnn daha fazla olduunu ve birka ufak deiikliin olduunu
2
gryorum (Bkz. upcoming-board-revision ).
3

Henz Raspberry PIniz yok ise, Farnell veya RS Components gibi firmalardan elde
edebilirsiniz. 75 gmrk snrn amad iin en uygun elde etme biimi bu. Fakat
4
robotistan gibi yerli giriimlerden elde etmekte mmkn.

14.2.2. Bread Board


Bread board, elektronik devreleri kolay bir biimde kurabilmek ve test edebilmek iin retilmi
basit ama nemli bir ara.

2
http://www.raspberrypi.org/upcoming-board-revision/
3
http://uk.rs-online.com/web/p/processor-microcontroller-development-kits/8111284/
4
http://www.robotistan.com/

86

SD Kart

ekil 14.1. Bread Board


Aslnda olay ok basit, kenarlarda ikier adet boylu boyunca uzanan 4 hat bulunyor. Ortada
ise, ikiye blnm enlemesine uzanan hatlar var. Hatlar zerindeki noktalarda ise, kablo, pin,
led, buton gibi bileenleri yerletirip, karabileceiniz delikler bulunuyor. Yani ierisi yle;

ekil 14.2. Bread Board hatlar

14.2.3. SD Kart
Raspberry PIyi satn aldmda SD Kart yannda gelmiti, fakat uan bu uygulama yaplyor
mu bilmiyorum. letim sisteminin kurulmas iin SD kart gerekmektedir.

14.2.4. Adaptr
5V kl microusb adaptr tercih edebilirsiniz.

14.2.5. Wifi adapter


Raspberry PIde ethernet girii bulunuyor fakat, alma ortamnzda kablonuz yok ise bir mini
5
wifi bileeni almak en iyi zm olacaktr.
5

http://www.ebay.com/itm/Mini-Wireless-USB-WiFi-Dongle-Adapter-for-Raspberry-Pi-802-11-b-gn-150Mbps-/191193467885?pt=AU_Components&hash=item2c8404cbed

87

Kablo, Led, GPIO


Extension Board

14.2.6. Kablo, Led, GPIO Extension Board


Bu gereleri Ebay zerinden toplu olarak elde etmi idim. Raspberry PI Starter Kit

http://www.ebay.com/itm/GPIO-Electronics-Starter-Kit-for-Raspberry-Pi-LCD-IR-SwitchDS18B20-/151285843554?pt=LH_DefaultDomain_15&hash=item233956c662

88

HDMI Kablosu

Ebay ile uzakdou lkeleri zerinden verilen sipariler yaklak 15-30


gn arasnda ulamaktadr.

14.2.7. HDMI Kablosu


Raspberry PI zerinde HDMI k bulunmaktadr. Ben HDMI destekli bir televizyon kullandm.
7
Bu maksatla 2 metrelik bir HDMI kablosu almay tercih ettim.

14.2.8. Klavye ve Maus


USB destekli bir klavye ve maus olmaldr.

14.3. Yazlmsal Gereksinimler


Java ME 8 ile balarken Netbeans veya Eclipse IDElerini kullanabiliriz. Bir anti-eclipser olarak
Netbeans kullanmay tercih ettim :)
7

http://www.ebay.com/itm/2M-Gold-Plated-Connection-HDMI-CableV1-4-HD-1080P-for-LCD-DVD-HDTV-Samsung-PS3-/151326918511?
pt=UK_Computing_Sound_Vision_Video_Cables_Adapters&hash=item233bc9876f

89

Yazlmsal Gereksinimler

Java ME 8 SDK
8
Java ME 8 SDKyi uanlk sadece Windows ortamnda kullanabiliyoruz. Java ME SDK
'y bu adresten edinerek sistemimize kurabiliriz.
Java ME 8 Plugin (Netbeans veya Eclipse)
9
Java ME SDK Plugins sayfasndan Java ME SDK Plugins for NetBeans
indiriyoruz. ndirdiimiz, zip dosyasn bir istediimiz bir dizine ayklayp, iindeki .npm
uzantl eklentilerin hepsini yklyoruz.
Tools > Plugins > Downloaded

ekil 14.3. Java ME 8 SDK Netbeans Pluginin Kurulmas


Java ME 8 Embedded
10
Raspberry PI zerine kurmak zere yaklak 3.5 MBlik Java ME 8 Embedded '
indiriyoruz. ( Not: Birazdan kurulumundan bahsedeceiz.)

http://www.oracle.com/technetwork/java/embedded/javame/javame-sdk/downloads/
javamesdkdownloads-2166598.html
9
http://www.oracle.com/technetwork/java/embedded/javame/javame-sdk/downloads/
javamesdkdownloads-2166598.html
10
http://www.oracle.com/technetwork/java/embedded/javame/embed-me/downloads/java-embedded-java-medownload-2162242.html

90

Raspbian OS Kurulmas

14.4. Raspbian OS Kurulmas


lk i olarak, Raspberry PI SD kart zerine, Debian tabanl bir iletim sistemi (Raspian)
11
kurulmaldr. http://www.raspberrypi.org/downloads/ sayfasndan indirilerek talimatlar ile
kurulmaldr. Sonrasnda ise, network balants salanmaldr.

14.4.1. Devrenin Kurulmas


Raspberry PInin tm portlarn bread board ile entegre etmek iin, GPIO extension kiti ve ara
kablosu kullanmak kolaylk salayacaktr.

ekil 14.4. GPIO Extension kablosunun Raspiye taklmas


Sonrasnda ise GPIO extension kiti kablonun teki ucuyla beraber bread boarda taklmaldr.

11

http://www.raspberrypi.org/documentation/installation/installing-images/

91

Devrenin Kurulmas

ekil 14.5. GPIO Extensionin bread boarda taklmas


Sonrasnda, bir LEDin katot (-) ucu bir diren ile birlikte, bread board zerindeki mavi (toprak)
hattna balanmaldr. Burada Starter Kit iinden kan 560 ohm luk direnci kullandk.

ekil 14.6. Diren ve LEDin taklmas


Bir sonraki aamada ise LEDin anod (+) ucuyla, P0-P7 aras portlardan herhangi birisini, bir
kablo ile birletiriyoruz. Bu uygulamada P5 portunu tercih ettin.

92

Java ME 8in Raspberry


PIye Yklenmesi

ekil 14.7. LED ve portun birbirine balanmas


Bu aamada devrenin kurulmas tamamlanm oluyor.

14.5. Java ME 8in Raspberry PIye Yklenmesi


Raspberry PIye bir Network balants ile ilikilendirdikten sonra, altmz
makineden Raspiye bir SSH balants kurarak tm ihtiyalarmz alma makinamiden
gerekletirebiliriz.
Raspberry PI ile SSH balants kurarken ve Raspberry PIye Java ME 8i transfer ederken
eitli Linux aralarna ihtiya duymaktayz. Gereken Linux komutlarn Windows ortamnda
kullanabilmek iin gnuwin32 projesinden faydalanabiliriz.
gnuwin32

12

indirilir.

ndirilen .exe bir dizine ayklanr.


Ayklanlan dizine konsoldan geilir ve download.bat altrlr.
download.bat sonras install.bat altrlr. Belirli bir sre sonra ykleme
tamamlanr ve Linux komutlarn taklit eden aralar ayklanan /gnuwin32/bin dizininde
belirir.

12

http://sourceforge.net/projects/getgnuwin32/files/

93

Java ME 8in Raspberry


PIye Yklenmesi

ekil 14.8. Gnuwin32 Linux Aralar


Bu dizin iindeki tm aralara, her konsol dizininden eriebilmek iin /bin dizini Environment
Variables (Sistem deikenleri) a eklenir.
Ardndan gnuwin32 iindeki scp aracyla Java MEyi Raspiye gndeririz.

$ cd /Downloads
$ scp oracle-jmee-8-1-rr-raspberrypi-linux-bin.zip pi@192.168.2.61:/home/pi/jmee

Java ME indirilen dizine geilir.

94

Java MEnin altrlmas

scp aracyla Java ME /home/pi/jmee dizinine transfer edilir.


192.168.2.61 adresi, Raspberry PInin alm olduu IP adresidir.

14.6. Java MEnin altrlmas


Raspberry PIye gnderilen zip dosyas ayklanarak, Java ME agent altrlr. Fakat
ncesinde SSH ile Raspberry PIye balant kurulmaldr.

$ ssh pi@192.168.2.61
$ pi@192.168.2.61's password: raspberry

192.168.2.61 adresindeki pi kullanc olarak balanlyor


ifre giriliyor
SSH ile balant kurduktan snra Java MEyi ayklayp altrabiliriz.

$ cd /home/pi/jmee
$ unzip oracle-jmee-8-1-rr-raspberrypi-linux-bin.zip
$ cd /bin
$ sudo ./usertest.sh

/pi/home/jmee dizinine geiliyor.


zip dosyas ayklanyor.
/bin dizinine geiliyor.
usertest.sh scripti root yetkisiyle altrlyor.
Bu aamada Raspberry PI zerinde bir Java agent almaya balyor. Sonrasnda ise Java
ME SDK ierisindeki Device Manager ile Raspberry PIye uzak balant kurabiliyoruz.

14.7. Device Managera Rapberry PI Tantmak


Java ME SDK iinde hem emlator hem de gerek makineleri ynetebiliyoruz. Biz gerek bir
Raspberry PI cihazn yneteceimiz iin, Device Managera uzaktaki Raspiyi tantmalyz.
Device Manager arac, Java ME SDK yklediiniz dizinde /bin dizininde yer almaktadr.

95

Device Managera
Rapberry PI Tantmak

ekil 14.9. Device Manager


device-manager.exe aracn altrarak, uzaktaki Raspberry PI cihazn ona tantabiliriz.
Kltlm sistem penceresinde bulunan Device Manager 'a sa tuluyoruz ve Manage
Device Connections mensn seiyoruz.

ekil 14.10. Manage Device Connections


Ardndan Raspberry PInin alm olduu IP adresini yazarak onu alma makinemize
tantyoruz.

96

Java ME 8 Embedded
Projesinin Oluturulmas

ekil 14.11. Add Device Connection


Bu aamada, Raspberry PI zerinde Java ME 8i altrm ve sistemimize tantm oluyoruz.
imdi ise uygulamamz yazp, Raspberry PI zerinde altrabiliriz.

14.8. Java ME 8 Embedded Projesinin Oluturulmas


Java ME 8 Embedded projesini Netbeans 8.0.1 ile hazrlayacaz. Bu aamada Java ME
pluginlerinin ve Java ME SDKnin eksik olmadndan emin olmalyz.

14.8.1. Adm 1
File > New Project mens takip edilir ve Java Me Ebdedded > Java Me Ebdedded
Application seilir.

ekil 14.12. Java Me Ebdedded Application seilmesi


97

Adm 2

14.8.2. Adm 2
Proje ismi ve gerekliyse dier ksmlar dzenlenir.

ekil 14.13. Proje Ayarlar

14.8.3. Adm 3
Bu admda oluan proje gzlemlenir ve JavaMeRaspi adnda Midlet trnden bir snfn
oluturulduu grlr.

98

Uygulamann Yazlmas

ekil 14.14. Proje grnm


Midlet snf iinde startApp() ve destroyApp() adnda iki gvdesiz metod
bulunmaktadr. startApp() uygulama almaya baladnda, destroyApp() ise,
uygulama sonlandnda otomatik olarak koturulmaktadr.

14.9. Uygulamann Yazlmas


Artk projeyi oluturduumuza gre JavaMeRaspi snfn dzenleyebiliriz.
public class JavaMeRaspi extends MIDlet {
@Override
public void startApp() {
try {
start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void start() throws IOException {
GPIOPin led5 = DeviceManager.open(24);
while (true) {

99

Uygulamann Yazlmas

led5.setValue(true);
bekle(1000);
led5.setValue(false);
bekle(1000);
}
}
private void bekle(int sure) {
try {
Thread.sleep(sure);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
@Override
public void destroyApp(boolean unconditional) {
// Uygulama sonland
}
}

start(); metodu ile ak balatlyor.


Port 5 , nesnel olarak temsil ediliyor.
Sonsuz bir dng kuruluyor.
Port 5 enerjilendiriliyor. Led yanyor.
1 saniye bekleniyor.
Port 5 'in enerjisi kesiliyor.
1 saniye bekleniyor.
Tanmlanan milisaniye kadar sre bekletiyor.
Bu noktada neden Port 5 iin 24 numarasn tercih edildiini merak edebilirsiniz. Raspberry
PInin her portu iin birer numaras bulunuyor. Bunlar;
Port

Numara

GPIO0

17

GPIO1

18

GPIO2

R1:21 / R2:27

100

Projeye Aygt Tantmak

Port

Numara

GPIO3

22

GPIO4

23

GPIO5

24

GPIO6

25

GPIO7

4
R1 : Revision 1
R2 : Revision 2
13
Daha detayl pin bilgileri iin

14.10. Projeye Aygt Tantmak


Uygulama tamam, imdi Device Managera tantlan Raspiyi Netbeans projesine tantmalyz.
Bunun iin projeye sa tulayarak Properties penceresine gidiyoruz ve Platform
ksmndan EmbeddedExternalDeviceX seili olduundan emin oluyoruz.

ekil 14.15. EmbeddedExternalDeviceXin Tantlmas

13

https://projects.drogon.net/raspberry-pi/wiringpi/pins/

101

Uygulama zinlerini
Tanmlamak

14.11. Uygulama zinlerini Tanmlamak


Java ME uygulamalar gml sistem zerinde alacakken, gelitiriciden sistemin
hangi zelliklerini kullanmaya yetkin olacana dair izinleri talep etmektedir. Bu sebeple
uygulamamza iki adet izin eklemeliyiz. Bunlar;
jdk.dio.gpio.GPIOPinPermission ve jdk.dio.DeviceMgmtPermission 'dir.

ekil 14.16. jdk.dio.DeviceMgmtPermission izni veriliyor


Bu yetki cihaz ynetme yetkisi vermektedir.

102

Uygulamann altrlmas

ekil 14.17. jdk.dio.gpio.GPIOPinPermission izni veriliyor


Bu yetki ise GPIO pinlerini kontrol etme yetkisi vermektedir.
Bu iki izin verildikten sonra tm admlar tamamlam oluyoruz.

14.12. Uygulamann altrlmas


Projeye sa tulayarak Run dediimizde, 5 numaral porta balanan krmz LEDin birer
saniye arayla yanp sndn gryoruz.
Faydalanlan Kaynaklar
1. Java ME Embedded Getting Started Guide
2. RaspberryPi GPIO
3. wiringPi

14

15

16

Tekrar grmek dileiyle..

14
https://docs.oracle.com/javame/8.1/get-started-rpi/toc.htm
15
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/RaspberryPi_GPIO/RaspberryPi_GPIO.html
16
https://projects.drogon.net/raspberry-pi/wiringpi/pins

103

104

Ek A. Bu kitap nasl yazld?


Java 8 Ebook kitab ak kaynak kodlu Asciidoc Fx
2

kitap editr kullanlarak, Asciidoc

iaretleme dili ile yazlmtr.

1
http://asciidocfx.com/
2
http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/

105

106

You might also like