Programmieren lernen mit Kotlin - Grundlagen, Objektorientierung und fortgeschrittene Konzepte

Christian Kohls, Alexander Dobrynin, Florian Leonhard

Programmieren lernen mit Kotlin

Grundlagen, Objektorientierung und fortgeschrittene Konzepte

2020

524 Seiten

Format: PDF, ePUB, Online Lesen

E-Book: €  29,99

E-Book kaufen

E-Book kaufen

ISBN: 9783446467118

 

Inhalt

6

Vorwort

18

1 Einführung

20

1.1 Eine Sprache für viele Plattformen

21

1.2 Deshalb ist Kotlin so besonders

21

1.3 Darauf dürfen Sie sich freuen

22

Teil I: Konzeptioneller Aufbau von Computern und Software

24

2 Komponenten eines Computers

26

2.1 Beliebige Daten als binäre Zahlen

26

2.2 Wie Zahlen in Texte, Bilder und Animationen umgewandelt werden

29

2.3 Zahlen als ausführbarer Code

30

3 Zugriff auf den Speicher

32

3.1 Organisation des Speichers

33

3.2 Daten im Speicher und Datenverarbeitung im Prozessor

34

3.3 Heap und Stack

35

3.4 Programme als Code schreiben statt als Zahlenfolgen

35

4 Interpreter und Compiler

38

4.1 Virtuelle Maschinen, Bytecode und Maschinencode

39

4.2 Kotlin – eine Sprache, viele Plattformen

40

5 Syntax, Semantik und Pragmatik

42

5.1 Syntax

42

5.2 Semantik

43

5.3 Pragmatik

45

6 Eingabe – Verarbeitung – Ausgabe

48

7 Los geht's

50

7.1 Integrierte Entwicklungsumgebungen

51

7.2 Projekt anlegen

53

Teil II: Grundlagen des Programmierens

56

8 Anweisungen und Ausdrücke

58

8.1 Ausdrücke

59

8.1.1 Literale

60

8.1.2 Operationen

61

8.1.3 Variablen und Funktionsaufrufe

63

8.2 Evaluation von Ausdrücken

64

8.2.1 Evaluieren von Operatoren

64

8.2.2 Evaluieren von Funktionen

65

8.2.3 Evaluieren von Variablen

66

8.3 Zusammenspiel von Werten und Typen

67

8.3.1 Typprüfungen durch den Compiler

68

8.3.2 Typen als Bausteine

69

9 Basis-Datentypen

72

9.1 Numerics

73

9.2 Characters und Strings

77

9.3 Booleans

78

9.4 Arrays

79

9.5 Unit

81

9.6 Any

84

9.7 Nothing

85

9.8 Zusammenfassung

86

10 Variablen

88

10.1 Deklaration, Zuweisung und Verwendung

89

10.2 Praxisbeispiel

92

10.2.1 Relevante Informationen extrahieren

92

10.2.2 Das Problem im Code lösen

93

11 Kontrollstrukturen

96

11.1 Fallunterscheidungen mit if

96

11.1.1 if-Anweisung

96

11.1.2 if-Ausdruck

98

11.2 Pattern-Matching mit when

100

11.2.1 Interpretieren von Werten

102

11.2.2 Typüberprüfungen

103

11.2.3 Überprüfen von Wertebereichen

105

11.2.4 Abbilden von langen if-else-Blöcken

107

11.3 Wiederholung von Code mit while-Schleifen

109

11.3.1 Zählen, wie oft etwas passiert

111

11.3.2 Gameloop

112

11.4 Iterieren über Datenstrukturen mit for-Schleifen

113

11.4.1 Iteration mit Arrays

114

11.4.2 Iteration mit Ranges

115

11.4.3 Geht das alles nicht auch mit einer while-Schleife?

116

12 Funktionen

118

12.1 Top-Level- und Member-Functions

118

12.2 Funktionsaufrufe (Applikation)

119

12.3 Syntax

120

12.4 Funktionsdefinition (Deklaration)

122

12.5 Funktionen als Abstraktion

124

12.6 Scoping

125

