-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
533 lines (284 loc) · 301 KB
/
atom.xml
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Programming blog</title>
<subtitle>This is a programming blog</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://pandaforme.github.io/"/>
<updated>2018-05-25T03:55:13.569Z</updated>
<id>https://pandaforme.github.io/</id>
<author>
<name>pandaforme</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>[Java] Flow control in try catch finally</title>
<link href="https://pandaforme.github.io/2018/05/25/Java-Flow-control-in-try-catch-finally/"/>
<id>https://pandaforme.github.io/2018/05/25/Java-Flow-control-in-try-catch-finally/</id>
<published>2018-05-25T03:35:00.000Z</published>
<updated>2018-05-25T03:55:13.569Z</updated>
<content type="html"><![CDATA[<p>在正常情況下,當執行完 try 的最後一行或是要把控制權轉交給它的呼叫者 (return 或丟出 exception)時,會執行 finally ,當 finally 執行完畢,再把控制權轉交給 try。</p><p>但是當在 finally 裡面寫下 return, throw exception, continue, break 會沒有辦法把控制權轉交給 try,造成不可以預期的結果。所以<strong>千萬</strong>不要在 finally 裡面 return 或丟出 exception,雖然現在的 IDE 都會聰明到幫你檢查出來。</p><p>主要原因 try-finally 轉成 Java byte code 時候,finally 是一個副程式,當 try 執行完畢時候就會去呼叫 finally 副程式。當 finally 副程式執行完畢,會跳到 try 的記憶體位置。但在 finally 裡面加了這些return, throw exception, continue, break,它就提前跳出程式回不到正確的位置。</p><p>另外,當 try 裡面強制中斷 JVM 或是非預期的情況發生提早結束 (這裡所指的非預期的情況不是丟出 exception,而是當下的 thread 突然死掉或是 JVM 突然有問題這類的。),finally 是不會執行的。</p><h1 id="Try-finally-clause"><a href="#Try-finally-clause" class="headerlink" title="Try-finally clause"></a>Try-finally clause</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// Block of code with multiple exit points</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">// Block of code that is always executed when the try block is exited,</span></span><br><span class="line"> <span class="comment">// no matter how the try block is exited</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Example-1"><a href="#Example-1" class="headerlink" title="Example 1"></a>Example 1</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>; </span><br><span class="line"><span class="keyword">try</span> { </span><br><span class="line"> i = i + <span class="number">1</span>; </span><br><span class="line"> System.out.println(i);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">finally</span>{</span><br><span class="line"> i = i + <span class="number">2</span>; </span><br><span class="line"> System.out.println(i);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//1</span></span><br><span class="line"><span class="comment">//3</span></span><br></pre></td></tr></table></figure><h1 id="Example-2"><a href="#Example-2" class="headerlink" title="Example 2"></a>Example 2</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>{</span><br><span class="line"> System.out.println(doSomeThing());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">doSomeThing</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">try</span> { </span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">finally</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//2</span></span><br></pre></td></tr></table></figure><h1 id="Example-3"><a href="#Example-3" class="headerlink" title="Example 3"></a>Example 3</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(doSomeThing(<span class="keyword">true</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">doSomeThing</span><span class="params">(<span class="keyword">boolean</span> bVal)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (bVal) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> System.out.println(<span class="string">"Got old fashioned."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Got old fashioned.</span></span><br><span class="line"><span class="comment">// 1</span></span><br></pre></td></tr></table></figure><h1 id="Example-4"><a href="#Example-4" class="headerlink" title="Example 4"></a>Example 4</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(doSomeThing());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">doSomeThing</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Exception(<span class="string">"from try"</span>);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Exception(<span class="string">"from finally"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Exception in thread "main" java.lang.Exception: from finally</span></span><br></pre></td></tr></table></figure><h1 id="Example-5"><a href="#Example-5" class="headerlink" title="Example 5"></a>Example 5</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(doSomeThing(<span class="keyword">true</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">doSomeThing</span><span class="params">(<span class="keyword">boolean</span> bVal)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> i = <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">finally</span> { <span class="comment">// the first finally clause</span></span><br><span class="line"> i = <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> i = <span class="number">3</span>;</span><br><span class="line"> <span class="keyword">return</span> i; <span class="comment">// this never completes, because of the continue</span></span><br><span class="line"> } <span class="keyword">finally</span> { <span class="comment">// the second finally clause</span></span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">3</span>) {</span><br><span class="line"> <span class="keyword">continue</span>; <span class="comment">// this continue overrides the return statement</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="Example-6"><a href="#Example-6" class="headerlink" title="Example 6"></a>Example 6</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> System.out.println(doSomeThing());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">doSomeThing</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.exit(<span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Exception(<span class="string">"from finally"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// terminates JVM and doesn't execute finally block</span></span><br></pre></td></tr></table></figure><h1 id="References"><a href="#References" class="headerlink" title="References"></a>References</h1><p><a href="https://www.javaworld.com/article/2077609/core-java/try-finally-clauses-defined-and-demonstrated.html" target="_blank" rel="noopener">Try-finally clauses defined and demonstrated</a></p>]]></content>
<summary type="html">
<p>&#x5728;&#x6B63;&#x5E38;&#x60C5;&#x6CC1;&#x4E0B;&#xFF0C;&#x7576;&#x57F7;&#x884C;&#x5B8C; try &#x7684;&#x6700;&#x5F8C;&#x4E00;&#x884C;&#x6
</summary>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Scala] The importance of recursion</title>
<link href="https://pandaforme.github.io/2017/04/26/Scala-The-importance-of-recursion/"/>
<id>https://pandaforme.github.io/2017/04/26/Scala-The-importance-of-recursion/</id>
<published>2017-04-26T09:55:00.000Z</published>
<updated>2017-05-13T16:20:49.000Z</updated>
<content type="html"><![CDATA[<h1 id="遞迴"><a href="#遞迴" class="headerlink" title="遞迴"></a>遞迴</h1><p>在functional programming世界中是不准許有mutable變數,意味著我們熟悉的 <code>while</code>, <code>for</code> 迴圈都是禁止使用。<br>那我們應該怎麼辦呢? 這邊會舉個數個例子,來解釋是透過遞迴方式來完成 <code>while</code> 或 <code>for</code> 迴圈。</p><h2 id="從一個串列中找出最大值"><a href="#從一個串列中找出最大值" class="headerlink" title="從一個串列中找出最大值"></a>從一個串列中找出最大值</h2><p>如果在 <code>Java</code> 我們會怎麼做呢?</p><ol><li>宣個一個變數(max)存放目前的最大值</li><li>透過<code>while</code> 或 <code>for</code> 迴圈,將串列中的每個元素跟我們宣告的變數(max)比大小<br>2.1 若元素的值大於max,max的值就改為此元素的值<br>2.2 若元素的值小於或等於max,不做任何事</li></ol><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> max = <span class="type">Int</span>.<span class="type">MinValue</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(i <- <span class="type">List</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>)){</span><br><span class="line"> <span class="keyword">if</span>(i > max)</span><br><span class="line"> max = i</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>透過遞迴方式我們會怎麼解決呢?</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">findMax(<span class="type">List</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">findMax</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>]): <span class="type">Int</span> = {</span><br><span class="line"> list <span class="keyword">match</span>{</span><br><span class="line"> <span class="comment">// 假如是空的串列,我們回傳0</span></span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="number">0</span></span><br><span class="line"> <span class="comment">// 假如只有一個元素的串列,那最大值就為該元素</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => h</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 主要邏輯</span></span><br><span class="line"> <span class="keyword">case</span> h :: t => <span class="type">Math</span>.max(h, findMax(t))</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>在迴圈版本中,逐一每個元素跟某一個mutable變數比大小。</li><li>在迴遞版本中,第一個元素跟去除第一個元素的串列的最大值比大小。</li></ul><p>迴遞的寫法更是簡潔和表達出整個程式主要邏輯,我們再來多試看看幾個題目。</p><h2 id="從一個串列中找出最小值"><a href="#從一個串列中找出最小值" class="headerlink" title="從一個串列中找出最小值"></a>從一個串列中找出最小值</h2><p>做法跟找出最大值類似,第一個元素跟去除第一個元素的串列的最小值比大小。</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">findMin(<span class="type">List</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">findMin</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>]): <span class="type">Int</span> = {</span><br><span class="line"> list <span class="keyword">match</span>{</span><br><span class="line"> <span class="comment">// 假如是空的串列,我們回傳0</span></span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="number">0</span></span><br><span class="line"> <span class="comment">// 假如只有一個元素的串列,那最小值就為該元素</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => h</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 主要邏輯</span></span><br><span class="line"> <span class="keyword">case</span> h :: t => <span class="type">Math</span>.min(h, findMin(t))</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="檢查一個串列中是否存在某個特定值"><a href="#檢查一個串列中是否存在某個特定值" class="headerlink" title="檢查一個串列中是否存在某個特定值"></a>檢查一個串列中是否存在某個特定值</h2><p>檢查第一個元素是否等於目標值或是去除第一個元素的串列有目標值</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">find(<span class="type">List</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>), <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">find</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>], target: <span class="type">Int</span>): <span class="type">Boolean</span> = {</span><br><span class="line"> list <span class="keyword">match</span>{</span><br><span class="line"> <span class="comment">// 假如是空的串列,回傳false</span></span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="literal">false</span></span><br><span class="line"> <span class="comment">// 假如只有一個元素的串列,而且該元素等於target,回傳true</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> <span class="keyword">if</span> (h == target) => <span class="literal">true</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 主要邏輯</span></span><br><span class="line"> <span class="keyword">case</span> h :: t => (h == target) || find(t, target)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="反轉一個字串"><a href="#反轉一個字串" class="headerlink" title="反轉一個字串"></a>反轉一個字串</h2><p>先反轉去除第一個字元的串列,之後再將第一字元放在最後面</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">reverse(<span class="string">"I should learn scala seriously!"</span>.toList)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">reverse</span></span>(list: <span class="type">List</span>[<span class="type">Char</span>]): <span class="type">String</span> = {</span><br><span class="line"> list <span class="keyword">match</span> {</span><br><span class="line"> <span class="comment">// 假如是空的串列,回傳false</span></span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="string">""</span></span><br><span class="line"> <span class="comment">// 假如只有一個元素的串列,回傳該元素</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => h.toString</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 主要邏輯</span></span><br><span class="line"> <span class="keyword">case</span> h :: t => reverse(t) + h</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="判斷一個字串是否為另外一個字串的子字串"><a href="#判斷一個字串是否為另外一個字串的子字串" class="headerlink" title="判斷一個字串是否為另外一個字串的子字串"></a>判斷一個字串是否為另外一個字串的子字串</h2><p>子字串的定義:字數,內容和順序需要符合,空字串為任何字串的子字串<br>例如:</p><ul><li>“abc” 為 “XXXYYYabc”的子字串</li><li>“XXXY” 為 “XXXYYYabc”的子字串</li><li>“” 為 “XXXYYYabc”的子字串</li><li>“ABC” 不為 “XXXYYYabc”的子字串</li><li>“QQWW” 不為 “XXXYYYabc”的子字串</li><li>“XXXaYYY” 不為 “XXXYYYabc”的子字串</li></ul><p>先比較主要字串和子字串的第一個字母是否一樣,</p><ul><li>若一樣則這兩個字串去除第一個字母繼續比</li><li>若不一樣,主要字串去除第一個字母和子字串繼續比</li></ul><p>例如:<br>主要字串: “abcdefghi”<br>子字串: “abc”<br>檢查主要字串前三個字母(abc)是否和子字串(abc)一樣,若一樣就回傳<code>true</code></p><p>主要字串: “abcdefghi”<br>子字串: “defgh”<br>檢查主要字串前五個字母(abcde)是否和子字串(defgh)一樣,若不一樣,<br>則 “bcdefghi” 和 “defgh” 繼續比</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">println(isSubString(<span class="string">"I should learn scala seriously!"</span>.toList, <span class="string">"scala"</span>.toList))</span><br><span class="line">println(isSubString(<span class="string">"I should learn scala seriously!"</span>.toList, <span class="string">"XXOO"</span>.toList))</span><br><span class="line">println(isSubString(<span class="string">"I should learn scala seriously!"</span>.toList, <span class="string">"scaxxyyla"</span>.toList))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">isSubString</span></span>(original: <span class="type">List</span>[<span class="type">Char</span>], target: <span class="type">List</span>[<span class="type">Char</span>]): <span class="type">Boolean</span> = {</span><br><span class="line"> (original, target) <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> (<span class="type">Nil</span>, _) => <span class="literal">false</span></span><br><span class="line"> <span class="keyword">case</span> (_, <span class="type">Nil</span>) => <span class="literal">true</span></span><br><span class="line"> <span class="keyword">case</span> (o :: <span class="type">Nil</span>, t :: <span class="type">Nil</span>) <span class="keyword">if</span> (o == t) => <span class="literal">true</span></span><br><span class="line"> <span class="keyword">case</span> (o :: <span class="type">Nil</span>, t :: <span class="type">Nil</span>) <span class="keyword">if</span> (o != t) => <span class="literal">false</span></span><br><span class="line"> <span class="keyword">case</span> (o, t) <span class="keyword">if</span> (o.take(t.length) == t) => <span class="literal">true</span></span><br><span class="line"> <span class="keyword">case</span> (oh :: ot, t) => isSubString(ot, t)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="將一個串列由小排到大"><a href="#將一個串列由小排到大" class="headerlink" title="將一個串列由小排到大"></a>將一個串列由小排到大</h2><p>我們來實作<a href="https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F" target="_blank" rel="noopener">Quicksort</a></p><ol><li>從數列中挑出一個元素,稱為 “基準”(pivot)。</li><li>重新排序數列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準後面(相同的數可以到任一邊)。在這個分割結束之後,該基準就處於數列的中間位置。這個稱為分割(partition)操作。</li><li>遞迴地(recursively)把小於基準值元素的子數列和大於基準值元素的子數列排序。</li></ol><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">quicksort(<span class="type">List</span>(<span class="number">4</span>, <span class="number">3</span>, <span class="number">2</span>, <span class="number">9</span>, <span class="number">10</span>))</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">quicksort</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>]): <span class="type">List</span>[<span class="type">Int</span>] = {</span><br><span class="line"> list <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="type">Nil</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => <span class="type">List</span>(h)</span><br><span class="line"> <span class="keyword">case</span> h :: t => quicksort(t.filter(_ <= h)) ::: h :: quicksort(t.filter(_ > h))</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="寫出費氏數列"><a href="#寫出費氏數列" class="headerlink" title="寫出費氏數列"></a>寫出費氏數列</h2><p>何謂費氏數列:<a href="https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97" target="_blank" rel="noopener">費氏數列</a></p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">fib(<span class="number">6</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fib</span></span>(n: <span class="type">Int</span>): <span class="type">Int</span> = {</span><br><span class="line"> n <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span> => <span class="number">0</span></span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span> => <span class="number">1</span></span><br><span class="line"> <span class="keyword">case</span> _ => fib(n - <span class="number">1</span>) + fib(n - <span class="number">2</span>)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>經過幾次的練習,我們應該大概可以慢慢掌握到怎麼運用遞迴來達到迴圈目的。</p><ol><li>先把主要邏輯寫出來</li><li>再把邊界條件設好,沒有邊界條件就會無窮的跑下去…<br>遞迴主要是透過自我呼叫,把每一步的狀態放在 <code>stack</code>,等走到邊界回傳邊界值或完成邊界條件後,再回溯回去。</li></ol><p>把問題透過<a href="https://zh.wikipedia.org/wiki/%E5%88%86%E6%B2%BB%E6%B3%95" target="_blank" rel="noopener">Divide and conquer</a>方式,<br>大問題分解成數個小問題,若小問題規模較小且易於解決時,則直接解。否則,遞歸地解決各小問題。<br>最後再將每個小問題的結果逐一合併起來。</p><p>遞迴的寫法很簡潔,但是最大的問題是效能不好和容易 <code>Stack Overflow</code>。<br>主要原因是會去嘗試走所有可能的路徑而且把每一個狀態放在stack,當狀態一多就爆了。<br>去嘗試走所有可能的路徑也是造成效能不好的原因。</p><p>假如:</p><ol><li>去嘗試走所有可能的路徑不多,但是每一個步計算很花時間,遞迴容易轉換成非同步程式。</li></ol><p>以排序為例,一個串列數量小於一千,我們可以使用<a href="https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F" target="_blank" rel="noopener">Insertion Sort</a>;大於一千改使用Quicksort:</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sort</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>]): <span class="type">List</span>[<span class="type">Int</span>] = {</span><br><span class="line"> <span class="keyword">if</span>(list.length < <span class="number">1000</span>){</span><br><span class="line"> <span class="comment">// 需要大量時間計算才可以得出結果</span></span><br><span class="line"> insertionSort(list)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> list <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="type">Nil</span></span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => <span class="type">List</span>(h)</span><br><span class="line"> <span class="keyword">case</span> h :: t => sort(t.filter(_ <= h)) ::: h :: sort(t.filter(_ > h))</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我們可以輕易將它轉換成非同步程式。<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sort</span></span>(list: <span class="type">List</span>[<span class="type">Int</span>]): <span class="type">Future</span>[<span class="type">List</span>[<span class="type">Int</span>]] = {</span><br><span class="line"> <span class="keyword">if</span>(list.length < <span class="number">1000</span>){</span><br><span class="line"> <span class="comment">// 需要大量時間計算才可以得出結果 </span></span><br><span class="line"> <span class="type">Future</span>(insertionSort(list))</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> list <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> <span class="type">Nil</span> => <span class="type">Future</span>(<span class="type">Nil</span>)</span><br><span class="line"> <span class="keyword">case</span> h :: <span class="type">Nil</span> => <span class="type">Future</span>(<span class="type">List</span>(h))</span><br><span class="line"> <span class="keyword">case</span> h :: t => <span class="type">Future</span>(sort(t.filter(_ <= h)) ::: h :: sort(t.filter(_ > h)))</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>非遞迴的版本就很難改了,因為主要存在共享的mutable變數,多個thread會共享同一個變數,就需要做同步處理。<br>同步問題沒有小心處理,結果很容易出錯。</p><ol><li>嘗試走所有可能的路徑很多</li></ol><p>例如:計算第五十個費氏數列<br>根據計算費氏數列的遞迴公式,<code>n = 50</code> 的樹狀結構會相當大。我們可以透過 <a href="http://localhost:4000/2016/12/09/Scala-Tail-recursion/" target="_blank" rel="noopener">Tail recursion</a> 來解決。<br>把上一個狀態的結果直接當成帶入參數,而不是依賴上一個狀態的結果。</p><p>因為 <code>fib(n) = fib(n - 1) + fib(n - 2)</code>,假如可以把 <code>fib(n - 1)</code> 和 <code>fib(n - 2)</code> 當參數帶入,<br>這樣就可以馬上得出 <code>fib(n)</code>,而不是等算完 <code>fib(n - 1)</code> 和 <code>fib(n - 2)</code> 後才可以得出 <code>fib(n)</code>。</p><pre><code class="scala"><span class="keyword">import</span> scala.annotation.tailrecfib(<span class="number">0</span>, <span class="number">1</span>, <span class="number">5</span>)<span class="meta">@tailrec</span><span class="function"><span class="keyword">def</span> <span class="title">fib</span></span>(previous: <span class="type">Int</span>, current: <span class="type">Int</span>, n: <span class="type">Int</span>): <span class="type">Int</span> = { n <span class="keyword">match</span> { <span class="keyword">case</span> <span class="number">0</span> => previous <span class="keyword">case</span> <span class="number">1</span> => current <span class="keyword">case</span> _ => fib(current, previous + current, n - <span class="number">1</span>) }}</code></pre><p>有興趣的讀者可以到 <a href="https://scalataiwan.github.io/ScalaKitchen/recursive.html" target="_blank" rel="noopener">ScalaKitchen</a> 試玩看看,也有提供<a href="https://scalataiwan.github.io/ScalaKitchen/" target="_blank" rel="noopener">中文版本的Scala入門教學</a>。</p>]]></content>
<summary type="html">
<h1 id="&#x905E;&#x8FF4;"><a href="#&#x905E;&#x8FF4;" class="headerlink" title="&#x905E;&#x8FF4;"></a>&#x905E;&#x8FF4;</h1><p>&#x5728;functi
</summary>
<category term="Scala" scheme="https://pandaforme.github.io/categories/Scala/"/>
<category term="Scala" scheme="https://pandaforme.github.io/tags/Scala/"/>
<category term="Recursion" scheme="https://pandaforme.github.io/tags/Recursion/"/>
<category term="Tail recursion" scheme="https://pandaforme.github.io/tags/Tail-recursion/"/>
</entry>
<entry>
<title>[Scala] Use Either to hand error cases</title>
<link href="https://pandaforme.github.io/2017/02/15/Scala-Use-Either-Try-to-hand-error/"/>
<id>https://pandaforme.github.io/2017/02/15/Scala-Use-Either-Try-to-hand-error/</id>
<published>2017-02-15T08:57:00.000Z</published>
<updated>2017-02-16T04:08:25.000Z</updated>
<content type="html"><![CDATA[<p>在OOP的語言中,我們exception來表達程式錯誤或是系統crash.Exception又可以分為<code>Checked Exception</code> 和 <code>UnChecked Excpetion</code>.</p><ul><li><p>Checked Exception: 會將要丟出的excpetion寫在function的signature.<br>例如:</p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">interface <span class="type">Foo</span>() <span class="keyword">throws</span> <span class="type">XXXException</span>, <span class="type">YYYException</span></span><br></pre></td></tr></table></figure></li><li><p>UnChecked Excpetion: 要丟出的excpetion不會寫在function的signature,呼叫function的人需要知道有exception要處理.</p></li></ul><p>Checked Exception會違反<a href="https://en.wikipedia.org/wiki/Open/closed_principle" target="_blank" rel="noopener">Open/Closed Principle</a>,當有新增丟出的excpetion,需要修改interface signature;UnChecked Excpetion則是需要知道有哪些exception需要處理.</p><p>這兩種exception孰好孰壞,在 <code>Clean code: a handbook of agile software craftsmanship, Robert C. Martin</code> 有提到:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">The debate is over. For years Java programmers have debated over the benefits and liabilities of checked exceptions. When checked exceptions were introduced in the first version of Java, they seemed like a great idea. The signature of every method would list all of the exceptions that it could pass to its caller. Moreover, these exceptions were part of the type</span><br><span class="line">of the method. Your code literally wouldn't compile if the signature didn't match what your code could do.</span><br><span class="line"></span><br><span class="line">At the time, we thought that checked exceptions were a great idea; and yes, they can yield some benefit. However, it is clear now that they aren't necessary for the production of robust software. C# doesn't have checked exceptions, and despite valiant attempts, C++ doesn't either. Neither do Python or Ruby. Yet it is possible to write robust software in all of these languages. Because that is the case, we have to decide—really—whether checked exceptions are worth their price.</span><br><span class="line"></span><br><span class="line">Checked exceptions can sometimes be useful if you are writing a critical library: You must catch them. But in general application development the dependency costs outweigh the benefits</span><br></pre></td></tr></table></figure></p><p>在Java中建議使用UnChecked Excpetion,但是這會導致另外一個災難…</p><ol><li>呼叫者不知道會丟出exception</li><li>呼叫者不知道有哪些excpetion要處理,當call chain很深的時候更是糟糕…</li><li>到處充滿了 <code>try{...} catch{...}</code></li></ol><p>相信使用Java開發的工程師應該感觸良多,尤其是在維護舊專案.一個call chain長達十幾層,每一層丟的excpetion都不一樣,有些層會處理exception,有些又不會,最後的大絕招就是每一層都加 <code>try{...} catch{...}</code>.</p><p>例外處理在OOP是一個很重要的議題,沒有謹慎處理很容易造成維護困難和發生問題不容易找到問題點.<br>因為Exception是有side effect,在FP是不被准許的.所以在pure FP程式中是看不到excpetion和 <code>try{...} catch{...}</code>.</p><h1 id="Either"><a href="#Either" class="headerlink" title="Either"></a>Either</h1><p>我們可以透過 <code>Either</code> 來達成,<code>Left</code> 放錯誤的物件,<code>Right</code> 放正確的物件:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">sealed</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Either</span>[<span class="type">A</span>, <span class="type">B</span>]</span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">Left</span>[+<span class="type">A</span>, +<span class="type">B</span>](<span class="params">a: <span class="type">A</span></span>) <span class="keyword">extends</span> <span class="title">Either</span>[<span class="type">A</span>, <span class="type">B</span>]</span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">Right</span>[+<span class="type">A</span>, +<span class="type">B</span>](<span class="params">b: <span class="type">B</span></span>) <span class="keyword">extends</span> <span class="title">Either</span>[<span class="type">A</span>, <span class="type">B</span>]</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">//</span> <span class="title">for</span> <span class="title">exmple</span></span></span><br><span class="line"><span class="class"><span class="title">type</span> <span class="title">Error</span> </span>= <span class="type">String</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> result = <span class="type">Right</span>[<span class="type">Error</span>, <span class="type">Int</span>](<span class="number">123</span>)</span><br><span class="line"><span class="keyword">val</span> error = <span class="type">Left</span>[<span class="type">Error</span>, <span class="type">Int</span>](<span class="string">"Something wrong!!!"</span>)</span><br></pre></td></tr></table></figure></p><p>我們可以把正確的結果或錯誤放到 <code>Either</code> 這個容器,呼叫者可以清楚知道有需要處理錯誤情況,再來程式碼不再到處充斥 <code>try{...} catch{...}</code>.</p><p>我們使用四則運算來當範例,如何使用 <code>Either</code><br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">div</span></span>(a: <span class="type">Double</span>, b: <span class="type">Double</span>): <span class="type">Either</span>[<span class="type">String</span>, <span class="type">Double</span>] = {</span><br><span class="line"> <span class="keyword">if</span>(b == <span class="number">0</span>) <span class="type">Left</span>[<span class="type">String</span>, <span class="type">Double</span>](<span class="string">"Can't divide by 0 !!!"</span>)</span><br><span class="line"> <span class="keyword">else</span> <span class="type">Right</span>[<span class="type">String</span>, <span class="type">Double</span>](a / b)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">add</span></span>(a: <span class="type">Double</span>, b: <span class="type">Double</span>): <span class="type">Either</span>[<span class="type">String</span>, <span class="type">Double</span>] = {</span><br><span class="line"> <span class="type">Right</span>[<span class="type">String</span>, <span class="type">Double</span>](a + b)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">minus</span></span>(a: <span class="type">Double</span>, b: <span class="type">Double</span>): <span class="type">Either</span>[<span class="type">String</span>, <span class="type">Double</span>] = {</span><br><span class="line"> <span class="type">Right</span>[<span class="type">String</span>, <span class="type">Double</span>](a - b)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">mul</span></span>(a: <span class="type">Double</span>, b: <span class="type">Double</span>): <span class="type">Either</span>[<span class="type">String</span>, <span class="type">Double</span>] = {</span><br><span class="line"> <span class="type">Right</span>[<span class="type">String</span>, <span class="type">Double</span>](a * b)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// ((((1 + 2) * 3) / 4) - 5)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> result = <span class="keyword">for</span> {</span><br><span class="line"> r1 <- add(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"> r2 <- mul(r1, <span class="number">3</span>)</span><br><span class="line"> r3 <- div(r2, <span class="number">4</span>)</span><br><span class="line"> r4 <- minus(r3, <span class="number">5</span>)</span><br><span class="line">} <span class="keyword">yield</span> {</span><br><span class="line"> r4</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// result: scala.util.Either[String,Double] = Right(-2.75)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ((((1 + 2) * 3) / 0) - 5)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">val</span> result = <span class="keyword">for</span> {</span><br><span class="line"> r1 <- add(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line"> r2 <- mul(r1, <span class="number">3</span>)</span><br><span class="line"> r3 <- div(r2, <span class="number">0</span>)</span><br><span class="line"> r4 <- minus(r3, <span class="number">5</span>)</span><br><span class="line">} <span class="keyword">yield</span> {</span><br><span class="line"> r4</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// result: scala.util.Either[String,Double] = Left(Can't divide by 0 !!!)</span></span><br></pre></td></tr></table></figure></p><p>根據上面簡單的範例,這樣的寫法很明顯優於傳統OOP用excpetion來處理錯誤:</p><ul><li>不再有 <code>try{...} catch{...}</code> 充斥在每個地方.</li><li>呼叫者可以根據fucntion signature知道是否會產生錯誤.</li><li>更可以專心在商業邏輯,而不用花多餘的心力在處理例外.</li></ul><h1 id="Try"><a href="#Try" class="headerlink" title="Try"></a>Try</h1><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">sealed</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Try</span>[+<span class="type">T</span>]</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">Failure</span>[+<span class="type">T</span>](<span class="params">exception: <span class="type">Throwable</span></span>) <span class="keyword">extends</span> <span class="title">Try</span>[<span class="type">T</span>] </span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">Success</span>[+<span class="type">T</span>](<span class="params">value: <span class="type">T</span></span>) <span class="keyword">extends</span> <span class="title">Try</span>[<span class="type">T</span>]</span></span><br></pre></td></tr></table></figure><p><code>Try</code> 也是類似於 <code>Either</code> 的context,有興趣的讀者可以試用看看.在實務上大部分都採用 <code>Either</code>,不採用 <code>Try</code>的原因是:</p><ul><li>沒有辦法對exception做 <code>exhaustive pattern match</code>,當是Failure的時候,呼叫者不知道有哪些exception會丟出,只知道會丟出一個 <code>Throwable class</code>.</li></ul><p>使用 <code>Either</code> 我們可以自訂Error type,當失敗時候就可以對Error type做 <code>exhaustive pattern match</code>,依據不同的錯誤做不同的處理.</p>]]></content>
<summary type="html">
<p>&#x5728;OOP&#x7684;&#x8A9E;&#x8A00;&#x4E2D;&#xFF0C;&#x6211;&#x5011;exception&#x4F86;&#x8868;&#x9054;&#x7A0B;&#x5F0F;&#x932F;&#x8AA4;&#x62
</summary>
<category term="Scala" scheme="https://pandaforme.github.io/categories/Scala/"/>
<category term="Scala" scheme="https://pandaforme.github.io/tags/Scala/"/>
<category term="Exception" scheme="https://pandaforme.github.io/tags/Exception/"/>
<category term="Either" scheme="https://pandaforme.github.io/tags/Either/"/>
<category term="Try" scheme="https://pandaforme.github.io/tags/Try/"/>
</entry>
<entry>
<title>[Scala] How to use Option correctly</title>
<link href="https://pandaforme.github.io/2016/12/20/Scala-How-to-use-Option-correctly/"/>
<id>https://pandaforme.github.io/2016/12/20/Scala-How-to-use-Option-correctly/</id>
<published>2016-12-20T07:13:00.000Z</published>
<updated>2017-05-18T08:05:16.000Z</updated>
<content type="html"><![CDATA[<p>對於Scala我一直把它當成進階版本的Java,當越來越了解Functional Programming的精神,才發現之前想法還蠻天真的.</p><p>可以從如何正確使用 <code>Option</code> ,讓我們慢慢來進入Functional Programming的世界.</p><p>先從一個簡單的API實例來開始: 假如有一個API,Admin使用者可以找出某個國家的所有使用者;不是Admin使用者就回傳空字串.</p><p>使用者會帶上 <code>userName</code> , <code>password</code> 和 <code>country</code> 呼叫此API,這個API會</p><ol><li>檢查格式是否正確</li><li>查詢資料庫是否有使用者</li><li>若有,檢查 <code>userType</code> 使否為 <code>Admin</code></li><li>根據 <code>country</code> 去資料庫撈取該國家的所有使用者</li><li>將結果轉成 <code>json</code> 放到 http response</li></ol><p>先定義 <code>Data Type</code>:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">sealed</span> <span class="class"><span class="keyword">trait</span> <span class="title">Name</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">UserName</span>(<span class="params">name: <span class="type">String</span></span>) <span class="keyword">extends</span> <span class="title">Name</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">sealed</span> <span class="title">trait</span> <span class="title">Password</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">MD5Password</span>(<span class="params">plainText: <span class="type">String</span></span>) <span class="keyword">extends</span> <span class="title">Password</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">sealed</span> <span class="title">trait</span> <span class="title">Country</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">object</span> <span class="title">TAIWAN</span> <span class="keyword">extends</span> <span class="title">Country</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">object</span> <span class="title">CHINA</span> <span class="keyword">extends</span> <span class="title">Country</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">sealed</span> <span class="title">trait</span> <span class="title">UserType</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">object</span> <span class="title">ADMIN</span> <span class="keyword">extends</span> <span class="title">UserType</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">object</span> <span class="title">EMAIL</span> <span class="keyword">extends</span> <span class="title">UserType</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">object</span> <span class="title">PHONE</span> <span class="keyword">extends</span> <span class="title">UserType</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">sealed</span> <span class="title">trait</span> <span class="title">Account</span> </span>{</span><br><span class="line"> <span class="keyword">val</span> name: <span class="type">String</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">final</span> <span class="keyword">case</span> <span class="class"><span class="keyword">class</span> <span class="title">AccountWithCredential</span>(<span class="params">name: <span class="type">UserName</span>, password: <span class="type">Password</span>, userType: <span class="type">UserType</span></span>) <span class="keyword">extends</span> <span class="title">Account</span></span></span><br><span class="line"><span class="class"><span class="title">final</span> <span class="title">case</span> <span class="title">class</span> <span class="title">AccountWithProfile</span>(<span class="params">name: <span class="type">UserName</span>, country: <span class="type">Country</span>, age: <span class="type">Int</span></span>) <span class="keyword">extends</span> <span class="title">Account</span></span></span><br></pre></td></tr></table></figure></p><p>這樣的 <code>Data Type</code> 也是所謂的 <code>Algebraic Type</code>,<br>以 <code>Account</code> 為例:</p><ul><li>它有兩種 subtype <code>AccountWithCredential</code> 和 <code>AccountWithProfile</code>,為 <code>Account</code> 的 <code>Sum Type</code></li><li>各種不同 subtype 有它們的參數,也稱之 <code>Product Type</code></li></ul><p>這種定義方式有點像Java世界中的 <code>Value Object</code>,把資料和行為分開是有好處的,避免資料和行為耦合過緊.<a href="https://en.wikipedia.org/wiki/Software_design_pattern" target="_blank" rel="noopener">Design Pattern</a> 也是透過pattern去分離資料和行為.</p><p>再來我們來定義行為:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">Repo</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">login</span></span>(name: <span class="type">UserName</span>, password: <span class="type">Password</span>): <span class="type">Option</span>[<span class="type">AccountWithCredential</span>]</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">getAccountsByCountry</span></span>(country: <span class="type">Country</span>): <span class="type">Option</span>[<span class="type">List</span>[<span class="type">AccountWithProfile</span>]]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">object</span> <span class="title">Repo</span> <span class="keyword">extends</span> <span class="title">Repo</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">login</span></span>(name: <span class="type">UserName</span>, password: <span class="type">Password</span>): <span class="type">Option</span>[<span class="type">AccountWithCredential</span>] = ???</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">getAccountsByCountry</span></span>(country: <span class="type">Country</span>): <span class="type">Option</span>[<span class="type">List</span>[<span class="type">AccountWithProfile</span>]] = ???</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p><code>login</code> 的回傳值為一個 <code>Option</code> context,裡面裝著 <code>AccountWithCredential</code>.</p><ul><li>若有找到就回傳 <code>Some[AccountWithCredential]</code></li><li>若沒有找就回傳 <code>None</code></li></ul><p>在 <code>Java 7</code> 之前的版本會定義找不到會回傳 <code>Null</code>,<code>Null</code> 會造成語意不清和程式碼充斥著一堆檢查是否為 <code>Null</code> 的程式碼.<br>我們可以透過 <a href="https://en.wikipedia.org/wiki/Null_Object_pattern" target="_blank" rel="noopener">Null Object pattern</a> 來解決這個問題.<br>在 <code>Scala</code> 或 <code>Java 8</code> 則是透過 <code>Option</code> / <code>Optional</code> data type來解決之.</p><p>我們可以實作API:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">object</span> <span class="title">Api</span> <span class="keyword">extends</span> <span class="title">App</span> </span>{</span><br><span class="line"> <span class="keyword">val</span> name: <span class="type">Option</span>[<span class="type">UserName</span>] = parse(<span class="type">UserName</span>(args(<span class="number">0</span>)))</span><br><span class="line"> <span class="keyword">val</span> password: <span class="type">Option</span>[<span class="type">MD5Password</span>] = parse(<span class="type">MD5Password</span>(args(<span class="number">1</span>)))</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Step1: login</span></span><br><span class="line"> <span class="comment">// Step2: check isAdmin == true</span></span><br><span class="line"> <span class="comment">// Step3: get accounts by country</span></span><br><span class="line"> <span class="comment">// Step4: convert accounts to json</span></span><br><span class="line"> <span class="comment">// Step5: add json to HttpResponse</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name.isEmpty) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">RuntimeException</span>(<span class="string">"bad id"</span>)</span><br><span class="line"> <span class="keyword">if</span> (password.isEmpty) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">RuntimeException</span>(<span class="string">"bad password"</span>)</span><br><span class="line"> <span class="keyword">val</span> json: <span class="type">Option</span>[<span class="type">String</span>] = getJsonProfile(name.get, password.get, <span class="type">CHINA</span>)</span><br><span class="line"> <span class="keyword">if</span> (json.isDefined) {</span><br><span class="line"> returnHttpResponse(json.get)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> returnHttpResponse(<span class="string">""</span>)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">parse</span></span>[<span class="type">A</span>](a: => <span class="type">A</span>): <span class="type">Option</span>[<span class="type">A</span>] = ???</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">getJsonProfile</span></span>(name: <span class="type">UserName</span>,</span><br><span class="line"> password: <span class="type">Password</span>,</span><br><span class="line"> country: <span class="type">Country</span>): <span class="type">Option</span>[<span class="type">String</span>] = {</span><br><span class="line"> <span class="keyword">val</span> accountWithCredential: <span class="type">Option</span>[<span class="type">AccountWithCredential</span>] =</span><br><span class="line"> <span class="type">Repo</span>.login(name, password)</span><br><span class="line"> <span class="keyword">if</span> (accountWithCredential.isDefined) {</span><br><span class="line"> accountWithCredential.get.userType <span class="keyword">match</span> {</span><br><span class="line"> <span class="keyword">case</span> <span class="type">ADMIN</span> =></span><br><span class="line"> <span class="keyword">val</span> accounts: <span class="type">Option</span>[<span class="type">List</span>[<span class="type">AccountWithProfile</span>]] =</span><br><span class="line"> <span class="type">Repo</span>.getAccountsByCountry(country)</span><br><span class="line"> <span class="keyword">if</span> (accounts.isDefined) {</span><br><span class="line"> listToJson(accounts.get)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">None</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">case</span> _: <span class="type">UserType</span> => <span class="type">None</span></span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">None</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// convert a list of Account to json String</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">listToJson</span></span>[<span class="type">A</span>](list: <span class="type">List</span>[<span class="type">A</span>]): <span class="type">Option</span>[<span class="type">String</span>] = ???</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">returnHttpResponse</span></span>(message: <span class="type">String</span>): <span class="type">Unit</span> = ???</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>這個版本利用 <code>isDefined</code> 去判定是否為空值,這樣的寫法跟使用 <code>Null</code> 當回傳值一樣,在這個版本完全看不出使用 <code>Option</code> 好處,反而顯得冗餘.</p><p>我們改寫另外一個版本 <code>getJsonProfile</code> :<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">getJsonProfile</span></span>(name: <span class="type">UserName</span>, password: <span class="type">Password</span>, country: <span class="type">Country</span>): <span class="type">Option</span>[<span class="type">String</span>] = {</span><br><span class="line"> <span class="type">Repo</span>.login(name, password).flatMap(</span><br><span class="line"> account => {</span><br><span class="line"> <span class="keyword">if</span> (account.userType == <span class="type">ADMIN</span>) {</span><br><span class="line"> <span class="type">Repo</span>.getAccountsByCountry(country).flatMap(profiles => listToJson(profiles))</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="type">None</span></span><br><span class="line"> })</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p><p>我們利用 <code>flatMap</code> 來幫串接,而不是嘗試取得 <code>Option</code> 裡面的值,<code>Option</code> 的 <code>flatMap</code> 的 signature 為 <code>A => Option[B]</code>.</p><p>例如: <code>getAccountsByCountry</code> 需依賴 <code>login</code> 的結果,才可以進行之後的動作.我們是透過 <code>flatMap</code> 將這兩個動作串接起來,<br>這樣就可以避免一堆冗餘 <code>if else</code> 檢查.</p><p>再舉一個抽象的例子:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">A</span></span>(a: <span class="type">A</span>): <span class="type">Option</span>[<span class="type">B</span>] = ???</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">B</span></span>(b: <span class="type">B</span>): <span class="type">Option</span>[<span class="type">C</span>] = ???</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">C</span></span>(c: <span class="type">C</span>): <span class="type">Option</span>[<span class="type">D</span>] = ???</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">total</span></span>(input: <span class="type">Option</span>[<span class="type">A</span>]): <span class="type">Option</span>[<span class="type">D</span>] = {</span><br><span class="line"> input.flatMap(<span class="type">A</span>(_).flatMap(<span class="type">B</span>(_).flatMap(<span class="type">C</span>(_))))</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>可以透過 <code>flatMap</code> 串接 <code>A</code>, <code>B</code>, <code>C</code> 這三個function,假如用 <code>isDefined</code> 來串接,程式碼的可讀性和維護性會大幅下降.<br>在 <code>Function Programming</code>中,常見的pattern會將值放到一個context裡面,在使用時候並不會將值取出來,而是透過 <code>flatMap</code> 或 <code>map</code> 來轉換context裡面的值.</p><p>我們可以傳入 <code>parse</code> 過後的結果,將所有的function串接在一起:<br><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">object</span> <span class="title">Api</span> <span class="keyword">extends</span> <span class="title">App</span> </span>{</span><br><span class="line"> <span class="keyword">val</span> name: <span class="type">Option</span>[<span class="type">UserName</span>] = parse(<span class="type">UserName</span>(args(<span class="number">0</span>)))</span><br><span class="line"> <span class="keyword">val</span> password: <span class="type">Option</span>[<span class="type">MD5Password</span>] = parse(<span class="type">MD5Password</span>(args(<span class="number">1</span>)))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">val</span> json: <span class="type">Option</span>[<span class="type">String</span>] = getJsonProfile(name, password, <span class="type">CHINA</span>)</span><br><span class="line"> <span class="keyword">if</span> (json.isDefined) {</span><br><span class="line"> returnHttpResponse(json.get)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> returnHttpResponse(<span class="string">""</span>)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">def</span> <span class="title">getJsonProfile</span></span>(name: <span class="type">Option</span>[<span class="type">UserName</span>], password: <span class="type">Option</span>[<span class="type">Password</span>], country: <span class="type">Country</span>): <span class="type">Option</span>[<span class="type">String</span>] = {</span><br><span class="line"> name.flatMap(name1 =></span><br><span class="line"> password.flatMap(password1 =></span><br><span class="line"> <span class="type">Repo</span>.login(name1, password1).flatMap(</span><br><span class="line"> account => {</span><br><span class="line"> <span class="keyword">if</span> (account.userType == <span class="type">ADMIN</span>) {</span><br><span class="line"> <span class="type">Repo</span>.getAccountsByCountry(country).flatMap(profiles => listToJson(profiles))</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="type">None</span></span><br><span class="line"> })</span><br><span class="line"> ))</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// other functions</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>可以發現串接的function越多,會越寫越右邊,有點類似 <code>Callback hell</code> ,或許也可以稱為 <code>flatMap hell</code>…<br>好險Scala有提供很好的 syntax sugar <code>for comprehension</code> 來解決 <code>flatMap hell</code></p><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">object</span> <span class="title">Api</span> <span class="keyword">extends</span> <span class="title">App</span> </span>{</span><br><span class="line"> <span class="keyword">val</span> name: <span class="type">Option</span>[<span class="type">UserName</span>] = parse(<span class="type">UserName</span>(args(<span class="number">0</span>)))</span><br><span class="line"> <span class="keyword">val</span> password: <span class="type">Option</span>[<span class="type">MD5Password</span>] = parse(<span class="type">MD5Password</span>(args(<span class="number">1</span>)))</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> {</span><br><span class="line"> name1 <- name</span><br><span class="line"> password1 <- password</span><br><span class="line"> account <- <span class="type">Repo</span>.login(name1, password1).filter(a => a.userType == <span class="type">ADMIN</span>)</span><br><span class="line"> profiles <- <span class="type">Repo</span>.getAccountsByCountry(<span class="type">CHINA</span>)</span><br><span class="line"> json <- listToJson(profiles)</span><br><span class="line"> } <span class="keyword">yield</span> {</span><br><span class="line"> returnHttpResponse(json)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// other functions</span></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>比較第一個版本和最後一個版本的程式碼,最後一個版本可以很清楚表達整個程式意圖,而不會被一堆 <code>if else</code> 檢查而干擾.<br>透過正確使用 <code>Option</code> 我們可以學習到:</p><ol><li>分離資料和行為</li><li>將資料放入context</li><li>利用 <code>flatMap</code>, <code>map</code> 轉換context裡面的值</li></ol><h3 id="衍生需求"><a href="#衍生需求" class="headerlink" title="衍生需求"></a>衍生需求</h3><p>最後一個版本可以發現<br>payload不正確或某個國家的使用者為零</p><p>結果竟然都是<code>None</code>,這樣會造成使用者體驗不佳和維護上的困難.那我們可以怎麼改善呢?</p><p>可以改用 <code>Try</code> 或 <code>Either</code> 來表達錯誤,在這邊使用 <code>Option</code> 來表示parse完的結果不太洽當,主要是展示可以透過compse方式來串接多個function,下一篇將改用 <code>Try</code> 或 <code>Either</code> ,讓前端可以清楚知道錯誤訊息.</p><h3 id="參考:"><a href="#參考:" class="headerlink" title="參考:"></a>參考:</h3><ol><li><a href="http://tpolecat.github.io/presentations/algebraic_types.html#1" target="_blank" rel="noopener">Introduction to Algebraic Types in Scala</a></li></ol>]]></content>
<summary type="html">
<p>&#x5C0D;&#x65BC;Scala&#x6211;&#x4E00;&#x76F4;&#x628A;&#x5B83;&#x7576;&#x6210;&#x9032;&#x968E;&#x7248;&#x672C;&#x7684;Java&#xFF0C;&#x7576;
</summary>
<category term="Scala" scheme="https://pandaforme.github.io/categories/Scala/"/>
<category term="Scala" scheme="https://pandaforme.github.io/tags/Scala/"/>
<category term="Option" scheme="https://pandaforme.github.io/tags/Option/"/>
</entry>
<entry>
<title>[Java] Java is Pass by Value and Not Pass by Reference</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/</id>
<published>2016-12-09T11:00:43.000Z</published>
<updated>2016-12-13T07:25:36.000Z</updated>
<content type="html"><![CDATA[<p>Java到底是pass by value還是pass by reference?說法眾說紛紜,後來看到這篇文章<a href="http://www.journaldev.com/3884/java-is-pass-by-value-and-not-pass-by-reference" target="_blank" rel="noopener">Java is Pass by Value and Not Pass by Reference</a>後,觀念才整個釐清。</p><p><strong><em>Java是pass by value!</em></strong></p><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Balloon</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> Stringcolor;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Balloon</span><span class="params">()</span> </span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Balloon</span><span class="params">(String c)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.color = c;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getColor</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> color;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.color = color;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">Balloon red = <span class="keyword">new</span> Balloon(<span class="string">"Red"</span>);</span><br><span class="line">Balloon blue = <span class="keyword">new</span> Balloon(<span class="string">"Blue"</span>);</span><br><span class="line"></span><br><span class="line">swap(red, blue);</span><br><span class="line">System.out.println(<span class="string">"red color="</span> + red.getColor());</span><br><span class="line">System.out.println(<span class="string">"blue color="</span> + blue.getColor());</span><br><span class="line"></span><br><span class="line">foo(blue);</span><br><span class="line">System.out.println(<span class="string">"blue color="</span> + blue.getColor());</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">foo</span><span class="params">(Balloon balloon)</span> </span>{</span><br><span class="line">balloon.setColor(<span class="string">"Red"</span>);</span><br><span class="line">balloon = <span class="keyword">new</span> Balloon(<span class="string">"Green"</span>);</span><br><span class="line">balloon.setColor(<span class="string">"Blue"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(Object o1, Object o2)</span> </span>{</span><br><span class="line">Object temp = o1;</span><br><span class="line">o1 = o2;</span><br><span class="line">o2 = temp;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap1</span><span class="params">(Balloon o1, Balloon o2)</span> </span>{</span><br><span class="line">String temp = o1.getColor();</span><br><span class="line">o1.setColor(o2.getColor());</span><br><span class="line">o2.setColor(temp);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>結果:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">//使用swap()</span><br><span class="line">red color=Red</span><br><span class="line">blue color=Blue</span><br><span class="line">blue color=Red</span><br><span class="line"></span><br><span class="line">//使用swap1()</span><br><span class="line">red color=Blue</span><br><span class="line">blue color=Red</span><br><span class="line">blue color=Red</span><br></pre></td></tr></table></figure></p><p>分析:</p><ol><li>尚未執行swap():<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-7--1.png" alt=""></li><li>執行swap(),o1指向red,o2指向blue:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-1---1--1.png" alt=""></li><li>swap()執行結束,原本的物件並沒有互相交換:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-2--1.png" alt=""></li><li>執行foo(),ballon指向blue:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-3--1.png" alt=""></li><li>執行foo()第一行,透過原本物件的setter method修改值:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-4--1.png" alt=""></li><li>執行foo()第二行:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-5--2.png" alt=""></li><li>執行foo()第三行:<img src="/2016/12/09/Java-Java-is-Pass-by-Value-and-Not-Pass-by-Reference/Untitled-6--2.png" alt=""></li></ol><p>因為Java是採用pass by value作法,當以物件作為參數傳入到method,在method裡面想要修改物件的值,需透過物件的setter method,這樣原本物件的值才會連帶一起變更。透過assign(=)或new等方式,原本物件的值都不會有變化。</p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.journaldev.com/3884/java-is-pass-by-value-and-not-pass-by-reference" target="_blank" rel="noopener">Java is Pass by Value and Not Pass by Reference</a></li></ul>]]></content>
<summary type="html">
<p>Java&#x5230;&#x5E95;&#x662F;pass by value&#x9084;&#x662F;pass by reference&#xFF1F;&#x8AAA;&#x6CD5;&#x773E;&#x8AAA;&#x7D1B;&#x7D1C;&#xFF0C
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] Java String Pool</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Java-String-Pool/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Java-String-Pool/</id>
<published>2016-12-09T10:57:57.000Z</published>
<updated>2016-12-13T07:25:39.000Z</updated>
<content type="html"><![CDATA[<p>假如沒有string pool這樣的機制,遇到string就建立一個物件,這樣記憶體就很快就會爆掉了。</p><p>在java中採取<a href="http://en.wikipedia.org/wiki/Flyweight_pattern" target="_blank" rel="noopener">Flyweight pattern</a>作法,可以共享同樣的string object。</p><p><img src="http://www.journaldev.com/wp-content/uploads/2012/11/String-Pool-Java1.png" alt=""></p><p>建立string object有兩種方式:</p><ol><li>String string = “Cat”;</li><li>String string = new String(“Cat”);</li></ol><p>採用第一種方法,會先檢查string pool是否有相同的string。若有就共用,沒有則建立之。</p><p>採用第二種方法﹐不會使用到string pool機制,而是在heap建立一個新的string object。若之後想要使用string pool機制,可以使用<a href="http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern%28%29" target="_blank" rel="noopener">intern</a>。</p><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StringExample</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>{</span><br><span class="line">String s1 = <span class="string">"Cat"</span>;</span><br><span class="line">String s2 = <span class="string">"Cat"</span>;</span><br><span class="line">String s3 = <span class="keyword">new</span> String(<span class="string">"Cat"</span>);</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"s1 == s2 ?"</span> + (s1 == s2));</span><br><span class="line">System.out.println(<span class="string">"s1 == s3 ?"</span> + (s1 == s3));</span><br><span class="line">System.out.println(<span class="string">"s1 == s3.intern() ?"</span> + (s1 == s3.intern()));</span><br><span class="line">System.out.println(<span class="string">"s1 equals s3 ?"</span> + s1.equals(s3));</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>結果:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">s1 == s2 ?true</span><br><span class="line">s1 == s3 ?false</span><br><span class="line">s1 == s3.intern() ?true</span><br><span class="line">s1 equals s3 ?true</span><br></pre></td></tr></table></figure></p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.journaldev.com/797/what-is-java-string-pool" target="_blank" rel="noopener">What is Java String Pool?</a></li></ul>]]></content>
<summary type="html">
<p>&#x5047;&#x5982;&#x6C92;&#x6709;string pool&#x9019;&#x6A23;&#x7684;&#x6A5F;&#x5236;&#xFF0C;&#x9047;&#x5230;string&#x5C31;&#x5EFA;&#x7ACB;
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[SQL] How to get rank using ANSI SQL</title>
<link href="https://pandaforme.github.io/2016/12/09/SQL-How-to-get-rank-using-ANSI-SQL/"/>
<id>https://pandaforme.github.io/2016/12/09/SQL-How-to-get-rank-using-ANSI-SQL/</id>
<published>2016-12-09T10:57:02.000Z</published>
<updated>2016-12-13T07:16:52.000Z</updated>
<content type="html"><![CDATA[<p>要對分數做排名,最直接的想法就對它們做ORDER BY。但是當分數有重複時候排名是要一樣,這時候ORDER BY就發揮不了作用。</p><p>不同的廠商的資料庫有提供不同的函數可以解決這個問題,假如沒有使用函數該如何做到呢?</p><h4 id="建立資料表:"><a href="#建立資料表:" class="headerlink" title="建立資料表:"></a>建立資料表:</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`golf`</span> (</span><br><span class="line"> <span class="string">`id`</span> <span class="built_in">int</span>(<span class="number">11</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> AUTO_INCREMENT,</span><br><span class="line"> <span class="string">`name`</span> <span class="built_in">varchar</span>(<span class="number">45</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="string">`score`</span> <span class="built_in">int</span>(<span class="number">11</span>) <span class="keyword">DEFAULT</span> <span class="literal">NULL</span>,</span><br><span class="line"> PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h4 id="新增資料:"><a href="#新增資料:" class="headerlink" title="新增資料:"></a>新增資料:</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (A,<span class="number">74</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (B,<span class="number">79</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (C,<span class="number">79</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (D,<span class="number">82</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (E,<span class="number">89</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (F,<span class="number">89</span>);</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`golf`</span>(<span class="string">`name`</span>,<span class="string">`score`</span>) <span class="keyword">VALUES</span> (G,<span class="number">98</span>);</span><br></pre></td></tr></table></figure><h4 id="查詢:"><a href="#查詢:" class="headerlink" title="查詢:"></a>查詢:</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> tmp.name,</span><br><span class="line"> tmp.score,</span><br><span class="line"> (<span class="keyword">SELECT</span> </span><br><span class="line"> <span class="keyword">COUNT</span>(*) + <span class="number">1</span></span><br><span class="line"> <span class="keyword">FROM</span></span><br><span class="line"> (<span class="keyword">SELECT</span> </span><br><span class="line"> golf.score</span><br><span class="line"> <span class="keyword">FROM</span></span><br><span class="line"> golf</span><br><span class="line"> <span class="keyword">GROUP</span> <span class="keyword">BY</span> golf.score) <span class="keyword">AS</span> tmp1</span><br><span class="line"> <span class="keyword">WHERE</span></span><br><span class="line"> tmp1.score > tmp.score) <span class="keyword">AS</span> <span class="keyword">rank</span></span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> golf <span class="keyword">AS</span> tmp</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> tmp.score <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure><h4 id="結果:"><a href="#結果:" class="headerlink" title="結果:"></a>結果:</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">namescorerank</span><br><span class="line">G981</span><br><span class="line">E892</span><br><span class="line">F892</span><br><span class="line">D823</span><br><span class="line">B794</span><br><span class="line">C794</span><br><span class="line">A745</span><br></pre></td></tr></table></figure><h4 id="想法:"><a href="#想法:" class="headerlink" title="想法:"></a>想法:</h4><p>先從排名這個概念下手,假如有三個人的分數(這三人分數都不一樣)大於我的分數,那麼我就是排名第四。因為分數重複的排名是一樣的,需要先對分數做一次GROUP BY,再根據上述的概念去算出排名。</p>]]></content>
<summary type="html">
<p>&#x8981;&#x5C0D;&#x5206;&#x6578;&#x505A;&#x6392;&#x540D;&#xFF0C;&#x6700;&#x76F4;&#x63A5;&#x7684;&#x60F3;&#x6CD5;&#x5C31;&#x5C0D;&#x5B83;&
</summary>
<category term="SQL" scheme="https://pandaforme.github.io/categories/SQL/"/>
<category term="SQL" scheme="https://pandaforme.github.io/tags/SQL/"/>
</entry>
<entry>
<title>[Java] Synchronize in Java</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Synchronize-in-Java/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Synchronize-in-Java/</id>
<published>2016-12-09T09:31:00.000Z</published>
<updated>2018-05-09T00:04:30.290Z</updated>
<content type="html"><![CDATA[<p>在了解Java的synchronized機制之前,先來複習一下Monitor。</p><p>可以把Monitor想像成它就是一個類別,裡面存放著共享變數、方法和建構子。<br><img src="/2016/12/09/Java-Synchronize-in-Java/Monitor.png" alt="Monitor"><br>Monitor會確保只有一個Process可以進入,其他也想要進入的Process,就必須在queue裡面等待。程式設計師可以根據不同的情況,決定是否要讓正在Monitor的Process進入waiting state或是喚醒其他在waiting state的Process。</p><p>例如:當某個Process取得Monitor的執行權利,在執行過程中發現不符合x情況,必須進入waiting state,可以使用x.wait()。想要喚醒x queue中的waiting Process,可以透過x.signal()。詳細可以參考<a href="http://www.amazon.com/Operating-System-Concepts-Abraham-Silberschatz/dp/1118063333/ref=sr_1_1?s=books&ie=UTF8&qid=1409112396&sr=1-1&keywords=Operating+System+Concepts" target="_blank" rel="noopener">Operating System Concepts</a>。</p><p>Java的synchronized就是實作了Monitor,Object的wait()和notify()就相當於wait()和signal()。有了這樣的概念後,在使用synchronized就比較不會發生鎖錯對象的問題。</p><p>synchronized使用方式可以分為兩種:</p><ol><li>synchronized method </li><li>synchronized block</li></ol><h1 id="範例"><a href="#範例" class="headerlink" title="範例"></a>範例</h1><p>TargetObject.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TargetObject</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span>count= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">method1</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in method1 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">method2</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in method2 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticMethod1</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in static method1 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticMethod2</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in static method2 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Thread1.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Thread1</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="keyword">private</span> TargetObjecttargetObject;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Thread1</span><span class="params">(TargetObject targetObject)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.targetObject = targetObject;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"><span class="keyword">this</span>.targetObject.method1();</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Thread2.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Thread2</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="keyword">private</span> TargetObjecttargetObject;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Thread1</span><span class="params">(TargetObject targetObject)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.targetObject = targetObject;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"><span class="keyword">this</span>.targetObject.method2();</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Run.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Run</span> </span>{</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">TargetObjecttargetObject= <span class="keyword">new</span> TargetObject();</span><br><span class="line">Thread thread1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Thread1(targetObject), <span class="string">"Thread1"</span>);</span><br><span class="line">Thread thread2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Thread2(targetObject), <span class="string">"Thread2"</span>);</span><br><span class="line">thread1.start();</span><br><span class="line">thread2.start();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>執行結果:沒有做同步處理,會存在race condition。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Thread1 in method1 and count = <span class="number">2</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">2</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">3</span></span><br><span class="line">Thread1 in method1 and count = <span class="number">4</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">5</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">6</span></span><br></pre></td></tr></table></figure></p><hr><h1 id="synchronized-method"><a href="#synchronized-method" class="headerlink" title="synchronized method"></a>synchronized method</h1><p>在TargetObject.java中的method1和method2加上 <code>synchronized</code> 就可以鎖定由TargetObject類別所實體化的物件targetObject。</p><p>TargetObject.java<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TargetObject</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span>count= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">method1</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in method1 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">method2</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in method2 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticMethod1</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in static method1 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticMethod2</span><span class="params">()</span> </span>{</span><br><span class="line">count++;</span><br><span class="line">System.out.println(Thread.currentThread().getName() + <span class="string">" in static method2 and count = "</span> + count);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>執行結果:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Thread1 in method1 and count = <span class="number">1</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">2</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">3</span></span><br><span class="line">Thread1 in method1 and count = <span class="number">4</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">5</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">6</span></span><br><span class="line">Thread1 in method1 and count = <span class="number">7</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">8</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">9</span></span><br></pre></td></tr></table></figure></p><hr><p>為了更清楚了解鎖定的對象,現在先 <strong>移除</strong> method1的synchronized,將同步機制移到Thread1.java。</p><p>Thread1.java<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Thread1</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="keyword">private</span> TargetObjecttargetObject;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Thread1</span><span class="params">(TargetObject targetObject)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.targetObject = targetObject;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"><span class="keyword">synchronized</span> (targetObject) {</span><br><span class="line"><span class="keyword">this</span>.targetObject.method1();</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>執行結果:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Thread1 in method1 and count = <span class="number">1</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">2</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">3</span></span><br><span class="line">Thread1 in method1 and count = <span class="number">4</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">5</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">6</span></span><br><span class="line">Thread1 in method1 and count = <span class="number">7</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">8</span></span><br><span class="line">Thread2 in method2 and count = <span class="number">9</span></span><br></pre></td></tr></table></figure></p><p>從執行結果可以看出上鎖的對象是在Run.java中實體化的 <strong>targetObject</strong>。</p><hr><p>若將</p><ul><li>Thread1.java中的 <code>this.targetObject.method1()</code> 改成 <code>TargetObject.staticMethod1()</code>。</li><li>Thread2.java中的 <code>this.targetObject.method2()</code> 改成 <code>TargetObject.staticMethod2()</code>。</li></ul><p>必須對TargetObject的staticMethod1和staticMethod2做 <code>synchronized</code> 。<br>透過上述的方式可以知道synchronized static method是鎖定 <code>TargetObject.class</code>。</p><hr><h1 id="synchronized-block"><a href="#synchronized-block" class="headerlink" title="synchronized block"></a>synchronized block</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(想要鎖定的物件或是<span class="class"><span class="keyword">class</span> <span class="title">literal</span>)</span>{</span><br><span class="line"> <span class="comment">//do something</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>synchronized block較有彈性,可以選擇鎖定的對象。<br>Thread1.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Thread1</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="keyword">private</span> TargetObjecttargetObject;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">byte</span>[]lock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Thread1</span><span class="params">(TargetObject targetObject, <span class="keyword">byte</span>[] lock)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.targetObject = targetObject;</span><br><span class="line"><span class="keyword">this</span>.lock = lock;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"><span class="keyword">synchronized</span> (<span class="keyword">this</span>.lock) {</span><br><span class="line"><span class="keyword">this</span>.targetObject.method1();</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Thread2.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Thread2</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="keyword">private</span> TargetObjecttargetObject;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">byte</span>[]lock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Thread2</span><span class="params">(TargetObject targetObject, <span class="keyword">byte</span>[] lock)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.targetObject = targetObject;</span><br><span class="line"><span class="keyword">this</span>.lock = lock;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"><span class="keyword">synchronized</span> (<span class="keyword">this</span>.lock) {</span><br><span class="line"><span class="keyword">this</span>.targetObject.method2();</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Run.java:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Run</span> </span>{</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">TargetObject targetObject = <span class="keyword">new</span> TargetObject();</span><br><span class="line"><span class="keyword">final</span> <span class="keyword">byte</span>[] lock = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">0</span>];</span><br><span class="line">Thread thread1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Thread1(targetObject, lock), <span class="string">"Thread1"</span>);</span><br><span class="line">Thread thread2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Thread2(targetObject, lock), <span class="string">"Thread2"</span>);</span><br><span class="line">thread1.start();</span><br><span class="line">thread2.start();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>在使用synchronized的時候,務必要搞清楚鎖定的對象,沒有搞清楚反而等同於沒有同步。</p>]]></content>
<summary type="html">
<p>&#x5728;&#x4E86;&#x89E3;Java&#x7684;synchronized&#x6A5F;&#x5236;&#x4E4B;&#x524D;&#xFF0C;&#x5148;&#x4F86;&#x8907;&#x7FD2;&#x4E00;&#x4E0B;M
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[SQL] 5 types of SQL JOIN</title>
<link href="https://pandaforme.github.io/2016/12/09/SQL-5-types-of-SQL-JOIN/"/>
<id>https://pandaforme.github.io/2016/12/09/SQL-5-types-of-SQL-JOIN/</id>
<published>2016-12-09T09:30:08.000Z</published>
<updated>2016-12-13T07:16:46.000Z</updated>
<content type="html"><![CDATA[<p>ANSI-standard SQL有五種JOIN:</p><ol><li>INNER JOIN</li><li>LEFT OUTER JOIN</li><li>RIGHT OUTER JOIN</li><li>FULL OUTER JOIN</li><li>CROSS JOIN</li></ol><p><a href="http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/" target="_blank" rel="noopener">A Visual Explanation of SQL Joins</a>用<a href="http://en.wikipedia.org/wiki/Venn_diagram" target="_blank" rel="noopener">Venn diagrams</a>方式圖解JOIN。</p><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">TableA TableB</span><br><span class="line">id name id name</span><br><span class="line">-- ---- -- ----</span><br><span class="line">1 Pirate 1 Rutabaga</span><br><span class="line">2 Monkey 2 Pirate</span><br><span class="line">3 Ninja 3 Darth Vader</span><br><span class="line">4 Spaghetti 4 Ninja</span><br></pre></td></tr></table></figure><ul><li>INNER JOIN:</li></ul><p>SQL:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">FROM</span> TableA</span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> TableB</span><br><span class="line"><span class="keyword">ON</span> TableA.name = TableB.name</span><br></pre></td></tr></table></figure></p><p>結果:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">TableA TableB</span><br><span class="line">id name id name</span><br><span class="line">-- ---- -- ----</span><br><span class="line">1 Pirate 2 Pirate</span><br><span class="line">3 Ninja 4 Ninja</span><br></pre></td></tr></table></figure></p><p>Venn diagram:<br><img src="http://blog.codinghorror.com/content/images/uploads/2007/10/6a0120a85dcdae970b012877702708970c-pi.png" alt=""></p><p><em>列出兩個Table共有的資料,即兩個Table的交集。</em></p><hr><ul><li>LEFT OUTER JOIN:</li></ul><p>SQL:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">FROM</span> TableA</span><br><span class="line"><span class="keyword">LEFT</span> <span class="keyword">OUTER</span> <span class="keyword">JOIN</span> TableB</span><br><span class="line"><span class="keyword">ON</span> TableA.name = TableB.name</span><br></pre></td></tr></table></figure></p><p>結果:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">TableA TableB</span><br><span class="line">id name id name</span><br><span class="line">-- ---- -- ----</span><br><span class="line">1 Pirate 2 Pirate</span><br><span class="line">2 Monkey null null</span><br><span class="line">3 Ninja 4 Ninja</span><br><span class="line">4 Spaghetti null null</span><br></pre></td></tr></table></figure></p><p>Venn diagram:<br><img src="http://blog.codinghorror.com/content/images/uploads/2007/10/6a0120a85dcdae970b01287770273e970c-pi.png" alt=""><br><em>以左邊Table為主,若沒有配對到資料,顯示null。</em></p><hr><ul><li>RIGHT OUTER JOIN:</li></ul><p>跟LEFT OUTER JOIN大同小異,結果改成以Table B為主,不再贅述。</p><hr><ul><li>FULL OUTER JOIN:</li></ul><p>SQL:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">FROM</span> TableA</span><br><span class="line"><span class="keyword">FULL</span> <span class="keyword">OUTER</span> <span class="keyword">JOIN</span> TableB</span><br><span class="line"><span class="keyword">ON</span> TableA.name = TableB.name</span><br></pre></td></tr></table></figure></p><p>結果:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">TableA TableB</span><br><span class="line">id name id name</span><br><span class="line">-- ---- -- ----</span><br><span class="line">1 Pirate 2 Pirate</span><br><span class="line">2 Monkey null null</span><br><span class="line">3 Ninja 4 Ninja</span><br><span class="line">4 Spaghetti null null</span><br><span class="line">null null 1 Rutabaga</span><br><span class="line">null null 3 Darth Vader</span><br></pre></td></tr></table></figure></p><p>Venn diagram:<br><img src="http://blog.codinghorror.com/content/images/uploads/2007/10/6a0120a85dcdae970b012877702725970c-pi.png" alt=""><br><em>為兩個Table的聯集,若沒有配對到資料以null顯示。</em></p><hr><ul><li>CROSS JOIN:<br>即是<a href="http://en.wikipedia.org/wiki/Cartesian_product" target="_blank" rel="noopener">Cartesian product</a>,會產生兩個Table所有的組合。<br>SQL:<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">FROM</span> TableA</span><br><span class="line"><span class="keyword">CROSS</span> <span class="keyword">JOIN</span> TableB</span><br></pre></td></tr></table></figure></li></ul><p>結果:<br>4*4 = 16種組合</p><p><em>因為CROSS JOIN會將所有組合列出來,所以當資料量龐大時候,效能會變得很差。</em></p><h3 id="總結:"><a href="#總結:" class="headerlink" title="總結:"></a>總結:</h3><p>可以利用以上的五種JOIN和過濾方式,對兩個集合進行交集、聯集、差集等操作。<br><img src="http://edwarcardona.files.wordpress.com/2013/03/sql_server_joins.jpg" alt="SQL JOINS"></p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/" target="_blank" rel="noopener">A Visual Explanation of SQL Joins</a></li><li><a href="https://en.wikipedia.org/wiki/Join_(SQL" target="_blank" rel="noopener">Join (SQL)</a>)</li><li><a href="http://coolshell.cn/articles/3463.html" target="_blank" rel="noopener">圖解SQL的Join</a> </li><li><a href="http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins" target="_blank" rel="noopener">Visual Representation of SQL Joins</a></li></ul>]]></content>
<summary type="html">
<p>ANSI-standard SQL&#x6709;&#x4E94;&#x7A2E;JOIN&#xFF1A;</p>
<ol>
<li>INNER JOIN</li>
<li>LEFT OUTER JOIN</li>
<li>RIGHT OUTER JOIN</li>
<li
</summary>
<category term="SQL" scheme="https://pandaforme.github.io/categories/SQL/"/>
<category term="SQL" scheme="https://pandaforme.github.io/tags/SQL/"/>
</entry>
<entry>
<title>The Law of Demeter</title>
<link href="https://pandaforme.github.io/2016/12/09/The-Law-of-Demeter/"/>
<id>https://pandaforme.github.io/2016/12/09/The-Law-of-Demeter/</id>
<published>2016-12-09T09:27:16.000Z</published>
<updated>2016-12-09T09:27:32.000Z</updated>
<content type="html"><![CDATA[<p>更詳細的說法是“Law of Demeter for Functions/Methods” (LoD-F),簡單化Object之間的互動,讓多個Object不要互相相依。</p><h2 id="定義:"><a href="#定義:" class="headerlink" title="定義:"></a>定義:</h2><p>The Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:</p><ol><li>O itself</li><li>M’s parameters</li><li>Any objects created/instantiated within M</li><li>O’s direct component objects</li><li>A global variable, accessible by O, in the scope of M</li></ol><h2 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A Law of Demeter example in Java.</span></span><br><span class="line"><span class="comment"> * Created by Alvin Alexander, <a href="http://devdaily.com" title="http://devdaily.com">http://devdaily.com</a>.</span></span><br><span class="line"><span class="comment"> * This is an adaptation of the source code example from the book</span></span><br><span class="line"><span class="comment"> * The Pragmatic Programmer.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LawOfDemeterInJava</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> Topping cheeseTopping;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Good examples of following the Law of Demeter.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">goodExamples</span><span class="params">(Pizza pizza)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Foo foo = <span class="keyword">new</span> Foo();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// (1) it's okay to call our own methods</span></span><br><span class="line"> doSomething();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// (2) it's okay to call methods on objects passed in to our method</span></span><br><span class="line"> <span class="keyword">int</span> price = pizza.getPrice();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// (3) it's okay to call methods on any objects we create</span></span><br><span class="line"> cheeseTopping = <span class="keyword">new</span> CheeseTopping();</span><br><span class="line"> <span class="keyword">float</span> weight = cheeseTopping.getWeightUsed();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// (4) any directly held component objects</span></span><br><span class="line"> foo.doBar();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doSomething</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">// do something here ...</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h2><ul><li><a href="http://en.wikipedia.org/wiki/Law_of_Demeter" target="_blank" rel="noopener">Law_of_Demeter</a></li><li><a href="http://alvinalexander.com/java/java-law-of-demeter-java-examples" target="_blank" rel="noopener">Law of Demeter - Java examples</a></li></ul>]]></content>
<summary type="html">
<p>&#x66F4;&#x8A73;&#x7D30;&#x7684;&#x8AAA;&#x6CD5;&#x662F;&#x201C;Law of Demeter for Functions/Methods&#x201D; (LoD-F)&#xFF0C;&#x7C21;&#x55
</summary>
</entry>
<entry>
<title>[Java] Object equality in Java</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Object-equality-in-Java/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Object-equality-in-Java/</id>
<published>2016-12-09T09:26:05.000Z</published>
<updated>2016-12-13T07:25:19.000Z</updated>
<content type="html"><![CDATA[<p>在Java中,要比較兩個基本型態的變數,要使用<code>==</code>。<br>要比較兩個物件型態的變數,要使用<code>equals</code>。</p><p>因為所有的物件都是繼承Object,加上Object的equals()是使用<code>==</code>判定,所以需要Override Object的<code>equals()</code>函式。</p><p>Object的<code>equals()</code>函式:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object paramObject)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> (<span class="keyword">this</span> == paramObject);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Point</span> </span>{</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span>x;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span>y;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Point</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.x = x;</span><br><span class="line"><span class="keyword">this</span>.y = y;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object that)</span> </span>{</span><br><span class="line"><span class="keyword">if</span> (that <span class="keyword">instanceof</span> Point) {</span><br><span class="line">Point point = (Point) that;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">this</span>.x == point.x && <span class="keyword">this</span>.y == point.y;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> Objects.hash(x,y);</span><br><span class="line">} </span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>注意:當Override equals時,hashCode最好也要Override。</li></ul><p>例如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PointTest</span> </span>{</span><br><span class="line"><span class="keyword">private</span> Objectpoint1;</span><br><span class="line"><span class="keyword">private</span> Pointpoint2;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Before</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setUp</span><span class="params">()</span> </span>{</span><br><span class="line">point1 = <span class="keyword">new</span> Point(<span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">point2 = <span class="keyword">new</span> Point(<span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">testCase</span><span class="params">()</span> </span>{</span><br><span class="line">Set<Object> set = <span class="keyword">new</span> HashSet<Object>();</span><br><span class="line">set.add(point1);</span><br><span class="line">assertTrue(set.contains(point2));</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><ol><li>計算point2的hashCode</li><li>計算point1的hashCode</li><li>若hashCode一樣代表落在同一個bucket</li><li>再透過equals判別是否相等</li></ol><p>hashCode可以透過Objects.hash()協助計算,或是自行設計公式。<br>例如:<a href="http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#hashCode(" target="_blank" rel="noopener">String的hashCode</a>)。</p><p>有蠻多類似的文章提到為什麼要用31當乘數呢?例如:<a href="http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier" target="_blank" rel="noopener">Why does Java’s hashCode() in String use 31 as a multiplier?</a></p><p>查了相關的討論幾乎都是31式質數並且jvm可以對其做最佳化,個人推測主要原因31可以大幅降低collision的機會,或許演算法或是有相關的論文會有更詳細的說明。</p><h4 id="相關資料:"><a href="#相關資料:" class="headerlink" title="相關資料:"></a>相關資料:</h4><p><a href="http://www.codedata.com.tw/java/object-equality-1/" target="_blank" rel="noopener">物件相等性(上)</a></p><h4 id="範例的原始碼:https-github-com-pandaforme-ObjectEqual"><a href="#範例的原始碼:https-github-com-pandaforme-ObjectEqual" class="headerlink" title="範例的原始碼:https://github.com/pandaforme/ObjectEqual"></a>範例的原始碼:<a href="https://github.com/pandaforme/ObjectEqual" target="_blank" rel="noopener">https://github.com/pandaforme/ObjectEqual</a></h4>]]></content>
<summary type="html">
<p>&#x5728;Java&#x4E2D;&#xFF0C;&#x8981;&#x6BD4;&#x8F03;&#x5169;&#x500B;&#x57FA;&#x672C;&#x578B;&#x614B;&#x7684;&#x8B8A;&#x6578;&#xFF0C;&#x89
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] Multiple parameters in a constructor</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Multiple-parameters-in-a-constructor/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Multiple-parameters-in-a-constructor/</id>
<published>2016-12-09T09:25:31.000Z</published>
<updated>2016-12-13T07:25:25.000Z</updated>
<content type="html"><![CDATA[<p>在開發的過程中很常會碰到需要傳入大量的參數到建構子的情況,這樣做法會讓其他人不易理解,造成維護和測試上的困難。在<a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank" rel="noopener">Clean Code: A Handbook of Agile Software Craftsmanship</a>有提到:函式的參數最好不要超過三個。</p><p>那這樣的情況應該要怎麼做會比較好呢?可以利用<a href="http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683" target="_blank" rel="noopener">Effective Java (2nd Edition)</a>中所提到的Builder pattern來解決。</p><p><em>並不是每種情況都適合使用Builder pattern來解決,Builder pattern是解法之一。</em></p><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><p>還沒有使用Builder pattern:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NutritionFacts</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servingSize; <span class="comment">// (mL) required </span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servings; <span class="comment">// (per container) required </span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> calories; <span class="comment">// optional </span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> fat; <span class="comment">// (g) optional </span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> sodium; <span class="comment">// (mg) optional </span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> carbohydrate; <span class="comment">// (g) optional </span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NutritionFacts</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(servingSize, servings, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NutritionFacts</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> calories)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(servingSize, servings, calories, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NutritionFacts</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> calories, <span class="keyword">int</span> fat)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(servingSize, servings, calories, fat, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NutritionFacts</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> calories, <span class="keyword">int</span> fat, <span class="keyword">int</span> sodium)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(servingSize, servings, calories, fat, sodium, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NutritionFacts</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> calories, <span class="keyword">int</span> fat, <span class="keyword">int</span> sodium,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> carbohydrate)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.servingSize = servingSize;</span><br><span class="line"> <span class="keyword">this</span>.servings = servings;</span><br><span class="line"> <span class="keyword">this</span>.calories = calories;</span><br><span class="line"> <span class="keyword">this</span>.fat = fat;</span><br><span class="line"> <span class="keyword">this</span>.sodium = sodium;</span><br><span class="line"> <span class="keyword">this</span>.carbohydrate = carbohydrate;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>使用Builder pattern:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NutritionFacts</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servingSize;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servings;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> calories;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> fat;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> sodium;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> carbohydrate;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Builder</span> </span>{</span><br><span class="line"> <span class="comment">// Required parameters</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servingSize;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> servings;</span><br><span class="line"> <span class="comment">// Optional parameters - initialized to default values</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> calories = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> fat = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> carbohydrate = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> sodium = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Builder</span><span class="params">(<span class="keyword">int</span> servingSize, <span class="keyword">int</span> servings)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.servingSize = servingSize;</span><br><span class="line"> <span class="keyword">this</span>.servings = servings;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Builder <span class="title">calories</span><span class="params">(<span class="keyword">int</span> val)</span> </span>{</span><br><span class="line"> calories = val;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Builder <span class="title">fat</span><span class="params">(<span class="keyword">int</span> val)</span> </span>{</span><br><span class="line"> fat = val;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Builder <span class="title">carbohydrate</span><span class="params">(<span class="keyword">int</span> val)</span> </span>{</span><br><span class="line"> carbohydrate = val;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Builder <span class="title">sodium</span><span class="params">(<span class="keyword">int</span> val)</span> </span>{</span><br><span class="line"> sodium = val;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> NutritionFacts <span class="title">build</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> NutritionFacts(<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">NutritionFacts</span><span class="params">(Builder builder)</span> </span>{</span><br><span class="line"> servingSize = builder.servingSize;</span><br><span class="line"> servings = builder.servings;</span><br><span class="line"> calories = builder.calories;</span><br><span class="line"> fat = builder.fat;</span><br><span class="line"> sodium = builder.sodium;</span><br><span class="line"> carbohydrate = builder.carbohydrate;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>initialize NutritionFacts:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">NutritionFacts sodaDrink = <span class="keyword">new</span> NutritionFacts.Builder(<span class="number">240</span>, <span class="number">8</span>).</span><br><span class="line"> calories(<span class="number">100</span>).sodium(<span class="number">35</span>).carbohydrate(<span class="number">27</span>).build();</span><br></pre></td></tr></table></figure></p><h3 id="比較:"><a href="#比較:" class="headerlink" title="比較:"></a>比較:</h3><p>優點:</p><ol><li>增加可讀性。</li><li>讓物件為immutable。</li></ol><p>缺點:</p><ol><li>builder和object的程式碼重複性很高。</li><li>新增或刪除object的attribute,需要回頭修改builder程式碼。例如:同時要Override object和builder的equals(),hashCode()。</li></ol><p><em>這裡的Builder pattern和<a href="http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612" target="_blank" rel="noopener">Design Patterns: Elements of Reusable Object-Oriented Software</a>中所提到的<a href="http://en.wikipedia.org/wiki/Builder_pattern" target="_blank" rel="noopener">Builder pattern</a>似乎不一樣,但是概念上很相近。後者會有一個共用組裝和建構Product的interface;前者因為組裝和建構流程差異過大,所以沒有共用的interface。所以前者很難做到抽換不同的Concrete Builder就可以產生不同的的Product。</em></p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.javaspecialists.eu/archive/Issue163.html" target="_blank" rel="noopener">Book Review: Effective Java 2nd Edition</a></li><li><a href="http://www.informit.com/articles/article.aspx?p=1216151&seqNum=1" target="_blank" rel="noopener">Creating and Destroying Java Objects</a></li></ul>]]></content>
<summary type="html">
<p>&#x5728;&#x958B;&#x767C;&#x7684;&#x904E;&#x7A0B;&#x4E2D;&#x5F88;&#x5E38;&#x6703;&#x78B0;&#x5230;&#x9700;&#x8981;&#x50B3;&#x5165;&#x5927;&
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] 4 types of Java inner classes</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-4-types-of-Java-inner-classes/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-4-types-of-Java-inner-classes/</id>
<published>2016-12-09T09:24:23.000Z</published>
<updated>2016-12-13T07:25:55.000Z</updated>
<content type="html"><![CDATA[<p>Java中有四種inner class,分別是:</p><ol><li>static inner class</li><li>member inner Class</li><li>local inner class</li><li>anonymous inner class</li></ol><h3 id="Static-inner-class:"><a href="#Static-inner-class:" class="headerlink" title="Static inner class:"></a>Static inner class:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OutterClass</span> </span>{</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span> </span>{</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"I am a static inner class"</span>);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">OutterClass.InnerClass innerClass = <span class="keyword">new</span> OutterClass.InnerClass();</span><br><span class="line">innerClass.print();</span><br><span class="line">} </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><em>static inner class不能存取outter class的memeber或method!若是一定要存取,則memeber或method要用static修飾。</em></p><h3 id="Member-inner-Class:"><a href="#Member-inner-Class:" class="headerlink" title="Member inner Class:"></a>Member inner Class:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OutterClass</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span>x= <span class="number">0</span>;</span><br><span class="line"><span class="keyword">private</span> InnerClassinnerClass;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">OutterClass</span><span class="params">()</span> </span>{</span><br><span class="line">innerClass = <span class="keyword">new</span> InnerClass();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span> </span>{</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>{</span><br><span class="line">x = x++;</span><br><span class="line">System.out.println(<span class="string">"Outer x is "</span> + x);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>{</span><br><span class="line">innerClass.print();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">OutterClass outterClass = <span class="keyword">new</span> OutterClass();</span><br><span class="line">outterClass.print();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ol><li><em>inner class可以自由存取outter class的member或method。</em></li><li><p><em>通常會用private修飾inner class,這樣可以避免公佈太多的細節,違反封裝原則。</em></p><h3 id="Local-inner-class:"><a href="#Local-inner-class:" class="headerlink" title="Local inner class:"></a>Local inner class:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OutterClass</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span>x= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">final</span> <span class="keyword">int</span> y = <span class="number">10</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line">System.out.println(<span class="string">"The value of x in OutterClass is "</span> + x);</span><br><span class="line">System.out.println(<span class="string">"The value of y in print() is "</span> + y);</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> Thread(<span class="keyword">new</span> InnerClass()).start();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">OutterClass outterClass = <span class="keyword">new</span> OutterClass();</span><br><span class="line">outterClass.print();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p><em>inner class可以自由存取outter class的member和method。</em></p></li><li><em>inner class要存取所在method的變數,必須使用final修飾該變數。<br>原因:以上述例子為例,當呼叫到outterClass.print(),變數y就失去作用了。然而InnerClass要再存取y就會出錯,所以才會使用final修飾變數y。即複製一份變數y給InnerClass使用,且值都不會再改變。Java 8有支援<a href="http://www.codedata.com.tw/java/understanding-lambda-closure-2-what-is-closure-2" target="_blank" rel="noopener">Closure</a>就可以解決此問題。</em><h3 id="Anonymous-inner-class:"><a href="#Anonymous-inner-class:" class="headerlink" title="Anonymous inner class:"></a>Anonymous inner class:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"><span class="keyword">new</span> Runnable() {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"I am a anonymous class"</span>);</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">};</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><p><em>性質和local inner class相同。</em></p><hr><p><em>如果多個變數為相同名稱時,預設會選用距離inner class最近的變數。不過實務上開發者很少會把變數名稱取為相同,有可能會讓讀者困惑。請參考<a href="http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#shadowing" target="_blank" rel="noopener">Shadowing</a>。</em><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ShadowTest</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">int</span> x = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">FirstLevel</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">int</span> x = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">methodInFirstLevel</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"x = "</span> + x);</span><br><span class="line"> System.out.println(<span class="string">"this.x = "</span> + <span class="keyword">this</span>.x);</span><br><span class="line"> System.out.println(<span class="string">"ShadowTest.this.x = "</span> + ShadowTest.<span class="keyword">this</span>.x);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String... args)</span> </span>{</span><br><span class="line"> ShadowTest st = <span class="keyword">new</span> ShadowTest();</span><br><span class="line"> ShadowTest.FirstLevel fl = st.new FirstLevel();</span><br><span class="line"> fl.methodInFirstLevel(<span class="number">23</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>結果:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">x = <span class="number">23</span></span><br><span class="line"><span class="keyword">this</span>.x = <span class="number">1</span></span><br><span class="line">ShadowTest.<span class="keyword">this</span>.x = <span class="number">0</span></span><br></pre></td></tr></table></figure></p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.programcreek.com/2009/02/4-inner-classes-tutorial-examples/" target="_blank" rel="noopener">4 types of Java inner classes </a></li><li><a href="http://www.codedata.com.tw/java/understanding-lambda-closure-2-what-is-closure-2" target="_blank" rel="noopener">認識 Lambda/Closure(2)什麼是 Closure?</a></li><li><a href="http://openhome.cc/Gossip/JavaGossip-V1/InnerClass.htm" target="_blank" rel="noopener">內部類別(Inner class)</a></li><li><a href="http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#shadowing" target="_blank" rel="noopener">Shadowing</a></li></ul>]]></content>
<summary type="html">
<p>Java&#x4E2D;&#x6709;&#x56DB;&#x7A2E;inner class&#xFF0C;&#x5206;&#x5225;&#x662F;&#xFF1A;</p>
<ol>
<li>static inner class</li>
<li>member i
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] The SerialVersionUID</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-The-SerialVersionUID/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-The-SerialVersionUID/</id>
<published>2016-12-09T09:24:00.000Z</published>
<updated>2016-12-09T11:20:04.000Z</updated>
<content type="html"><![CDATA[<p>當實作了Serializable interface時,Eclipse總是會提醒你<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">The serializable <span class="class"><span class="keyword">class</span> <span class="title">xxx</span> <span class="title">does</span> <span class="title">not</span> <span class="title">declare</span> <span class="title">a</span> <span class="title">static</span> <span class="title">final</span> <span class="title">serialVersionUID</span> <span class="title">field</span> <span class="title">of</span> <span class="title">type</span> <span class="title">long</span></span></span><br></pre></td></tr></table></figure></p><p>serialVersionUID相當於這個Object的版本控管,若不宣告serialVersionUID,JVM會協助產生。但是因為演算法對Object內容有相當高的敏感度和不同的JVM有不同的實作方式,所以有可能Object都一樣,但是在不同JVM上算出的serialVersionUID卻是不同,丟出InvalidClassException。</p><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Serializable</span></span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span>serialVersionUID= <span class="number">1L</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span> age;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> String addres;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>接收方將Person Object序列化存到硬碟上。</p><p>之後Person Object做了修改<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Serializable</span></span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span>serialVersionUID= <span class="number">2L</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> String name;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>此時,接收方嘗試Person Object反序列化,就會丟出InvalidClassException。</p><p>那些情況屬於不可相容的改變,請參考:<a href="http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html#5172" target="_blank" rel="noopener">Incompatible Changes</a></p><p>那些情況屬於可相容的改變,請參考:<br><a href="http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html#6754" target="_blank" rel="noopener">Compatible Changes</a></p><p>當Object內容改變,可以根據上述連結來判定屬於可相容的改變或是不可相容的改變。若是不可相容的改變就要修正serialVersionUID的值。</p><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/" target="_blank" rel="noopener">Understand The SerialVersionUID</a></li><li><a href="http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html" target="_blank" rel="noopener">Serializable (Java Platform SE 7)</a></li></ul>]]></content>
<summary type="html">
<p>&#x7576;&#x5BE6;&#x4F5C;&#x4E86;Serializable interface&#x6642;&#xFF0C;Eclipse&#x7E3D;&#x662F;&#x6703;&#x63D0;&#x9192;&#x4F60;<br><figure
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] Enum in Java</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Enum-in-Java/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Enum-in-Java/</id>
<published>2016-12-09T09:23:29.000Z</published>
<updated>2016-12-13T07:25:47.000Z</updated>
<content type="html"><![CDATA[<p>enum類別可以單獨宣告或是宣告在其他類別裡面。</p><h3 id="單獨宣告:"><a href="#單獨宣告:" class="headerlink" title="單獨宣告:"></a>單獨宣告:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Direction {</span><br><span class="line"> EAST,WEST,SOUTH,NORTH;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在編譯時期compiler會自動:</p><ul><li><p>加入final修飾enum和繼承Enum:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">enum</span> Direction extends Enum{</span><br><span class="line"> EAST,WEST,SOUTH,NORTH;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>加入private Constructor:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">enum</span> Direction extends Enum{</span><br><span class="line"> EAST,WEST,SOUTH,NORTH;</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Direction</span><span class="params">(String s, <span class="keyword">int</span> i)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(s, i);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>加入public static final修飾列舉內容值:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">enum</span> Direction extends Enum{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction EAST,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction WEST,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction SOUTH,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction NORTH;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Direction</span><span class="params">(String s, <span class="keyword">int</span> i)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(s, i);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>初始化:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">enum</span> Direction extends Enum{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction EAST,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction WEST,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction SOUTH,</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Direction NORTH;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Direction</span><span class="params">(String s, <span class="keyword">int</span> i)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(s, i);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">static</span>{</span><br><span class="line"> EAST = <span class="keyword">new</span> Direction(<span class="string">"EAST"</span>, <span class="number">0</span>);</span><br><span class="line"> WEST = <span class="keyword">new</span> Direction(<span class="string">"WEST"</span>, <span class="number">1</span>);</span><br><span class="line"> SOUTH = <span class="keyword">new</span> Direction(<span class="string">"SOUTH"</span>, <span class="number">2</span>);</span><br><span class="line"> NORTH = <span class="keyword">new</span> Direction(<span class="string">"NORTH"</span>, <span class="number">3</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>override Enum的valueOf method。</p></li><li>產生一個values method,回傳值為enum類別內容值的陣列。</li></ul><hr><h3 id="宣告在其他類別:"><a href="#宣告在其他類別:" class="headerlink" title="宣告在其他類別:"></a>宣告在其他類別:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DirectionOutter</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">enum</span> Direction {</span><br><span class="line"> EAST,WEST,SOUTH,NORTH;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在編譯時期compiler會自動:</p><ul><li>加入static final修飾enum和繼承Enum:<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DirectionOutter</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">enum</span> Direction extends Enum {</span><br><span class="line"> EAST,WEST,SOUTH,NORTH;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><p>其餘行為和單獨宣告一樣。</p><hr><p>當宣告一個enum類別,compiler會”自動”做那麼多事,會有以下特性:</p><ol><li>自動繼承<a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html" target="_blank" rel="noopener">Enum</a>抽象類別,因為Enum抽象類別實做了<a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html" target="_blank" rel="noopener">Comparable</a>和<a href="http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html" target="_blank" rel="noopener">Serializable</a>,所以enum物件之間是可以比較和enum物件是可以序列化。</li><li>enum類別不能繼承其他類別或被繼承。</li><li>enum物件為<a href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank" rel="noopener">Singleton</a>,所以可以使用==或equals進行比較。</li><li>enum物件為immutable物件。</li><li>建構子存取權限一定是private。</li></ol><p><em>只有compiler可以繼承Enum。</em></p><hr><h3 id="增加屬性:"><a href="#增加屬性:" class="headerlink" title="增加屬性:"></a>增加屬性:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Direction {</span><br><span class="line">WEST(<span class="number">180</span>),</span><br><span class="line">EAST(<span class="number">0</span>),</span><br><span class="line">NORTH(<span class="number">90</span>),</span><br><span class="line">SOUTH(<span class="number">270</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">Direction</span><span class="params">(<span class="keyword">final</span> <span class="keyword">int</span> angle)</span> </span>{</span><br><span class="line"><span class="keyword">this</span>.angle = angle;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span>angle;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAngle</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> angle;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>建構子的存取權限可以不加(compiler會自動加入private)或是加入privae。</p><hr><h3 id="實作抽象方法:"><a href="#實作抽象方法:" class="headerlink" title="實作抽象方法:"></a>實作抽象方法:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Direction {</span><br><span class="line">WEST(<span class="number">180</span>) {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shout</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"WEST"</span>);</span><br><span class="line">}</span><br><span class="line">},</span><br><span class="line">EAST(<span class="number">0</span>) {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shout</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"EAST"</span>);</span><br><span class="line">}</span><br><span class="line">},</span><br><span class="line">NORTH(<span class="number">90</span>) {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shout</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"NORTH"</span>);</span><br><span class="line">}</span><br><span class="line">},</span><br><span class="line">SOUTH(<span class="number">270</span>) {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shout</span><span class="params">()</span> </span>{</span><br><span class="line">System.out.println(<span class="string">"SOUTH"</span>);</span><br><span class="line">}</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">shout</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">Direction(<span class="keyword">final</span> <span class="keyword">int</span> angle) {</span><br><span class="line"><span class="keyword">this</span>.angle = angle;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span>angle;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAngle</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> angle;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><hr><h3 id="將值轉換成enum"><a href="#將值轉換成enum" class="headerlink" title="將值轉換成enum"></a>將值轉換成enum</h3><p>根據使用情境,可以使用valueOf轉換或是自行設計轉化方式。</p><ul><li><p>若想將字串WEST轉換成Direction.WEST:<br>使用valueOf</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Direction.valueOf(<span class="string">"WEST"</span>);</span><br></pre></td></tr></table></figure></li><li><p>當使用者輸入180度時,要轉換成Direction.WEST:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Direction {</span><br><span class="line">WEST(<span class="number">180</span>),EAST(<span class="number">0</span>),NORTH(<span class="number">90</span>),SOUTH(<span class="number">270</span>);</span><br><span class="line"> </span><br><span class="line">Direction(<span class="keyword">final</span> <span class="keyword">int</span> angle) {</span><br><span class="line"><span class="keyword">this</span>.angle = angle;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span>angle;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAngle</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">return</span> angle;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Map<Integer, Direction>lookup= <span class="keyword">new</span> HashMap<Integer, Direction>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> {</span><br><span class="line"><span class="keyword">for</span> (Direction s : Direction.values())</span><br><span class="line">lookup.put(s.getAngle(), s);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Direction <span class="title">get</span><span class="params">(<span class="keyword">int</span> angle)</span> </span>{</span><br><span class="line"><span class="keyword">return</span> lookup.get(angle);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><p>透過map物件進行轉換。</p><hr><h3 id="將enum物件存放到容器:"><a href="#將enum物件存放到容器:" class="headerlink" title="將enum物件存放到容器:"></a>將enum物件存放到容器:</h3><ul><li><p><a href="http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html" target="_blank" rel="noopener">EumSet</a>:</p><ol><li>用EnumSet來存放enum物件的時間和空間效能較好。</li><li>在多執行緒實行下是不安全。</li><li>enum物件在EnumSet的順序為在宣告時候的順序。</li></ol></li><li><a href="http://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html" target="_blank" rel="noopener">EnumMap</a>:<ol><li>用EnumSet來存放enum物件的時間和空間效能較好。</li><li>在多執行緒實行下是不安全。<h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3></li></ol></li><li><a href="http://howtodoinjava.com/2012/12/07/guide-for-understanding-enum-in-java/" target="_blank" rel="noopener">Guide for understanding enum in java</a></li></ul>]]></content>
<summary type="html">
<p>enum&#x985E;&#x5225;&#x53EF;&#x4EE5;&#x55AE;&#x7368;&#x5BA3;&#x544A;&#x6216;&#x662F;&#x5BA3;&#x544A;&#x5728;&#x5176;&#x4ED6;&#x985E;&#x52
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[Java] Heap space vs. Stack</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-Heap-space-vs-Stack/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-Heap-space-vs-Stack/</id>
<published>2016-12-09T09:22:47.000Z</published>
<updated>2016-12-13T07:25:43.000Z</updated>
<content type="html"><![CDATA[<p>在理解Java是否為Pass by Value(參考<a href="http://pandaforme.ghost.io/java-is-call-by-value-and-not-call-by-reference/" target="_blank" rel="noopener">這篇文章</a>)之前,建議先了解heap和stack的功用。</p><ul><li>Heap space:<ol><li>當建立物件時,會在heap space分配一個空間給物件使用。</li><li>所有在heap space上的物件,都可以被其他的thread存取。</li><li>Garbage Collection會清除heap space內沒有被使用到的物件。 </li><li>可透過-Xms參數調整heap space的開始大小。</li><li>可透過-Xmx參數設定heap space的最大值。</li><li>假如heap space滿了,Java會丟出<figure class="highlight plain"><figcaption><span>Java Heap Space```</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line">* Stack:</span><br><span class="line"> 1. 若變數是基本型態,就存放它的值。</span><br><span class="line"> 2. 若變數是物件,就存放它在heap space的位置。</span><br><span class="line"> 3. stack不能被其他thead存取。</span><br><span class="line"> 4. 可透過-Xss參數調整stack大小。</span><br><span class="line"> 5. 假如stack滿了,Java會丟出```java java.lang.StackOverFlowError</span><br></pre></td></tr></table></figure></li></ol></li></ul><h3 id="範例:"><a href="#範例:" class="headerlink" title="範例:"></a>範例:</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Memory</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{ <span class="comment">// Line 1</span></span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">1</span>; <span class="comment">// Line 2</span></span><br><span class="line"> Object obj = <span class="keyword">new</span> Object(); <span class="comment">// Line 3</span></span><br><span class="line"> Memory mem = <span class="keyword">new</span> Memory(); <span class="comment">// Line 4</span></span><br><span class="line"> mem.foo(obj); <span class="comment">// Line 5</span></span><br><span class="line"> } <span class="comment">// Line 9</span></span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">foo</span><span class="params">(Object param)</span> </span>{ <span class="comment">// Line 6</span></span><br><span class="line"> String str = param.toString(); <span class="comment">//// Line 7</span></span><br><span class="line"> System.out.println(str);</span><br><span class="line"> } <span class="comment">// Line 8</span></span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="http://www.journaldev.com/wp-content/uploads/2014/08/Java-Heap-Stack-Memory.png" alt=""></p><ol><li>當開始執行程式時候,JVM會載入相關的class到heap space。</li><li>產生main thread並且建立它的stack。</li><li>執行Line2,因為i是基本型態,所以push其值到stack。</li><li>執行Line3,因為obj是物件,所以push它在heap space的位置到stack。</li><li>執行Line4,因為mem是物件,所以push它在heap space的位置到stack。</li><li>執行Line6,push obj在heap space的位置到stack。</li><li>執行Line7,push obj.toString()在heap space的位置到stack。</li><li>執行Line8,pop str和param。</li><li>執行Line9,pop mem、obj和i,程式執行結束。</li></ol><p><em>如何透過pop屬於這個method的變數,推測實作方式或許是類似於四則運算。</em></p><p>例如:</p><ol><li>執行Line1,push “{“。</li><li>執行Line6,push “{“。</li><li>執行Line8,一直pop,直到遇到”{“停止。</li><li>執行Line9,一直pop,直到遇到”{“停止。</li></ol><h3 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h3><ul><li><a href="http://www.journaldev.com/4098/java-heap-memory-vs-stack-memory-difference" target="_blank" rel="noopener">Java Heap Memory vs Stack Memory Difference</a></li><li><a href="http://java-success.blogspot.tw/2012/04/how-will-you-go-about-explaining.html" target="_blank" rel="noopener">How will you go about explaining the following Java concepts to a beginner?</a></li></ul>]]></content>
<summary type="html">
<p>&#x5728;&#x7406;&#x89E3;Java&#x662F;&#x5426;&#x70BA;Pass by Value(&#x53C3;&#x8003;<a href="http://pandaforme.ghost.io/java-is-call-by-val
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[LeetCode] 277. Find the Celebrity</title>
<link href="https://pandaforme.github.io/2016/12/09/Celebrity-Problem/"/>
<id>https://pandaforme.github.io/2016/12/09/Celebrity-Problem/</id>
<published>2016-12-09T09:22:00.000Z</published>
<updated>2018-05-07T10:56:48.403Z</updated>
<content type="html"><![CDATA[<h1 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h1><p>Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them.</p><p>Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: “Hi, A. Do you know B?” to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense).</p><p>You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows.</p><p>Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity’s label if there is a celebrity in the party. If there is no celebrity, return -1.</p><h1 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h1><p>先對N個人作編號,從1到N。先從編號1的人開始,問他認不認識編號2的人。<br>情況有兩種: </p><ul><li>編號1認識編號2:那麼編號1一定不是名人,編號2有可能是名人。</li><li>編號1不認識編號2:編號2一定不是名人,因為名人要有N-1人認識他。</li></ul><p>根據以上結果,可以得到結論: </p><ol><li>編號1認識編號2:那麼編號1一定不是名人,編號2有可能是名人。</li><li>編號1不認識編號2:編號2一定不是名人,編號1有可能是名人。</li></ol><p>每問一人就會淘汰掉一人,接著繼續問可能是名人的人選和下一個編號的關係,直到問完N個人就可以找出名人。時間複雜度是 O(N)。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">findCelebrity</span><span class="params">(<span class="keyword">int</span> n)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> celebrity = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">if</span> (knows(celebrity, i))</span><br><span class="line"> celebrity = i;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">if</span> (i != celebrity) {</span><br><span class="line"> <span class="keyword">if</span> (knows(celebrity, i) || !knows(i, celebrity))</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> celebrity;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="References"><a href="#References" class="headerlink" title="References"></a>References</h1><ol><li><a href="http://www.careercup.com/question?id=13167666" target="_blank" rel="noopener">Celebrity Problem</a></li><li><a href="http://blog.csdn.net/beiyeqingteng/article/details/7707485" target="_blank" rel="noopener">名人問題 (Celebrity problem)</a></li></ol>]]></content>
<summary type="html">
<h1 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h1><p>Suppose you are at a party with n people (labe
</summary>
<category term="LeetCode" scheme="https://pandaforme.github.io/tags/LeetCode/"/>
</entry>
<entry>
<title>[Java] The details of Inheritance</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-The-details-of-Inheritance/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-The-details-of-Inheritance/</id>
<published>2016-12-09T09:20:42.000Z</published>
<updated>2016-12-13T07:24:49.000Z</updated>
<content type="html"><![CDATA[<p>在Java使用繼承時要注意幾個小細節,不然很容易出錯。</p><ul><li>建構子的呼叫順序 </li><li>compiler會自動產生無參數的建構子,會自動初始化field變數 </li></ul><p>例如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Parent1</span></span>{</span><br><span class="line"> <span class="keyword">int</span> i;</span><br><span class="line"> String s;</span><br><span class="line"> <span class="comment">/* compiler會自動產生無參數的建構子,</span></span><br><span class="line"><span class="comment"> * 並且初始化field變數</span></span><br><span class="line"><span class="comment"> * public Parent1() {</span></span><br><span class="line"><span class="comment"> * i = 0;</span></span><br><span class="line"><span class="comment"> * s = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Parent2</span> <span class="title">extend</span> <span class="title">Parent1</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Parent2</span><span class="params">(<span class="keyword">int</span> i)</span></span>{</span><br><span class="line"> <span class="comment">//因為沒有指定要呼叫父類別的哪一個建構子,</span></span><br><span class="line"> <span class="comment">//compiler會自動呼叫super()</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="title">extend</span> <span class="title">Parent2</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Son</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(<span class="number">1</span>);</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>new Son()的時候會呼叫Parent2的建構子(public Parent2(int i)),Parent2的建構子會呼叫Parent1的建構子(public Parent1())。</p><p><em>注意:當沒有寫建構子,compiler會自動產生一個無參數的建構子。在繼承過程中若沒有特別指定要呼叫父類別的哪一個建構子,compiler會自動呼叫super()。</em></p><p>來看一個例子:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Base</span> </span>{</span><br><span class="line"><span class="keyword">int</span>i;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Base</span><span class="params">()</span> </span>{</span><br><span class="line">add(<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> j)</span> </span>{</span><br><span class="line">i += j;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Extension</span> <span class="keyword">extends</span> <span class="title">Base</span> </span>{</span><br><span class="line"><span class="keyword">int</span>i= <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Extension</span><span class="params">()</span> </span>{</span><br><span class="line">add(<span class="number">2</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> j)</span> </span>{</span><br><span class="line">i += j * <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">exec(<span class="keyword">new</span> Extension());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">exec</span><span class="params">(Extension base)</span> </span>{</span><br><span class="line">base.add(<span class="number">8</span>);</span><br><span class="line">System.out.println(base.i);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>會印出什麼樣的結果呢?</p><p>分析: </p><ol><li>new Extension()的時候會呼叫Base的建構子(public Base()),呼叫add(2)。</li><li>因為Extension有覆寫(override)Base的add function,所以Base建構子所呼叫的add(1)是呼叫Extension中的add function。</li><li>因為多型的關係,當Base建構子呼叫add(1),裡面的i是Extension的i,並不是Base的i。</li><li>當Base建構子呼叫add(1)完畢,此時Extension的i為2。</li><li>接著呼叫Extension的建構子,此時會先初始化field變數,所以i會被重設為3。</li><li>之後是呼叫add(2),此時i為7。Extension的初始化完畢。</li><li>呼叫add(8)時,可以得出i = 7 +16 = 23,所以印出23。</li></ol><p>假如將<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">exec</span><span class="params">(Extension base)</span></span></span><br></pre></td></tr></table></figure></p><p>改成<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">exec</span><span class="params">(Base base)</span></span></span><br></pre></td></tr></table></figure></p><p>結果還是一樣嗎?<br>結果是0,因為此時的i指的是Base的i。</p>]]></content>
<summary type="html">
<p>&#x5728;Java&#x4F7F;&#x7528;&#x7E7C;&#x627F;&#x6642;&#x8981;&#x6CE8;&#x610F;&#x5E7E;&#x500B;&#x5C0F;&#x7D30;&#x7BC0;&#xFF0C;&#x4E0D;&#x71
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
<entry>
<title>[LeetCode] 56. Merge Intervals</title>
<link href="https://pandaforme.github.io/2016/12/09/LeetCode-Merge-Intervals/"/>
<id>https://pandaforme.github.io/2016/12/09/LeetCode-Merge-Intervals/</id>
<published>2016-12-09T09:17:00.000Z</published>
<updated>2018-05-07T10:21:21.322Z</updated>
<content type="html"><![CDATA[<h1 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h1><p>Given a collection of intervals, merge all overlapping intervals.</p><p>Example 1:</p><pre><code>Input: [[1,3],[2,6],[8,10],[15,18]]Output: [[1,6],[8,10],[15,18]]Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].</code></pre><p>Example 2:</p><pre><code>Input: [[1,4],[4,5]]Output: [[1,5]]Explanation: Intervals [1,4] and [4,5] are considerred overlapping.</code></pre><h1 id="Soultion"><a href="#Soultion" class="headerlink" title="Soultion"></a>Soultion</h1><p>這題的主要在考如何判斷兩個interval為重疊的演算法。</p><h2 id="怎麼判斷兩個interval為重疊:"><a href="#怎麼判斷兩個interval為重疊:" class="headerlink" title="怎麼判斷兩個interval為重疊:"></a>怎麼判斷兩個interval為重疊:</h2><p>1.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">i : |--------|</span><br><span class="line">i': |-----|</span><br></pre></td></tr></table></figure></p><p>2.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">i : |--------|</span><br><span class="line">i': |-----|</span><br></pre></td></tr></table></figure></p><p>3.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">i : |--------|</span><br><span class="line">i': |-----|</span><br></pre></td></tr></table></figure></p><p>4.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">i : |--------|</span><br><span class="line">i': |--------------|</span><br></pre></td></tr></table></figure></p><p>以上為兩個interval重疊的情況,可以歸納出以下情況:</p><ul><li><code>i.start <= i'.end</code></li><li><code>i'.start <= i.end</code></li></ul><p>知道上述規則後合併就變得很簡單,因為給定的陣列是沒有排序過的,先依照 <code>interval.start</code> 排序。</p><ol><li>初始化 merge = interval.get(0)</li><li>依序檢查 interval.get(i) 是否和 merge 重疊</li><li>若重疊,merge = 合併 interval.get(i) 和 merge</li><li>若不重疊,把 merge 寫入到結果,merge = interval.get(i)</li></ol><p>有點像貪食蛇,就一直吃直到不能吃為止。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> List<Interval> <span class="title">merge</span><span class="params">(List<Interval> intervals)</span> </span>{</span><br><span class="line"> List<Interval> result = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (intervals.size() == <span class="number">0</span> || intervals.size() == <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> intervals;</span><br><span class="line"></span><br><span class="line"> intervals.sort(Comparator.comparingInt(o -> o.start));</span><br><span class="line"></span><br><span class="line"> Interval merge = intervals.get(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < intervals.size(); i++) {</span><br><span class="line"> <span class="keyword">if</span> (isOverlap(merge, intervals.get(i))) {</span><br><span class="line"> merge = <span class="keyword">new</span> Interval(</span><br><span class="line"> Math.min(merge.start, intervals.get(i).start),</span><br><span class="line"> Math.max(merge.end, intervals.get(i).end));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> result.add(merge);</span><br><span class="line"> merge = intervals.get(i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> result.add(merge);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isOverlap</span><span class="params">(Interval interval1, Interval interval2)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> interval1.start <= interval2.end && interval2.start <= interval1.end;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h1><p>Given a collection of intervals, merge all ove
</summary>
<category term="LeetCode" scheme="https://pandaforme.github.io/categories/LeetCode/"/>
<category term="Algorithm" scheme="https://pandaforme.github.io/tags/Algorithm/"/>
<category term="LeetCode" scheme="https://pandaforme.github.io/tags/LeetCode/"/>
</entry>
<entry>
<title>[Java] lock、tryLock和lockInterruptibly的差別</title>
<link href="https://pandaforme.github.io/2016/12/09/Java-lock%E3%80%81tryLock%E5%92%8ClockInterruptibly%E7%9A%84%E5%B7%AE%E5%88%A5/"/>
<id>https://pandaforme.github.io/2016/12/09/Java-lock、tryLock和lockInterruptibly的差別/</id>
<published>2016-12-09T09:16:50.000Z</published>
<updated>2016-12-13T07:24:30.000Z</updated>
<content type="html"><![CDATA[<p>在Java中的<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html" target="_blank" rel="noopener">Lock</a>介面有lock、tryLock和lockInterruptibly三個功能很相近的method,看完javadoc後還是搞不太清楚它們之間的差異性,終於找到一篇解釋清楚的文章了。</p><ul><li>lock():若lock被thread A取得,thread B會進入block狀態,直到取得lock。</li><li>tryLock():若當下不能取得lock,thread就會放棄。</li><li>lockInterruptibly():跟lock()情況一下,但是thread B可以透過interrupt被喚醒處理InterruptedException。</li></ul><p>範例:</p><ul><li>lock():</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LockDemo</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> ReentrantLocklock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LockDemo</span><span class="params">()</span> </span>{</span><br><span class="line">lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line">LockDemo lockDemo = <span class="keyword">new</span> LockDemo();</span><br><span class="line">Runnable runnable = <span class="keyword">new</span> Runnable() {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line">lockDemo.lock.lock();</span><br><span class="line">System.out.println(String.format(<span class="string">"%s %s locked"</span>, <span class="keyword">new</span> Date(System.currentTimeMillis()), Thread.currentThread().getName()));</span><br><span class="line">}</span><br><span class="line">};</span><br><span class="line">Thread threadA = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread A"</span>);</span><br><span class="line">Thread threadB = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread B"</span>);</span><br><span class="line"></span><br><span class="line">threadA.start();</span><br><span class="line">threadB.start();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以發現ThreadB呈現block狀態,一直在等待Thread A釋放lock。</p><ul><li>tryLock():</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TryLockDemo</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> ReentrantLocklock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">TryLockDemo</span><span class="params">()</span> </span>{</span><br><span class="line">lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line">TryLockDemo lockDemo = <span class="keyword">new</span> TryLockDemo();</span><br><span class="line">Runnable runnable = <span class="keyword">new</span> Runnable() {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">if</span> (lockDemo.lock.tryLock()) {</span><br><span class="line">System.out.println(String.format(<span class="string">"%s %s locked"</span>, <span class="keyword">new</span> Date(System.currentTimeMillis()), Thread.currentThread().getName()));</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">};</span><br><span class="line">Thread threadA = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread A"</span>);</span><br><span class="line">Thread threadB = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread B"</span>);</span><br><span class="line"></span><br><span class="line">threadA.start();</span><br><span class="line">threadB.start();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>若一開始lock被Thread A取得,Thread B透過tryLock()當下若沒有取得到lock,就會放棄。</p><ul><li>lockInterruptibly():</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LockInterruptiblyDemo</span> </span>{</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> ReentrantLocklock;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LockInterruptiblyDemo</span><span class="params">()</span> </span>{</span><br><span class="line">lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line">LockInterruptiblyDemo lockDemo = <span class="keyword">new</span> LockInterruptiblyDemo();</span><br><span class="line"></span><br><span class="line">Runnable runnable = <span class="keyword">new</span> Runnable() {</span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">lockDemo.lock.lockInterruptibly();</span><br><span class="line">System.out.println(String.format(<span class="string">"%s %s locked"</span>, <span class="keyword">new</span> Date(System.currentTimeMillis()), Thread.currentThread().getName()));</span><br><span class="line">}</span><br><span class="line"><span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line">System.out.println(String.format(<span class="string">"%s %s interrupted"</span>, <span class="keyword">new</span> Date(System.currentTimeMillis()), Thread.currentThread().getName()));</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">};</span><br><span class="line">Thread threadA = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread A"</span>);</span><br><span class="line">Thread threadB = <span class="keyword">new</span> Thread(runnable, <span class="string">"Thread B"</span>);</span><br><span class="line"></span><br><span class="line">threadA.start();</span><br><span class="line">Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">threadB.start();</span><br><span class="line">threadB.interrupt();</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Thread A先取得lock,Thread B無法取得lock進入block狀態,可以透過發出interrupt方式喚醒Thread B。</p><p>Lock和synchronized幾乎是大同小異,但是Lock可以做更細微的同步方式。</p><h4 id="參考資料:"><a href="#參考資料:" class="headerlink" title="參考資料:"></a>參考資料:</h4><p><a href="http://www.dewen.io/q/9077" target="_blank" rel="noopener">用通俗的語言說說lock和lockInterruptibly的區別</a></p>]]></content>
<summary type="html">
<p>&#x5728;Java&#x4E2D;&#x7684;<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html" target="_blank" rel="
</summary>
<category term="Java" scheme="https://pandaforme.github.io/categories/Java/"/>
<category term="Java" scheme="https://pandaforme.github.io/tags/Java/"/>
</entry>
</feed>