-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCh8_Stocks.html
More file actions
1845 lines (1787 loc) · 99.4 KB
/
Ch8_Stocks.html
File metadata and controls
1845 lines (1787 loc) · 99.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript: Ch8 Stocks</title>
<meta name="title" content="Variations on a Theme: JavaScript: Ch8 Stocks">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="UTF-8">
<meta name="description" content="An object-oriented Introduction">
<meta name="keywords" content="JavaScript,object orientation,introduction">
<meta name="author" content="Ralph P. Lano">
<meta name="robots" content="index,follow">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="book.css">
</head>
<body>
<center>
<div id="wrap">
<ul class="sidenav">
<p><a href="../index.html">Variations on a Theme</a><a href="index.html">JavaScript</a></p>
<li><a href="Ch1_Karel.html">Karel</a></li>
<li><a href="Ch2_Graphics.html">Graphics</a></li>
<li><a href="Ch3_Console.html">Console</a></li>
<li><a href="Ch4_Agrar.html">Agrar</a></li>
<li><a href="Ch5_MindReader.html">MindReader</a></li>
<li><a href="Ch6_Swing.html">Swing</a></li>
<li><a href="Ch7_Asteroids.html">Asteroids</a></li>
<li><a href="Ch8_Stocks.html">Stocks</a></li>
<li><a href="index.html"> </a></li>
<li><a href="AppA_Primer.html">Primer</a></li>
<li><a href="AppB_Libraries.html">Libraries</a></li>
<li><a href="AppC_Ideas.html">Ideas</a></li>
</ul>
<div class="content">
<p>
<img alt="" src="img/c24f32f0-1b68-42ac-a304-5a7e04e7d05b.png" style="display: block; margin-left: auto; margin-right: auto; width: 364px; height: 307px;" /></p>
<h1>
Stocks</h1>
<p>
The book is coming to an end, which usually means it's getting interesting. We will cover such topics as files, exception handling and we will get to know our first data structures. We continue with object-oriented analysis, learn a little more about interfaces and hear about polymorphism.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/readFromFile" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/readFromFile.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
Files</h2>
<p>
As soon as we turn off the computer, all data is gone - unless it has been saved. Saved means that we wrote it to a file. This is easier than you might think, but we start with reading from a file.</p>
<p>
To read from a file we have to do three things:</p>
<ol>
<li>
open the file,</li>
<li>
read from the file, line by line, and</li>
<li>
close the file.</li>
</ol>
<p>
In code it looks like this:</p>
<pre style="margin-left: 40px;">
// open file
let fr = new <span style="color:#0000ff;">Utils.FileReader</span>(fileName);
// read from file, line by line
while (true) {
let line = <span style="color:#0000ff;">fr.readLine()</span>;
if (<span style="color:#0000ff;">line == null</span>)
break;
println(line);
}
// close file
fr.close();</pre>
<p>
We use our Utils.FileReader class to read text files. We simply pass the file name of the file to be opened. </p>
<p>
Then we simply use a Loop-And-A-Half to read line by line from the file using the readLine() method. We know that we have reached the end of the file when readLine() returns null. Then there is nothing more to read, which means we close the file reader with the close() method.</p>
<p>
A brief note on our Utils.FileReader class is in order: a browser can not directly access your file system. What the browser can do, is upload files, we see that later in the project UploadFile. What our class Utils.FileReader does is to load a file from the web server where we host our JavaScript files. Also, interesting, most of the programs we wrote up to now, do work locally from the file system without hosting. The Utils.FileReader does not, because it violate the CORS policy of your browser [8]. And a final remark, why did we not call it simply FileReader? There already exists a class in JavaScript that is called FileReader, which does not really do what you would expect of it, coming from Java. And it is a nice opportunity to show, how to handle naming conflicts in JavaScript.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/writeToFile" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/writeToFile.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
Write to File</h2>
<p>
When writing to a file we have to do three things:</p>
<ol>
<li>
open the file for writing,</li>
<li>
then write to the file, and</li>
<li>
close the file.</li>
</ol>
<p>
The code looks very similar to the one above:</p>
<pre style="margin-left: 40px;">
// open file
let fw = new <span style="color:#0000ff;">Utils.FileWriter</span>("test.txt");
// write to file, one string at a time
println("Enter text to write ('.' to quit): ");
while (true) {
let line = await readLine("");
if (line == '.')
break;
<span style="color:#0000ff;">fw.append(line + "\n");</span>
}
// close file
fw.close();</pre>
<p>
<img alt="" src="img/testTxt.png" style="margin-left: 10px; margin-right: 10px; width: 200px; height: 100px; float: right;" />We use the FileWriter class to write to text files. First we pass the file name to which we want to write. Then we use the Loop-And-A-Half again to write line by line using the method write(). The '\n' may also be interesting: it is the character for new line, and ensures that the next string in the "test.txt" file is written to a new line. To avoid getting stuck in an infinite loop, we check if the user has entered a period, this is our abort criterion. Then we close our writer with the close() method.</p>
<p>
Like not being allowed to read files, the browser also is not allowed to write files. But what the browser can do is download files. So this is what we do here, we actually download the files, and the user can then choose whether and where to store the files.</p>
<p>
.</p>
<h2>
Data Structures</h2>
<p>
Data structures are extremely important. Unfortunately, most people stop with the array data structure, which we have seen already. More important, however, is the Map data structure. JavaScript has the Array class and the Map class for these. The equivalent classes in Java are called ArrayList and HashMap. Let us briefly compare the two:</p>
<table align="center" border="0" cellpadding="10" cellspacing="10" style="width: 100%;">
<tbody>
<tr>
<td style="text-align: center; vertical-align: middle;">
<table align="center" border="0" cellpadding="1" cellspacing="1" width="200">
<tbody>
<tr>
<td>
<b>Array</b></td>
<td>
<b>ArrayList</b></td>
</tr>
<tr>
<td>
new Array()</td>
<td>
new ArrayList()</td>
</tr>
<tr>
<td>
push(value)</td>
<td>
add(value)</td>
</tr>
<tr>
<td>
at(idx)</td>
<td>
get(idx)</td>
</tr>
<tr>
<td>
includes(value)</td>
<td style="vertical-align: top;">
contains(value)</td>
</tr>
<tr>
<td>
indexOf(value)</td>
<td>
indexOf(value)</td>
</tr>
<tr>
<td>
</td>
<td>
values()</td>
</tr>
<tr>
<td>
length</td>
<td>
size()</td>
</tr>
<tr>
<td>
splice(indexOf(value),1)</td>
<td>
remove(value)</td>
</tr>
</tbody>
</table>
</td>
<td style="text-align: center; vertical-align: middle;">
<table align="center" border="0" cellpadding="1" cellspacing="1" width="200">
<tbody>
<tr>
<td style="vertical-align: top;">
<b>Map</b></td>
<td>
<b>HashMap</b></td>
</tr>
<tr>
<td>
new Map()</td>
<td>
new HashMap()</td>
</tr>
<tr>
<td>
set(key, value)</td>
<td>
put(key, value)</td>
</tr>
<tr>
<td>
get(key)</td>
<td>
get(key)</td>
</tr>
<tr>
<td>
has(key)</td>
<td>
containsKey(key)</td>
</tr>
<tr>
<td>
keys()</td>
<td>
keySet()</td>
</tr>
<tr>
<td>
values()</td>
<td>
values()</td>
</tr>
<tr>
<td>
size</td>
<td>
size()</td>
</tr>
<tr>
<td>
delete(key)</td>
<td>
remove(key)</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>
As you can see they are basically equivalent from a user point of view. I wrote little wrapper classes in the utils library, so you can choose either the Java syntax or the JavaScript syntax. The simple reason for this is, that I had all the examples written in Java, and did not want to do a complete rewrite. I was surprised that this worked so well, that I did want to show you this, because it is a very nice example of software portability [9].</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/uniqueNames" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/uniqueNames.png" style="width: 200px; height: 135px; display: block;" />Try it</a></div>
<h2>
ArrayList</h2>
<p>
Let's start by declaring and instantiating an ArrayList:</p>
<pre style="margin-left: 40px;">
let names = new ArrayList();
</pre>
<p>
Here we create an ArrayList with the name "names". An ArrayList can grow and shrink, depending on requirements. That's very practical!</p>
<p>
Next, we want to add a few names to our list of names, but only if the name is not already in the list:</p>
<pre style="margin-left: 40px;">
while (true) {
let name = await readLine("Enter new name: ");
if (name.length == '')
break;
if (!names.<span style="color:#0000ff;">contains</span>(name)) {
names.<span style="color:#0000ff;">add</span>(name);
}
}
</pre>
<p>
With the method contains() we check, if a certain name is already in the list. If not, we add it with add(). Also, we don't have to specify an index when adding, new entries are simply inserted at the end of the list.</p>
<p>
If we want to print our list of names, we have to iterate over the list:</p>
<pre style="margin-left: 40px;">
for (let i = 0; i < names.<span style="color:#0000ff;">size</span>(); i++) {
println(names.<span style="color:#0000ff;">get</span>(i));
}</pre>
<p>
With the size() method we can determine how many entries our list has, and with get() we read the entry at a certain position. Additionally, the ArrayList has the following practical methods:</p>
<ul>
<li>
<strong>set():</strong> replaces the entry at a certain position with a new one,</li>
<li>
<strong>indexOf():</strong> searches for an entry and returns the position,</li>
<li>
<strong>remove():</strong> removes an entry from the list, and</li>
<li>
<strong>clear():</strong> deletes the complete list.</li>
</ul>
<p>
But as I stated before, you can also use the equivalent JavaScript Array methods.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/phoneBook" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/phoneBook.png" style="width: 200px; height: 222px; display: block;" />Try it</a></div>
<h2>
HashMap</h2>
<p>
HashMaps are probably the most useful of all data structures: because we can use them for searching. Classic examples of hash maps are telephone books and dictionaries. Let's take a closer look at the former, the PhoneBook. We'll start with the HashMap declaration:</p>
<pre style="margin-left: 40px;">
let phoneBook = new HashMap();</pre>
<p>
A HashMap associates a value with a key, which is why it is sometimes also called an associative array.</p>
<p>
Let's add some values to our PhoneBook:</p>
<pre style="margin-left: 40px;">
while (true) {
name = await readLine("Enter name: ");
if (name == '')
break;
let number = await readInt("Enter number: ");
phoneBook.<span style="color:#0000ff;">put</span>(name, number);
}</pre>
<p>
Inserting is done with the method put(): it takes two arguments, a name and a number. If the name already exists in the map, it is overwritten, if not, it is inserted. In a HashMap there can never be two entries with the same name, keys must be unique.</p>
<p>
After we have filled our PhoneBook with some data, we want to search in it, because that's what the HashMap is good for:</p>
<pre style="margin-left: 40px;">
name = await readLine("Enter name to search: ");
if (name == '')
break;
if (phoneBook.<span style="color:#0000ff;">containsKey</span>(name)) {
println(phoneBook.<span style="color:#0000ff;">get</span>(name));
} else {
println("no entry for this name");
}</pre>
<p>
With the containsKey() method we can test if a name exists in the map, and with get() we can get the number to the name. This looks very similar to the ArrayList, but it is much cooler: with the ArrayList we have to know the index of the entry we want to access, with the HashMap we simply say: give me the phone number for that name.</p>
<p>
Just in case we want to list all phone numbers in our PhoneBook, let us iterate through our map:</p>
<pre style="margin-left: 40px;">
for (const name of phoneBook.<span style="color:#0000ff;">keySet</span>()) {
let number = phoneBook.<span style="color:#0000ff;">get</span>(name);
println(name + ": " + number);
}</pre>
<p>
This looks different: the first line seems to make no sense at all. The problem with maps is that they do not have an index, i.e. we can not say give me the second element, because a map does not know what its second element is (or at least it doesn't tell us). There is also not really any fixed ordering, i.e. the order in which the entries are output may be completely different from the order in which they were inserted.</p>
<p>
This is why the iteration uses this pseudo-for-loop trick:</p>
<pre style="margin-left: 40px;">
for (const name of phoneBook.<span style="color:#0000ff;">keySet</span>()) { ... }</pre>
<p>
It basically says: give me a name from the list of names in the map. And after that one, you give me the next one, etc. until we're all through. Once you've accepted that is how a map works, the rest is easy.</p>
<p>
.</p>
<h2>
Object-Orientierted Analysis</h2>
<p>
We are at a transition: we are just leaving the procedural one-class world and entering the object-oriented multi-class world. This transition is not entirely painless. And where the top-down approach has served us really well so far, it now only helps us on a small scale, but no longer on a larger scale.</p>
<p>
However, this is where object-oriented analysis comes to the rescue. Before we start to write any code, we first need to think about what we want. This is called requirements analysis. It is best to write the requirements down in very simple sentences. For example, the requirements for a web shop could be formulated in the following way:</p>
<p style="margin-left: 40px;">
"The Azamon Shop has articles and shopping carts. An article has a name, type and price. A shopping cart has a user name and a list of articles. We can list all the articles of the shop. We can list all the articles in a shopping cart. We can put an article in a shopping cart. We can calculate the price of all articles in a shopping cart."</p>
<p>
These requirements are the basis for our object-oriented analysis.</p>
<p>
<strong>1.Step:</strong> In the first step of this analysis we take a colored pencil and underline the verbs green and the nouns with red:</p>
<p style="margin-left: 40px;">
"The <span style="color:#ff0000;">Azamon Shop</span> <span style="color:#00ff00;">has</span> <span style="color:#ff0000;">articles</span> and <span style="color:#ff0000;">shopping carts</span>. An <span style="color:#ff0000;">article</span> <span style="color:#00ff00;">has</span> a <span style="color:#ff0000;">name</span>, <span style="color:#ff0000;">type</span> and <span style="color:#ff0000;">price</span>. A <span style="color:#ff0000;">shopping cart</span> <span style="color:#00ff00;">has</span> a <span style="color:#ff0000;">user name</span> and a list of <span style="color:#ff0000;">articles</span>. We can <span style="color:#00ff00;">list</span> all the <span style="color:#ff0000;">articles</span> of the <span style="color:#ff0000;">shop</span>. We can <span style="color:#00ff00;">list</span> all the <span style="color:#ff0000;">articles</span> in a <span style="color:#ff0000;">shopping cart</span>. We can <span style="color:#00ff00;">put</span> an <span style="color:#ff0000;">article</span> in a <span style="color:#ff0000;">shopping cart</span>. We can <span style="color:#00ff00;">calculate</span> the <span style="color:#ff0000;">price</span> of all <span style="color:#ff0000;">articles</span> in a <span style="color:#ff0000;">shopping cart</span>."</p>
<p>
<strong>2.Step:</strong> In the second step we make a list for all the verbs:</p>
<ul>
<li>
has</li>
<li>
list</li>
<li>
list</li>
<li>
put</li>
<li>
calculate</li>
</ul>
<p>
and the nouns are listed and counted:</p>
<ul>
<li>
shop: II</li>
<li>
article: IIIIIII</li>
<li>
shopping cart: IIIII</li>
<li>
name: I</li>
<li>
type: I</li>
<li>
price: II</li>
<li>
user name: I</li>
</ul>
<p>
Counting is not absolutely necessary, but helps to recognize what may be more important.</p>
<p>
<strong>3.Step:</strong> In the third step we look at the list of nouns. Which of the nouns can we describe with a simple data type like int, double, string etc.?</p>
<ul>
<li>
shop: ???</li>
<li>
article: ???</li>
<li>
shopping cart: ???</li>
<li>
name: String</li>
<li>
type: String</li>
<li>
price: int</li>
<li>
user name: String</li>
</ul>
<p>
If something is complicated, i.e. consists of other parts, such as shop, article and shopping cart, then it is a complicated data type, i.e. a class. So we have identified our classes: Shop, Article and ShoppingCart.</p>
<p>
<strong>4.Step:</strong> The fourth step is to assign the right attributes to the right classes. To do this, we simply re-read our requirements. They say:</p>
<ul>
<li>
"The Azamon Shop has articles and shopping carts": so obviously articles and shopping carts belong to the shop, are therefore attributes of the Shop.</li>
<li>
"An article has a name, a type and a price": so name, type and price are part of the Article.</li>
<li>
"A shopping cart has a user name and a list of articles": so user name and list of articles belong to the ShoppingCart.</li>
</ul>
<p>
At this point it also makes sense to pay attention to the plural: every time a word appears in the plural, this means that we need a list (or map) of the respective attributes. For example, "list of articles" or "shopping carts" then become ArrayLists.</p>
<p>
<img alt="" src="img/5e5039fa-0351-444b-b855-7fc03777b3ab.png" style="width: 221px; height: 170px; float: right;" />With this information we can already write down our classes with attributes:</p>
<pre style="margin-left: 40px;">
class Shop {
constructor() {
this.carts;
this.articles;
}
}
class Article {
constructor() {
this.name;
this.type;
this.price;
}
}
class AzamonCart {
constructor() {
this.userName;
this.articles;
}
}</pre>
<p>
<strong>5.Step:</strong> The last step is to assign the methods to the correct classes. All the verbs we collected in the second step, turn into methods (we have always said that methods are verbs). We go through our list of verbs one at a time:</p>
<ul>
<li>
has: "has" does not count as a verb, since it expresses affiliation and was already used in step 4.</li>
<li>
list: refers to "We can list all items in the shop", so it is part of the Shop and should be called listArticles().</li>
<li>
list: refers to "We can list all items in a shopping cart", so it is part of the ShoppingCart and should also be called listArticles().</li>
<li>
put: refers to "We can put an item in a shopping cart", therefore it belongs to the ShoppingCart and should be called putArticle() or addArticle().</li>
<li>
calculate: refers to "We can calculate the price of all items in a shopping cart", so it belongs to the ShoppingCart, and should be called calculatePrice().</li>
</ul>
<p>
After this analysis, our classes, their attributes and methods are basically fixed:</p>
<pre style="margin-left: 40px;">
class Shop {
constructor() {
super();
this.carts;
this.articles;
}
listArticles() {
}
}
class Article {
constructor() {
super();
this.name;
this.type;
this.price;
}
}
class Cart {
constructor() {
super();
this.userName;
this.articles;
}
listArticles() {
}
addArticleToCart() {
}
calculatePriceOfArticlesInCart() {
}
}</pre>
<p>
What we have not decided yet are the parameters the methods accept and what they return. And it never hurts to give each class a constructor. And of course a minor thing: the code is still missing.</p>
<p>
.</p>
<h2>
Errors</h2>
<p>
What if something goes wrong? Or first of all, what can go wrong? For example, look at the following two lines of code:</p>
<pre style="margin-left: 40px;">
let fritz;
fritz.setColor(Color.RED);</pre>
<p>
If you run this in the browser, nothing happens. However, if you look at the browser's console (usually with F12) you will see the following error message:</p>
<p style="margin-left: 40px;">
<img alt="" src="img/JSError.png" style="margin-left: 10px; margin-right: 10px; width: 387px; height: 98px;" /></p>
<p>
The error message says that fritz is undefined. The error is a <em>TypeError</em>. It even tells you where the problem is: at line 16 column 3 of your JavaScript file (16:3). Usually it provides a link which you can click on and it navigates you automatically to the problematic line in the code.</p>
<p>
Can anything else go wrong? Yes, many things can go wrong. Here are a couple of typical cases:</p>
<pre style="margin-left: 40px;">
// TypeError
let num = 1;
num.toUpperCase();
// RangeError
let b = new Array(-1)
// ReferenceError
let x = 3;
x = x + y;
// SyntaxError
eval("let s = 'hi");</pre>
<p>
You want the upper case version of a number, or an array with a negative size, or you are using a variable that has not been initialized, and then there can be errors in you JavaScript code itself. </p>
<p>
What happens to our program when an error occurs? Well, other programming languages just crash., but JavaScript is very cool about this: it tries to ignore the errors, and continues as if nothing had happened, kind of like my mother in law. But naturally, the results that come out will most likely be wrong or nonsense. Hence, what we should do is appropriate error handling with try-catch.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/exceptions" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/exceptions.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
Try-Catch</h2>
<p>
With a try-catch statement we first try if everything works. If it works, fine, if not, then we tell the program what to do. In code it looks like this:</p>
<pre style="margin-left: 40px;">
try {
// problematic code
...
} catch ( e ) {
// deal with error
...
}
...
</pre>
<p>
We surround our problematic code with a try block. If everything works, the program continues normally (the catch block is not executed). If something goes wrong, however, the program does not terminate, but jumps to the catch block instead and executes it. After that, the program assumes that we have everything under control and executes the code after the catch block as if nothing had happened.</p>
<p>
Interesting maybe that what would be errors in other languages, are no problem for JavaScript:</p>
<pre style="margin-left: 40px;">
// ArithmeticException
let x = 5 / 0;
console.log(x); // Infinity
// NumberFormatException
let y = parseInt("five");
console.log(y); // NaN
// ArrayIndexOutOfBoundsException
let eggs = [0, 1, 2, 3];
console.log(eggs[5]); // undefined</pre>
<h3>
throw</h3>
<p>
If you want to, you can also throw your own errors. For instance,</p>
<pre style="margin-left: 40px;">
if (!locateKarel()) {
throw Error("Could not locate Karel in the world");
}</pre>
<p>
would throw an error, which then should be caught with some try-catch.</p>
<h3>
"use strict"</h3>
<p>
While we are at errors: recall that in JavaScript we are not required to declare variables. This can lead to problems:</p>
<pre style="margin-left: 40px;">
//"use strict"; // uncomment this line
function run(() {
let fritz = 5;
frits = 4;
console.log(fritz);
}</pre>
<p>
In the third line, we want to reassign a new value to the variable <em>fritz</em>. But we made a typo, and hence instead of a reassignment, we declared a new variable named <em>frits</em>. JavaScript does not care, there is no error here. To avoid these kinds of stupid mistakes, it is highly recommended that you start all of your JavaScript code with the "use strict" keyword. Adding it, will result in an error being thrown.</p>
<p>
<strong>SEP: Always add the line "use strict" at the top of your code!</strong></p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/numberGuessConsole" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/numberGuessConsole.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
Interfaces</h2>
<p>
Finally we come to the last topic of this chapter: <em>interfaces</em>. We could make this very short by saying that JavaScript does not have interfaces or abstract classes. Period.</p>
<p>
But obviously, if so many languages have it, there must be a good reason for it. Until now we have always programmed alone. But what if we work in teams, meaning several people write on the same program? How do we know who writes what? How can we be sure the different pieces fit together? We use interfaces for exactly this purpose.</p>
<p>
Let's take NumberGuess as an example. The objective of the game is for the computer to choose a random number, let's say between 0 and 99, and for the player to guess that number in as few steps as possible. The program consists of two parts: the part that takes care of the logic (NumberGuessLogic) and the part that interacts with the player (NumberGuessConsole). This means we have two classes, who depend on each other. We want to clearly define this dependency, and we do this by means of an interface. Since JavaScript does not have interfaces or abstract classes, we just use a normal class:</p>
<pre style="margin-left: 40px;">
// interface or abstract class
class NumberGuessLogic {
constructor() {
// if we need 'this' in constructor of subclass, then super() must be called,
// hence we can not throw an Error here:
// throw new Error('NumberGuessLogic is interface, can not be instantiated!');
}
/**
* guess should be number between 0 and 99 <br/>
* return 0 if guess was correct <br/>
* return +1 if guess was higher <br/>
* return -1 if guess was lower
*
* @param guess
* @return
*/
<span style="color:#0000ff;">makeGuess(guess)</span> {
throw new Error('Method is abstract, needs to be implemented!');
}
}</pre>
<p>
This interface is a contract between two developers:</p>
<ul>
<li>
For one developer (NumberGuessConsole) it means that there will be a method <em>makeGuess(int guess)</em>, which takes the number guessed as a parameter, and which returns whether the number was to small, to large or correct (-1, +1, 0).</li>
<li>
For the other developer (NumberGuessLogic) it means that she has to write a method <em>makeGuess(int guess)</em>, which compares a guess with the internally generated random number and returns whether the number was to small, to large or correct (-1, +1, 0).</li>
</ul>
<p>
This allows two or more developers to independently write separate pieces for a common program that can then easily be merged. Notice two things about the code: it has lots of comments, because two people have to agree explicitely what the method is supposed to do, there should be no ambiguity. And it throws an error, indicating, that this class is not really supposed to be used.</p>
<p>
Let's continue with how this would be used: We start with the part that implements the NumberGuessLogic interface. It is customary to add the extension "Impl" to classes that implement a given interface, hence the name NumberGuessLogicImpl:</p>
<pre style="margin-left: 40px;">
// implementation of interface
class NumberGuessLogicImpl <span style="color:#0000ff;">extends NumberGuessLogic</span> {
constructor() {
super();
const rgen = new RandomGenerator();
this.number = rgen.nextInt(0, 99);
}
/**
* guess should be number between 0 and 99 return 0 if guess was correct
* return +1 if guess was higher return -1 if guess was lower
*
* @param guess
* @return
*/
makeGuess(guess) {
if (guess == this.number) {
return 0;
}
if (guess > this.number) {
return +1;
} else {
return -1;
}
}
}</pre>
<p>
This class must have a method called makeGuess(int guess), which of course must do something now. Naturally, the random number must be generated somewhere, probably in the constructor.</p>
<p>
Regardless of this, the other developer can already start with NumberGuessConsole class. This is a normal console program:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
// let logic = new NumberGuessLogic();
let logic = new NumberGuessLogicImpl();
<span style="color:#0000ff;">if (logic instanceof NumberGuessLogic)</span> {
while (true) {
let guess = await readInt("Enter guess: ");
if (logic.makeGuess(guess) == 0)
break;
if (logic.makeGuess(guess) == 1) {
println("Number is smaller.");
} else {
println("Number is higher.");
}
}
println("You won!");
} else {
println("'logic' is not of type NumberGuessLogic!");
}
}</pre>
<p>
Notice first that with the <em>instanceof</em> operator we make sure that the Impl class is of the correct type. And second the commented line, that is the line the second developer used before the Impl class was finished, to write her code. When both developers are done, we just put the classes together into one project, and everything should work fine.</p>
<p>
We could have used the same approach also in the TicTacToe and the MindReader projects, if we wanted to.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/polymorphism" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/polymorphism.png" style="width: 200px; height: 120px; display: block;" />Try it</a></div>
<h2>
Polymorphism</h2>
<p>
Steve Jobs used to end his presentation with the sentence "one more thing..." and usually that's when it got interesting. Polymorphism literally means "many forms". And what does this have to do with JavaScript? </p>
<p>
Let's remember our Student example from the MindReader chapter. We defined a class Student:</p>
<pre style="margin-left: 40px;">
class Student {
constructor(name, id = -1) {
this.name = name;
...
}
toString() {
return "Student [name=" + this.name + ", id=" + this.getId()
+ ", credits=" + this.incrementCredits() + "]";
}
}</pre>
<p>
In addition, we could also define a class Freshman, which extends a Student:</p>
<pre style="margin-left: 40px;">
class Freshman extends Student {
constructor(name, id = -1) {
super(name, id);
}
toString() {
return "Freshman [name=" + this.name + ", id=" + this.getId()
+ ", credits=" + this.incrementCredits() + "]";
}
}</pre>
<p>
This means, Freshman can do everything Student can, the only difference is when calling the toString() method.</p>
<p>
Since both classes are of type Student, we can assume that they have a toString() method, and thus the following function makes totally sense,</p>
<pre style="margin-left: 40px;">
function polymorphic(studnt) {
println(studnt.toString());
}</pre>
<p>
if it is called with with a Student or a Freshman object:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
const hansel = new Freshman("Hänschen");
polymorphic(hansel);
const gretel = new Student("Gretchen");
polymorphic(gretel);
}</pre>
<p>
Now in JavaScript there is a little problem: there is no compiler preventing us from doing stupid things. For instance we could call the polymorphic() function with a string:</p>
<pre style="margin-left: 40px;">
polymorphic("hi there");</pre>
<p>
That would work, but it is not really what we wanted. But if we change the polymorphic() function slightly,</p>
<pre style="margin-left: 40px;">
function polymorphic(studnt) {
if (studnt <span style="color:#0000ff;">instanceof</span> Student) {
println(studnt.toString());
} else {
throw Error("Parameter is not of type Student!");
}
}</pre>
<p>
we get exactly what we wanted: a method that works for both Students and Freshmen, meaning it is polymorph. Well, as polymorph as it is going to get in JavaScript.</p>
<p>
We now know all three pillars of object-oriented programming:</p>
<ul>
<li>
Data Encapsulation and Information Hiding,</li>
<li>
Inheritance and Composition,</li>
<li>
and Polymorphism.</li>
</ul>
<p style="margin-left: 40px;">
<img alt="" src="img/e5c22719-1927-42b8-86c6-2c21661acdaf.png" style="width: 273px; height: 229px;" /></p>
<p>
.</p>
<hr />
<h1>
Review</h1>
<p>
It was about time we learned how to work with files. Also the exception handling should have come much earlier, but of course it makes much more sense to introduce it together with files. What is really new and will prove very useful for the future are the data structures ArrayList and HashMap. They will make our lives easier many times over. And we have checked off the topics of interfaces and polymorphism, nothing really to be afraid of.</p>
<p>
But the most important thing in this chapter was the object-oriented analysis, so to speak Top-Down 2.0.</p>
<p>
.</p>
<hr />
<h1>
Projects</h1>
<p>
Was all the trouble worthwhile? Well, see for yourself.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/writeToStorage" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/writeToStorage.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
WriteToStorage</h2>
<p>
Most browsers have something that is called local storage. It kind of acts like a file system, and one way we can use it is as a kind of replacement. The API is very similar to the FileWriter's:</p>
<pre style="margin-left: 40px;">
async function setup() {
...
let fw = new StorageWriter('test.txt');
fw.clear();
println('Enter text to write (\'.\' to quit): ');
while (true) {
let line = await readLine('');
if (line == '.')
break;
fw.append(line + '\n');
}
}</pre>
<p>
Naturally, you must allow access to local storage in your browser for this to work.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/readFromStorage" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/readFromStorage.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
ReadFromStorage</h2>
<p>
Once you have written something, maybe you also want to read it, that's what the StorageReader is for:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
let fileName = await readLine("Enter file to read (test.txt): ");
// open file
let sr = new StorageReader(fileName);
let line = sr.read();
println(line);
}</pre>
<p>
You can't really store a lot in the storage, but it is easy to use and sometime comes in quite handy.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch8_Stocks/uploadFile" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/uploadFile.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
UploadFile</h2>
<p>
When we were discussing the FileReader, we mentioned that the browser does not really have access to the local file system of the user. But, what we can do in a browser is upload files. In this case, the user usually has to select a file on her computer, and then click on an upload button. The class JSFileUpload wraps the underlying HTML <input type='file'> tag:</p>
<pre style="margin-left: 40px;">
function setup() {
createGUI(300, 150);
let fritz = new JSFileUpload();
addWidget(fritz);
}</pre>
<p>
Once the user selected a file, we can read it in the onChange() function:</p>
<pre style="margin-left: 40px;">
function onChange(ev) {
let input = ev.target;
let reader = new FileReader();
reader.onload = function () {
let text = reader.result;
print(text);
};
reader.readAsText(input.files[0]);
}</pre>
<p>
Notice, that the FileReader class used here is JavaScript normal FileReader class, and not our Utils.FileReader class.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/minutes" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/minutes.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
Minutes</h2>
<p>
Sometimes we are responsible for the minutes of a team meeting. Wouldn't it be nice to have a program for taking the meeting notes? The idea is this: just type a sentence, press Enter and the line will be saved in a file called "minutes.txt". For this we open a file with a FileWriter, read line by line (loop-and-a-half) from the console with readLine(), and write each line into the file immediately. Of course, we still need an abort criterion (sentinel): this could simply be an empty line. After that, of course, we must not forget to close our file. A useful extension would be to add the time when the text was entered to each line. Then our program would really deserve its name.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/wordCount" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/wordCount.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
WordCount</h2>
<p>
WordCount is a very simple program: it reads a specific file line by line and counts the lines, words and characters it contains. We use the FileReader together with the BufferedReader to read line by line. We need three variables for counting:</p>
<pre style="margin-left: 40px;">
let counterLines = 0;
let counterWords = 0;
let counterChars = 0;</pre>
<p>
(these can be local variables). Counting the lines is very easy. Counting the characters is also easy, because we know how many characters are in a line with line.length(). To count the words we could either use the StringTokenizer, or use the method split() of the String class:</p>
<pre style="margin-left: 40px;">
function countWords(line) {
let words = line.split(" ");
return words.length;
}</pre>
<p>
The split() method should be used with caution. Apparently it looks as if it would simply cut a string into its individual parts and store these individual parts in a string array. Sure it does that, but what criterion does it use to cut the string? Unlike the StringTokenizer, which simply takes a list of separators to split a string, the split() method uses regular expressions. So until we know what regular expressions are we shouldn't really use the split() method.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/createFileWithRandomNumbers" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/createFileWithRandomNumbers.png" style="width: 200px; height: 113px; display: block;" />Try it</a></div>
<h2>
CreateFileWithRandomNumbers</h2>
<p>
From time to time (e.g. in the next project) we need a file with some random values. These could be just numbers, but these could also be random names or addresses or whatever. The user should tell us the name of the file into which we are supposed to write the random numbers, then we need the range in which the numbers should be, and we need to know how many numbers we should generate. The program should then create a file using FileWriter and RandomGenerator. For the next project we need those random numbers.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/histogram" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/histogram.png" style="width: 200px; height: 135px; display: block;" />Try it</a></div>
<h2>
Histogram</h2>
<p>
To get a quick overview of the grade distribution in an exam, it would be nice to have a histogram of that data. You can of course do this with some fancy graphics program (comes later), but it's much quicker to do this with a console program.</p>
<p>
We want to accumulate points, so we count how many exams had points between 0 and 9, between 10 and 19, and so on. For example, we could define an array for eleven numbers, and we want the array to be prefilled with all zeros:</p>
<pre style="margin-left: 40px;">
let histogramData = new Array(11).fill(0);</pre>
<p>
Then there is a small trick on how to easily add entries into the array using integer numbers:</p>
<pre style="margin-left: 40px;">
function putScoreInHistogram(score) {
const idx = Math.trunc(score / 10);
histogramData[idx]++;
}</pre>
<p>
That's a tough line to digest, but after long enough admiration, let's move on. </p>
<p>
We read line by line from our Scores.txt file, convert the strings into ints using</p>
<pre style="margin-left: 40px;">
let score = parseInt(line);</pre>
<p>
Then we add them to our array using our miracle method putScoreInHistogram(). After reading all our data, we iterate through our array and output it to the console. We could just print the numbers, but much prettier are little stars (also called asterisks not Asterix!):</p>
<pre style="margin-left: 40px;">
function convertToStars(i) {
let stars = "";
for (let j = 0; j < i; j++) {
stars += "*";
}
return stars;
}</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/punctuation" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/punctuation.png" style="width: 200px; height: 137px; display: block;" />Try it</a></div>
<h2>
Punctuation</h2>
<p>
When we browse the Internet, there are programs (or rather algorithms) that can automatically recognize in which language we are writing. We type a few words and punctuation marks, and the program can tell us what language we are using. Actually, it turns out this is not really that difficult.</p>
<p>
The idea in this project is to count the punctuation marks, such as: ";,.!?'. Similar as in the last project (histogram) we read a given text from a file and then show the frequency of punctuation marks in a histogram. It turns out that each language has its favorite punctuation marks, and we can recognize a language by the frequency with which certain punctuation marks occur. Of course the text to be analyzed should be of a certain length, and it should be typical for a given languag (so Ulysses would be rather unsuitable [2]).</p>
<p>
The highlight of this program is the instance variable punctuation:</p>
<pre style="margin-left: 40px;">
const punctuation = ";:'\",!?.";</pre>
<p>
i.e. a string containing all possible punctuation marks. We have specially marked the character '\"' here, because it is the only way to get the quotation mark into a string. </p>
<p>
We then read line by line from a file that the user gave us, and analyze each line:</p>
<pre style="margin-left: 40px;">
function analyzeForPunctuation(line) {
for (let i = 0; i < line.length; i++) {
let c = line.charAt(i);
if (punctuation.includes(c)) {
let index = punctuation.indexOf(c);
histogramData[index]++;
totalNrOfPunctuations++;
}
}
}</pre>
<p>
That's pretty heavy tobacco. Again, we read line by line. Then we iterate over each character in each line, one character at a time. We check if it is a punctuation mark, and if so, we increase the counter for that punctuation mark by one. We also have a counter for the total number of punctuation marks, which allows us to normalize the numbers when displaying the asterisks.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr8_Stocks/worldMap" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/worldMap.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
WorldMap</h2>
<p>
Wikipedia has a list with the longitude and latitude of many cities worldwide [3]. If we go through this list, "Cities.txt", and paint a GOval for each city, then we can draw a world map. Again, we use the FileReader/BufferedReader combo to read line by line from the file. The data is in the following form:</p>
<pre style="margin-left: 40px;">