12.7 Rekursive Funktionen

127

12.7.1 Endlose Rekursion

127

12.7.2 Terminierende Rekursion

128

12.7.3 Rekursion vs. Iteration

129

12.7.4 Von Iteration zur Rekursion

130

12.8 Shadowing von Variablen

131

12.9 Pure Funktionen und Funktionen mit Seiteneffekt

132

12.9.1 Das Schlechte an Seiteneffekten

133

12.9.2 Ohne kommen wir aber auch nicht aus

136

12.9.3 Was denn nun?

137

12.10 Die Ideen hinter Funktionaler Programmierung

138

12.11 Lambdas

139

12.12 Closures

142

12.13 Funktionen höherer Ordnung

143

12.13.1 Funktionen, die Funktionen als Parameter akzeptieren

144

12.13.2 Funktionen, die Funktionen zurückgeben

146

12.14 Zusammenfassung

153

12.15 Das war's

153

Teil III: Objektorientierte Programmierung

154

13 Was sind Objekte?

156

14 Klassen

160

14.1 Eigene Klassen definieren

160

14.2 Konstruktoren

162

14.2.1 Aufgaben des Konstruktors

164

14.2.2 Primärer Konstruktor

164

14.2.3 Parameter im Konstruktor verwenden

165

14.2.4 Initialisierungsblöcke

165

14.2.5 Klassen ohne expliziten Konstruktor

166

14.2.6 Zusätzliche Eigenschaften festlegen

166

14.2.7 Klassen mit sekundären Konstruktoren

167

14.2.8 Default Arguments

168

14.2.9 Named Arguments

169

14.3 Funktionen und Methoden

170

14.3.1 Objekte als Parameter

170

14.3.2 Methoden: Funktionen auf Objekten ausführen

171

14.3.3 Von Funktionen zu Methoden

173

14.4 Datenkapselung

175

14.4.1 Setter und Getter

176

14.4.2 Berechnete Eigenschaften

178

14.4.3 Methoden in Eigenschaften umwandeln

179

14.4.4 Sichtbarkeitsmodifikatoren

180

14.5 Spezielle Klassen

182

14.5.1 Daten-Klassen

182

14.5.2 Enum-Klassen

184

14.5.3 Singuläre Objekte

189

14.6 Verschachtelte Klassen

192

14.6.1 Statische Klassen

193

14.6.2 Lokale Klassen

194

14.6.3 Innere Klassen

195

14.6.4 Anonyme innere Objekte

197

14.7 Klassen und Objekte sind Abstraktionen

197

15 Movie Maker – Ein Simulationsspiel

200

15.1 Überlegungen zur Klassenstruktur

201

15.1.1 Eigenschaften und Methoden von Movie

202

15.1.2 Eigenschaften und Methoden von Director

203

15.1.3 Eigenschaften und Methoden von Actor

204

15.1.4 Genre als Enum

204

15.1.5 Objektstruktur

205

15.2 Von der Skizze zum Programm

206

15.2.1 Movie-Maker-Projekt anlegen

206

15.2.2 Genre implementieren

207

15.2.3 Actor und Director implementieren

207

15.2.4 Erfahrungszuwachs bei Fertigstellung eines Films

209

15.3 Komplexe Objekte zusammensetzen

210

15.3.1 Skills als eine Einheit zusammenfassen

210

15.3.2 Begleit-Objekt für Skills

211

15.3.3 Objektkomposition und Objektaggregation

212

15.3.4 Zusammensetzung der Klasse Movie

214

15.3.5 Film produzieren

216

15.3.6 Ein Objekt für Spieldaten

217

Teil IV: Vererbung und Polymorphie

220

16 Vererbung

222

16.1 Vererbungsbeziehung

223

16.2 Klassenhierarchien

225

16.3 Eigenschaften und Methoden vererben

226

17 Polymorphie

230

17.1 Überschreiben von Methoden

231

17.1.1 Eine Methode unterschiedlich überschreiben

231

17.1.2 Dynamische Bindung

232

17.1.3 Überschreiben eigener Methoden

233

17.1.4 Überladen von Methoden

235

17.2 Typen und Klassen

236

17.2.1 Obertypen und Untertypen

237

17.2.2 Generalisierung und Spezialisierung

238

17.2.3 Typkompatibilität

240

17.2.4 Upcast und Downcast

243

17.2.5 Vorsicht bei der Typinferenz

244

17.2.6 Smart Casts

245

18 Abstrakte Klassen und Schnittstellen

246

18.1 Abstrakte Klassen

246

18.2 Schnittstellen

248

18.2.1 Schnittstellen definieren

249

18.2.2 Schnittstellen implementieren

249

18.2.3 Schnittstellen für polymorphes Verhalten

250

18.2.4 Standardverhalten für Interfaces

253

18.2.5 Mehrere Interfaces implementieren

254

18.3 Alles sind Typen

255

Teil V: Robustheit

258

19 Nullfähigkeit

260

19.1 Nullfähige Typen

260

19.1.1 Typen nullfähig machen

261

19.1.2 Optional ist ein eigener Typ

261

19.2 Sicherer Zugriff auf nullfähige Typen

262

19.2.1 Überprüfen auf null

263

19.2.2 Safe Calls

263

19.2.3 Verkettung von Safe Calls

264

19.3 Nullfähige Typen auflösen

265

19.3.1 Überprüfen mit if-else

265

19.3.2 Der Elvis-Operator rockt

266

19.3.3 Erzwungenes Auflösen

266

20 Exceptions

268

20.1 Sowohl Konzept als auch eine Klasse

268

20.2 Beispiele für Exceptions

269

20.2.1 ArrayIndexOutOfBoundsException

269

20.2.2 ArithmeticException

270

20.3 Exceptions aus der Java-Bibliothek

271

20.4 Exceptions auffangen und behandeln

272

20.4.1 Schreiben in eine Datei

272

20.4.2 Metapher: Balancieren über ein Drahtseil

273

20.5 Exceptions werfen

275

20.6 Exceptions umwandeln

276

20.6.1 Von Exception zu Optional

277

20.6.2 Von Optional zu Exception

278

20.6.3 Exceptions vs. Optionals

278

20.7 Exceptions weiter werfen

279

20.8 Sinn und Zweck von Exceptions

282

21 Movie Maker als Konsolenspiel umsetzen

284

21.1 Die Gameloop

284

21.2 Einen neuen Film produzieren

286

21.3 Statistik anzeigen

289

22 Entwurfsmuster

290

22.1 Das Strategiemuster

291

22.1.1 Im Code verstreute Fallunterscheidungen mit when

291

22.1.2 Probleme des aktuellen Ansatzes

293

22.1.3 Unterschiedliche Strategien für die Ausgabe

294

22.1.4 Nutzen der Strategie

297

22.2 Das Dekorierermuster

297

22.2.1 Probleme des gewählten Ansatzes

299

22.2.2 Dekorierer für Komponenten

300

22.2.3 Umsetzung des Dekorierers

302

22.2.4 Nutzen des Dekorierers

304

22.3 Weitere Entwurfsmuster

305

23 Debugger

306

Teil VI: Datensammlungen und Collections

310

24 Überblick

312

24.1 Pair und Triple

314

24.1.1 Verwendung

314

24.1.2 Syntaktischer Zucker

315

24.1.3 Destructuring

315

24.1.4 Einsatzgebiete

315

24.2 Arrays

316

24.2.1 Direkter Datenzugriff

316

24.2.2 Arrays mit null-Referenzen

317

24.2.3 Arrays mit primitiven Daten

319

24.2.4 Arrays vs. Listen

319

24.3 Listen

320

24.3.1 Unveränderliche Listen

320

24.3.2 Veränderliche Listen

321

24.3.3 List und MutableList sind verwandte Schnittstellen

321

24.4 Sets

322

24.4.1 Sets verwenden

322

24.4.2 Mengen-Operationen

323

24.5 Maps

324

24.5.1 Maps erzeugen

324

24.5.2 Arbeiten mit Maps

325

24.5.3 Maps durchlaufen

326

25 Funktionen höherer Ordnung für Datensammlungen

330

25.1 Unterschiedliche Verarbeitung von Listen

330

25.1.1 Imperative Verarbeitung von Listen

330

25.1.2 Funktionale Verarbeitung von Listen

332

25.1.3 Funktionen als kombinierbare Arbeitsanleitungen

333

25.1.4 Aufbau von Funktionen höherer Ordnung am Beispiel von map

334

25.2 Hilfreiche Funktionen für Datensammlungen

336

25.3 Anwendungsbeispiele für Funktionen höherer Ordnung

338

25.4 Sequenzen

345

25.4.1 Eager Evaluation – viel zu fleißig

345

25.4.2 Lazy Evaluation – Daten bei Bedarf verarbeiten

345

25.4.3 Sequenzen verändern die Reihenfolge

347

25.4.4 Fleißig oder faul – was ist besser?

349

26 Invarianz, Kovarianz und Kontravarianz

350

26.1 Typsicherheit durch Typ-Parameter

350

26.1.1 Invarianz

351

26.1.2 Die Grenzen von Invarianz

352

26.1.3 Kovarianz

352

26.1.4 Kontravarianz

354

26.2 Invarianz, Kovarianz und Kontravarianz im Vergleich

356

27 Listen selbst implementieren

360

27.1 Was ist eine Liste?

360

27.1.1 Unterschiedliche Listen als konkrete Formen

361

27.1.2 Eine Schnittstelle für alle möglichen Listen

361

27.1.3 Typ-Parameter selbst definieren (Generics)

362

27.1.4 Verschiedene Implementierungen derselben Schnittstelle

363

27.2 Implementierung der SimpleList durch Delegation

364

27.3 Implementierung der SimpleList mit Arrays

365

27.3.1 Datenstruktur

365

27.3.2 Direkte Abbildung der Listen-Operationen auf ein Array

365

27.3.3 Listen-Operationen mit aufwendiger Laufzeit bei Arrays

366

28 Verkettete Listen

370

28.1 Basisstruktur der verketteten Liste

371

28.2 Implementierung der verketteten Liste

373

28.3 Umsetzung der Funktionen

373

28.3.1 Einfügen am Anfang einer verketteten Liste

373

28.3.2 Zugriff auf das erste Element der verketteten Liste

375

28.3.3 Zugriff auf das letzte Element der verketteten Liste

375

28.3.4 Allgemeines Schema zum Durchlaufen einer verketteten Liste

377

28.3.5 Elemente der verketteten Liste zählen

377

28.3.6 Zugriff auf das n-te Element

378

28.4 Über alle Listenelemente iterieren

379

28.4.1 Die Schnittstelle Iterable

380

28.4.2 Iterator implementieren

380

28.4.3 Iterator verwenden

381

28.4.4 Interne Iteration

382

29 Testen und Optimieren

384

29.1 Korrektheit von Programmen

384

29.2 Testfälle in JUnit schreiben

385

29.2.1 Assertions

386

29.2.2 Implementierung der Liste testen

386

29.3 Teste zuerst

387

29.4 Klasseninvariante

389

29.4.1 Alternative Implementierung von size() für die verkettete Liste

389

29.4.2 Gewährleistung eines gültigen Zustands

390

30 Optimierung und Laufzeiteffizienz

392

30.1 Laufzeit empirisch ermitteln

392

30.2 Laufzeit theoretisch einschätzen

393

30.3 Die O-Notation

394

30.4 Praktische Beispiele für die O-Notation

395

31 Unveränderliche verkettete Liste

396

31.1 Datenstruktur für die unveränderliche Liste

397

31.1.1 Fallunterscheidung durch dynamische Bindung

397

31.1.2 Explizite Fallunterscheidung innerhalb der Funktion

398

31.1.3 Neue Listen erzeugen statt Liste verändern

398

31.1.4 Hilfsfunktionen über Companion-Objekt bereitstellen

400

31.2 Rekursive Implementierungen

401

31.2.1 map und fold als rekursive Implementierung

401

31.2.2 forEach und Endrekursion

402

Teil VII: Android

404

32 Grundlagen

406

32.1 Erstellen eines Projekts

407

32.2 Aufbau von Android Studio

410

32.3 Funktionsweise einer Android-App

411

32.4 Projektstruktur einer Android-App

416

33 Entwicklung einer Android-App

418

33.1 Integration der Daten

418

33.2 StartActivity erstellen (manuell)

419

33.2.1 Anlegen des Layouts

419

33.2.2 Erstellen der Activity

428

33.2.3 Registrieren der Activity

429

33.3 Persistenz

430

33.3.1 Definition der Schnittstelle

431

33.3.2 Implementierung mit Shared Preferences

432

33.3.3 Zentrales Instanziieren mit Extension Functions

434

33.3.4 Zugriff auf die Datenbankinstanz

434

33.4 CreateMovieActivity erstellen (automatisiert)

435

33.4.1 Erstellen der Activity

435

33.4.2 Starten der Activity

436

33.4.3 Implementieren des Layouts

436

33.4.4 Implementieren der Activity

442

33.5 Ergebnisdialog

448

33.5.1 Erstellen des Layouts

448

33.5.2 Erstellen und Anzeigen des Dialogs

450

33.6 Letzter Feinschliff

451

Teil VIII: Nebenläufigkeit

454

34 Grundlagen

456

34.1 Threads

460

34.1.1 Nicht-determinierter Ablauf

461

34.1.2 Schwergewichtige Threads

462

34.2 Koroutinen (Coroutines)

462

34.2.1 Koroutine vs. Subroutine

463

34.2.2 Coroutines vs. Threads

464

34.3 Zusammenfassung der Konzepte

466

35 Coroutines verwenden

468

35.1 Nebenläufige Begrüßung

469

35.1.1 Koroutine im Global Scope starten

469

35.1.2 Mehrere Koroutinen nebenläufig starten

470

35.1.3 Künstliche Wartezeit einbauen mit sleep

471

35.1.4 Informationen über den aktuellen Thread

472

35.2 Blockieren und Unterbrechen

472

35.2.1 Mehrere Koroutinen innerhalb von runBlocking starten

473

35.2.2 Zusammenspiel von Threads

475

35.3 Arbeit auf Threads verteilen

475

35.4 Jobs

478

35.5 Nebenläufigkeit auf dem main-Thread

479

35.5.1 Zusammenspiel von blockierenden und unterbrechenden Abschnitten

480

35.5.2 Abwechselnde Ausführung

481

35.6 Strukturierte Nebenläufigkeit mit Coroutine Scopes

482

35.7 runBlocking für main

484

35.8 Suspending Functions

485

35.8.1 Unterbrechen und Fortsetzen – Behind the scenes

485

35.8.2 Eigene Suspending Functions schreiben

485

35.8.3 Async

487

35.8.4 Strukturierte Nebenläufigkeit mit Async

489

35.8.5 Auslagern langläufiger Berechnungen

489

35.9 Dispatcher

490

35.9.1 Dispatcher festlegen

490

35.9.2 Wichtige Dispatcher für Android

492

36 Wettlaufbedingungen

494

36.1 Beispiel: Bankkonto

494

36.1.1 Auftreten einer Wettlaufbedingung

496

36.1.2 Unplanbare Wechsel zwischen Threads

496

36.2 Vermeidung von Wettlaufbedingungen

497

36.2.1 Threadsichere Datenstrukturen

497

36.2.2 Thread-Confinement

498

36.2.3 Kritische Abschnitte

501

37 Deadlocks

504

38 Aktoren

508

39 Da geht noch mehr

512

39.1 Infix-Notation

512

39.2 Operatoren überladen

513

39.3 Scope-Funktionen

515

39.3.1 apply-Funktion

515

39.3.2 let-Funktion

516

39.3.3 also-Funktion

517

39.3.4 Unterschiede der Scope-Funktionen

517

39.3.5 with-Funktion

518

39.4 Extension Functions

518

39.5 Weitere Informationsquellen

519

Stichwortverzeichnis

522

 

© 2009-2024 ciando GmbH