-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeed.xml
More file actions
1279 lines (1034 loc) · 63.7 KB
/
feed.xml
File metadata and controls
1279 lines (1034 loc) · 63.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>与机器,人,神共舞</title>
<description>编程,读书,思考,旅行,与机器对话,与人交谈,对神发问,探索,体验人生美丽的风景</description>
<link>https://longlinht.github.io/</link>
<atom:link href="https://longlinht.github.io//feed.xml" rel="self" type="application/rss+xml" />
<item>
<title>The greatest philosophiers from Socrates to Peter Singer</title>
<description><p>I felt overwhelmed reading books about philosophy history every time until I read A Little History of Philosophy, written by Nigel Warburton. Its conciseness and to-the-pointness deeply attracted me, and I finished it fast. Although it only has 40 chapters, it is still not easy to remember and understand all philosophiers’ideas, works, and experiences. So I decided to make a list. Every item on the list includes the philosopher’s name, birth and death years, and his or her most famous idea.</p>
<ul>
<li>
<p>Socrates</p>
<ul>
<li>470–399 BC</li>
<li>I know that I know nothing</li>
<li>The unexamined life is not worth living”</li>
<li>Gadfly</li>
</ul>
</li>
<li>Plato
<ul>
<li>428/427 or 424/423 BC</li>
<li>In The Republic,Philosophers would be at the top and would get a special education; Beneath them would be soldiers who were trained to defend the country, and beneath them would be the workers.</li>
</ul>
</li>
<li>Aristotle
<ul>
<li>384–322 BC</li>
<li>Eudaemonia isn’t about fleeting moments of bliss or how you feel.</li>
</ul>
</li>
<li>Pyrrho
<ul>
<li>365–360 BC</li>
<li>We know nothing</li>
</ul>
</li>
<li>Epicurus
<ul>
<li>341–270 BC</li>
<li>The fear of death was a waste of time and based on bad logic.</li>
</ul>
</li>
<li>Cicero
<ul>
<li>106-43 BC</li>
<li>Learning Not to Care</li>
</ul>
</li>
<li>Augustine
<ul>
<li>354-430 AD</li>
<li>God has given us free will.</li>
</ul>
</li>
<li>Boethius
<ul>
<li>480–524 AD</li>
<li>He should not forget that God judges human beings on how they behave, the choices they make, even though he knows in advance what they will do.</li>
</ul>
</li>
<li>Aquinas
<ul>
<li>1225-1274</li>
<li>This first cause, he declared, must have been God. God is the uncaused cause of everything that is.</li>
</ul>
</li>
<li>Machiavelli
<ul>
<li>1469-1527</li>
<li>Machiavelli stresses that it’s better as a leader to be feared than to be loved.If you can achieve what you are aiming for by showing kindness, keeping your promises, and being loved, then you should do this (or at least appear to do it). But if you can’t, then you need to combine these human qualities with animal ones.</li>
</ul>
</li>
<li>Thomas Hobbes
<ul>
<li>1588-1679</li>
<li>Life outside society would be ‘solitary, poor, nasty, brutish, and short’.</li>
</ul>
</li>
<li>René Descartes
<ul>
<li>1596-1650</li>
<li>I think, therefore I am</li>
</ul>
</li>
<li>Blaise Pascal
<ul>
<li>1623-1662</li>
<li>Place Your Bets</li>
</ul>
</li>
<li>Baruch Spinoza
<ul>
<li>1632-1677</li>
<li>God is nature and nature is God</li>
</ul>
</li>
<li>John Locke
<ul>
<li>1632-1704</li>
<li>Whenever laws end, tyranny begins.</li>
</ul>
</li>
<li>George Berkeley
<ul>
<li>1685-1753</li>
<li>Truth is the cry of all, but the game of few.</li>
</ul>
</li>
<li>Voltaire
<ul>
<li>1694–1778</li>
<li>I hate what you say, but will defend to the death your right to say it</li>
</ul>
</li>
<li>
<p>Leibniz</p>
<ul>
<li>1646–1716</li>
<li>The present is big with the future.</li>
</ul>
</li>
<li>
<p>David Hume</p>
<ul>
<li>1711–76</li>
<li>Reason is, and ought only to be the slave of the passions.</li>
</ul>
</li>
<li>
<p>Jacques Rousseau</p>
<ul>
<li>1712-1778</li>
<li>Man was born free, and everywhere he is in chains</li>
</ul>
</li>
<li>
<p>Immanuel Kant</p>
<ul>
<li>1724-1804</li>
<li>Always recognize that human individuals are ends, and do not use them as mere means to your end.</li>
</ul>
</li>
<li>
<p>Jeremy Bentham</p>
<ul>
<li>1748-1832</li>
<li>It is the greatest good to the greatest number of people which is the measure of right and wrong.</li>
</ul>
</li>
<li>
<p>Hegel</p>
<ul>
<li>1770-1831</li>
<li>The owl of Minerva spreads its wings only with the falling of the dusk.</li>
</ul>
</li>
<li>
<p>Schopenhauer</p>
<ul>
<li>1788-1860</li>
<li>Reality has two aspects. It exists both as Will and as Representation.</li>
</ul>
</li>
<li>
<p>Charles Darwin</p>
<ul>
<li>1809-1882</li>
<li>It is not the strongest of the species that survives, nor the most intelligent that survives. It is the one that is the most adaptable to change.</li>
</ul>
</li>
<li>
<p>Søren Kierkegaard</p>
<ul>
<li>1813-1855</li>
<li>Life can only be understood backward, but it must be lived forward.</li>
</ul>
</li>
<li>
<p>Karl Marx</p>
<ul>
<li>1818-1883</li>
<li>Workers of the world, unite! You have nothing to lose but your chains.</li>
</ul>
</li>
<li>
<p>William James</p>
<ul>
<li>1842-1910</li>
<li>The deepest principle in human nature is the craving to be appreciated.</li>
</ul>
</li>
<li>
<p>Nietzsche</p>
<ul>
<li>1844-1900</li>
<li>God is dead, and we have killed him.</li>
</ul>
</li>
<li>
<p>Sigmund Freud</p>
<ul>
<li>1856-1939</li>
<li>The interpretation of dreams is the royal road to a knowledge of the unconscious activities of the mind.</li>
</ul>
</li>
<li>
<p>Bertrand Russell</p>
<ul>
<li>1872-1970</li>
<li>The whole problem with the world is that fools and fanatics are always so certain of themselves, and wiser people so full of doubts.</li>
</ul>
</li>
<li>
<p>Alfred Jules Ayer</p>
<ul>
<li>1910-1989</li>
<li>The principle of verification is a criterion of meaningfulness. We say that a sentence is factually significant to any given person, if, and only if, he knows how to verify the proposition which it purports to express.</li>
</ul>
</li>
<li>
<p>Jean-Paul Sartre</p>
<ul>
<li>1905-1980</li>
<li>Existence precedes essence.</li>
</ul>
</li>
<li>
<p>Wittgenstein</p>
<ul>
<li>1889-1951</li>
<li>The limits of my language mean the limits of my world.”</li>
</ul>
</li>
<li>
<p>Hannah Arendt</p>
<ul>
<li>1906-1975</li>
<li>The sad truth is that most evil is done by people who never make up their minds to be good or evil.</li>
</ul>
</li>
<li>
<p>Philippa Foot</p>
<ul>
<li>1920-2010</li>
<li>The duty of not being unjust can override the duty of truth-telling.</li>
</ul>
</li>
<li>
<p>John Rawls</p>
<ul>
<li>1921-2002</li>
<li>The most reasonable principles of justice are those everyone would accept and agree to from a fair position.</li>
</ul>
</li>
<li>
<p>Alan Turing</p>
<ul>
<li>1912-1954</li>
<li>A machine can be called intelligent when it can deceive a human into believing that it is human.</li>
</ul>
</li>
<li>
<p>Peter Singer</p>
<ul>
<li>1946</li>
<li>To protest about bullfighting in Spain, the eating of dogs in South Korea, or the slaughter of baby seals in Canada, while continuing to eat eggs from hens who have spent their lives crammed into cages, or veal from calves who have been deprived of their mothers, their proper diet, and the freedom to lie down with their legs extended, is like denouncing apartheid in South Africa while asking your neighbors not to sell their houses to blacks.</li>
</ul>
</li>
</ul>
</description>
<pubDate>Sun, 23 Jul 2023 22:20:12 +0400</pubDate>
<link>https://longlinht.github.io//the-40-greatest-philosophiers</link>
<guid isPermaLink="true">https://longlinht.github.io//the-40-greatest-philosophiers</guid>
</item>
<item>
<title>Userful EOR operations in algorithm design</title>
<description><p>The EOR is a short form of Exclusive OR, which is a logic operator and satisfies the commutative law and the associative law. It means:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 ^ N == N
N ^ N == 0
A ^ B == B ^ A
A ^ B ^ C == A ^ (B ^ C)
</code></pre></div></div>
<p>With these properties, EOR can be useful to efficiently solve some questions. Let us start with a simple one:</p>
<blockquote>
<p>Given an integer array with only one integer appearing odd times and others appearing even times, print the odd-times one.</p>
</blockquote>
<p>At first glance, you could have several solutions to this question. But trust me, you might not have an elegant solution like the one below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static void printOddTimesNumber1(int[] array) {
int eor = 0;
for(int i=0; i &lt; array.length; i++) {
eor ^= array[i];
}
System.out.println(eor);
}
</code></pre></div></div>
<p>With just few lines of code, it’s done. It utilizes the basic properties of EOR pretty well. EOR operation on even-time numbers always 0 while only one odd-times number <code class="language-plaintext highlighter-rouge">^</code> 0 always itself.</p>
<p>One more difficult question:</p>
<blockquote>
<p>Given an integer array with only two integers appearing odd times and others appearing event times, print the two odd-time numbers.</p>
</blockquote>
<p>We give the solution directly and explain the code later.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static void printOddTimesNumber2(int[] array) {
int eor = 0;
for(int i=0; i &lt; array.length; i++) {
eor ^= array[i];
}
int rightOne = eor &amp; (~eor + 1);
onlyOne = 0;
for(int i=0; i &lt; array.length; i++) {
if(array[i] &amp; rightOne != 0) {
onlyOne ^= array[i];
}
}
int zeroOne = eor ^ onlyOne;
System.out.println(onlyOne, eor ^ onlyOne);
}
</code></pre></div></div>
<p>The code seems complex, especially this segment <code class="language-plaintext highlighter-rouge">eor &amp; (~eor + 1)</code>. The expression gets an integer whose only bit is the same as the most right 1 bit of eor and the rest is 0.</p>
<p>Assume that these two numbers are A and B. The first part of the code was figured out: eor = A ^ B. We know A != B. So there must be a bit of A and B that is different. If the bit of A is 1 and the bit of B is 0, We need to figure out this bit. Then the complex expression above helped. Having the <code class="language-plaintext highlighter-rouge">rightOne</code>, we can iterate the array to find which number’s this bit is 1. After iteration, we get it as <code class="language-plaintext highlighter-rouge">onlyOne</code> which is A. Finally, we also get the <code class="language-plaintext highlighter-rouge">zeroOne</code> which is B.</p>
</description>
<pubDate>Sat, 22 Jul 2023 22:20:12 +0400</pubDate>
<link>https://longlinht.github.io//useful-eor-operation</link>
<guid isPermaLink="true">https://longlinht.github.io//useful-eor-operation</guid>
</item>
<item>
<title>A practical way to make sure the correctness of your algorithm</title>
<description><p>As programmers, it really frustrates us when we cannot 100 percent make sure the functions or algorithms we have written can produce the results we expected. Although we have passed many test cases, we are still not confident enough to say these functions can work and output correct values in all cases. It is impossible for us to have a test case system like Leecode wherever and whenever. It is not realistic. So we need to figure out a way to test our algorithm ourselves. Fortunately, there is indeed one.</p>
<p>As a fact, this method is based on comparing an existing solution to verify a new one. It sounds simple, right? What are we waiting for? Let us implement it step by step.</p>
<ul>
<li>Identify a function or algorithm you would like to test. For this example, it is a selection sort function we wrote.</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static void selectionSort(int[] arr) {
if (arr == null || arr.length &lt; 2) {
return;
}
for (int i = 0; i &lt; arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j &lt; arr.length; j++) {
minIndex = arr[j] &lt; arr[minIndex] ? j : minIndex;
}
swap(arr, i, minIndex);
}
}
</code></pre></div></div>
<ul>
<li>In order to compare, we need to implement a simple function, which also can sort the array using an existed and verified solutiion. In this case we using a Java API.</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static void comparator(int[] arr) {
Arrays.sort(arr);
}
</code></pre></div></div>
<ul>
<li>Implement a random sample generator.</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) (Math.random() * maxSize) + 1];
arr[0] = (int) (Math.random() * maxValue) - (int) (Math.random() * maxValue);
for (int i = 1; i &lt; arr.length; i++) {
do {
arr[i] = (int) (Math.random() * maxValue) - (int) (Math.random() * maxValue);
} while (arr[i] == arr[i - 1]);
}
return arr;
}
</code></pre></div></div>
<ul>
<li>Write a function to compare output.</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null &amp;&amp; arr2 != null) || (arr1 != null &amp;&amp; arr2 == null)) {
return false;
}
if (arr1 == null &amp;&amp; arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i &lt; arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
</code></pre></div></div>
<ul>
<li>Using various size of sample to test the function we wrote and compare to the existed solution.</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i &lt; testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
selectionSort(arr1);
comparator(arr2);
if (!isEqual(arr1, arr2)) {
succeed = false;
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
int[] arr = generateRandomArray(maxSize, maxValue);
printArray(arr);
selectionSort(arr);
printArray(arr);
}
</code></pre></div></div>
<p>We can randomly set the test time and sample size to do loads of tests to make sure the function works and outputs correctly. If it can produce expected results after millions of tests. We can be sure of the correctness of this function. But if there is one time they are not equal, in other words, <code class="language-plaintext highlighter-rouge">selectionSort</code> produces outputs that are not equal, <code class="language-plaintext highlighter-rouge">comparator</code>. We have to say the new solution cannot be accepted; we should debug and test more to find the problem. As long as we use this sharp comparator more and more, we will have more confidence to write down more reliable algorithms.</p>
</description>
<pubDate>Thu, 20 Jul 2023 22:20:12 +0400</pubDate>
<link>https://longlinht.github.io//a-practical-way-for-algorithm-correctness</link>
<guid isPermaLink="true">https://longlinht.github.io//a-practical-way-for-algorithm-correctness</guid>
</item>
<item>
<title>A quick tour of Spring Boot</title>
<description><p>As an Android developer currently, I have always dreamed of becoming a full-stack developer, so I started to learn Java backend programming. During the past two weeks, I have read one book and watched a series of tutorial videos on Spring Boot. So I am going to summarize what I have learned and write down my thoughts.</p>
<p>I have to admit that I had never heard of Spring Boot before I started learning it. After I effortlessly started up a simple project and ran it successfully following the steps the book describes, I have to say it is pretty easy to create and run an application. It just takes one or two minutes to start a runnable program without any extra effort. It just works.</p>
<p>So the first question is what such a powerful Spring Boot is. Actually, it is not a mysterious thing. You can treat it as an enhanced Spring, which simplifies the complicated configurations and makes dependency management unprecedentedly easy. Let us compare the differences between Spring and Spring Boot in configurations to experience the attractions of Spring Boot for developers.</p>
<p>for Spring applications:</p>
<ul>
<li>We have to manually add dependency in pom.xml</li>
<li>We have to manually program the Web3.0 configuration class.</li>
<li>We have to manually write the Spring/Spring MVC configuration class.</li>
</ul>
<p>while for Spring Boot applications:</p>
<p>We only need to check a dependency to add it or manually add it, not manually write a configuration class anymore. Writing business controllers and designing data models become the only things we need to do. It significantly speeds up the process of development. No configurations, no worry about dependencies, especially dependency versions—it sounds amazing. We cannot stop asking, How did Spring Boot make it? The answer is that these configurations and dependencies are embedded into Spring Boot. The starter is the key point. Spring Boot has embedded most dependencies we need and organized every dependency with the most matched versions. For example, if we need Spring Web, we just add lines like below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
&lt;dependencies&gt;
...
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;
...
&lt;dependencies&gt;
</code></pre></div></div>
<p>You may have noticed that the dependency didn’t specify the version and that the name of artifactId contains <code class="language-plaintext highlighter-rouge">starter</code>. The version is not necessary any more; Spring Boot helps us figure out all embedded dependencies with the proper version based on the Spring Boot version. This saves us much time and effort in finding the matched versions of dependencies. As an Android developer, I have to say that Android developers also need a framework like this, which can do the most dirty work for us.</p>
<p>Spring Boot also helps us avoid writing boilerplate code like the Spring MVC configuration class. I think it makes the most use of the annotation and the reflection of Java to implement. It is not uncommon to find that almost all production-grade frameworks written in Java use these Java features to fulfill complicated tasks.</p>
<p>Another obvious difference between Spring and Spring Boot in the work flow is that Spring Boot has embedded a Tomcat, so I do not need to configure one manually any more. When you are in the process of development, you even forget its existence. You just run and wait for the result.</p>
<p>Although Spring Boot has helped us get rid of annoying XML configurations, it still has configurations. Several styles of configuration files are supported. But the style of yaml is preferred.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>spring:
thymeleaf:
cache: false
</code></pre></div></div>
<p>Yaml differs from traditional property files, which consist of key=value lines. The reason for choosing yaml instead of property files is that property files cannot represent structured configuration well.</p>
<p>Before going to the most exciting part of Spring Boot, let us go on a whirlwind REST tour.
If we would like to locate a resource through a URI (path) and do different operations on it, we usually define different paths to complete different tasks.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://localhost/user/saveUser
http://localhost/user/delete?id=1
http://localhost/user/updateUser
http://localhost/user/getById?id=1
http://localhost/user/getAll
</code></pre></div></div>
<p>While adopting REST style, we can do this more elegantly:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://localhost/user/users
http://localhost/user/users/1
http://localhost/user/users
http://localhost/user/users/1
http://localhost/user/users
</code></pre></div></div>
<p>On first sight, it is hard to tell the difference among these paths. In fact, Spring Boot has provided us with several annotations to specify every action each path stands for. The first path with the GET action will make a request for all users, while the third path with the POST action will save a user. Concise and elegant, right? Next, we will step into the key part of Spring Boot that can show its power.</p>
<p>Spring Boot has been evolving quickly since it appeared. Until now, it has been seamlessly integrated with most mainstream third-party technologies like JUnit(for testing), MyBatis(for persistence), Druid(for data source), Simple(for cache). Actually, it supports most of them directly. Introducing them to your project becomes quick and effortless. I have tried to integrate several of them into my trivial project and found a general routine to complete the integration task. When you want to introduce a technology (library) for a specific purpose to your project, generally speaking, you should do these three steps:</p>
<ol>
<li>Import the starter of this library.</li>
<li>Turn on this library, which means letting Spring Boot know you want to use this library or technology.</li>
<li>Using it in your business code.</li>
</ol>
<p>For example, if we want to introduce Simple for cache, we will follow these 3 steps:</p>
<p>1.Import</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre></div></div>
<p>2.Turn on</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
@SpringBootApplication
@EnableCaching
public class TacoCloudApplication implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(TacoCloudApplication.class, args);
}
}
</code></pre></div></div>
<p>3.Using</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@Cachable(value="cacheSpace",key="#id")
public User getById(Integer id) {
return userDao.selectById(id);
}
</code></pre></div></div>
<p>After these 3 steps, we can already use all the cache capabilities that Simple has provided for us. Other 3rd-party libraries are directly supported by Spring Boot nearly all can be introduced like above. The quick tour of Spring Boot has to end now. This article is just a summary and whirlwind tour; next I will dive deep into a specific technology often used in Spring Boot.</p>
</description>
<pubDate>Wed, 12 Jul 2023 22:20:12 +0400</pubDate>
<link>https://longlinht.github.io//a-quick-tour-of-spring-boot</link>
<guid isPermaLink="true">https://longlinht.github.io//a-quick-tour-of-spring-boot</guid>
</item>
<item>
<title>生活在Vim中</title>
<description><p>从第一天接触Vim编辑器到现在已经过去10年了,从最开始的不知所措到现在的运用自如,Vim已经融入到了我工作生活的很多场景, 它对于我已经不仅仅是一个高效强大的编辑器,更是变成了一种做事的方式和编辑,操作的哲学。关于这种哲学我最喜欢一个类比: 使用Vim的过程就像是一个画家画画的过程,当一个画家需要挥毫泼墨时,他就进入了insert模式,可以对画布进行任意的修改,当一个画家需要思考和审视时,他需要防止笔误和操作失当,这个时候他就需要进入normal模式,这个时候不能修改画布,只能在画布上移动,无论是移动你的手指和思绪,这个时候都不能对画布进行修改。这种特有的多模式也许是Vim和Emacs与其他大部分编辑器最显著的不同。</p>
<p>当你初窥Vim的与众不同后,如果你还不熟悉它的使用,你可能会不知所措,甚至无法编辑,无法退出,你和它会僵死在那里。你遇到的这种困境也正是Vim特有的操作方式引起的。这篇文章不打算如流水账般罗列Vim的诸多命令,我只挑选几种在日常代码编辑中最常用的命令来呈现Vim的神奇与强大。Vim之强大主要体现在无论是移动查询还是修改替换都能将一个动作做到非常小的粒度和精确控制,并且可以以极少的击键次数优雅地实现你精细的操作。我来举一个最常见的例子:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>int i = 3 * (4 + 2);
</code></pre></div></div>
<p>如上,假如我们想将括号中的内容改掉,一般的编辑器的做法都是移动到数字4,然后完全选中括号中的内容后修改。但是如果使用Vim,动作将会非常简单和快捷,只需移动到左括号后键入<code class="language-plaintext highlighter-rouge">ci(</code>即可,然后就可以直接进入insert模式修改了。敏感的读者可能已经感知到Vim的这条命令其实就是change in (),有非常强的自然语言命令的感觉。</p>
<p>因为vim的使用其实可以写成一本书,网络上的教程更是数不胜数,这篇文章也不打算写成一篇使用教程。vim本身的使用需要长期的实践,而vim的使用场景的扩展可能就需要不断的探索和尝试了。我因为长期使用vim,对其浸润很深,所以发现了不少vim的其他使用方式和场景。第一个场景就是vim的命令和操作方式以插件的形式存在于其他的编辑器,IDE和软件应用中。 以下是三个典型的插件:</p>
<ul>
<li>
<p>VsVim(这个是大名鼎鼎的Visual Studio的一款Vim插件)</p>
</li>
<li>
<p>VSCodeVim(for Visual Studio Code)</p>
</li>
<li>
<p>IdeaVim(for Android Studio)</p>
</li>
</ul>
<p>这三个插件都是应用于IDE或编辑器, 下面的这个插件甚至应用于Google浏览器:</p>
<ul>
<li>Vimium</li>
</ul>
<p>其实按照这个思路,凡是有编辑需求的应用都可以嵌入Vim插件,这样的话即使某一天Vim这个编辑器不存在了, Vim的这种思想却可以一直存在下去,这也许就是Vim的魅力吧! 至此,谈到Vim的永生,就不得不谈一个我最近几年一直在用的Emacs变体–Spacemacs。Spacemacs本质上还是Emacs,一个厉害的程序员通过配置文件将其扩展成了一个可以同时支持Vim和Emacs操作的巨无霸,足见Emacs的强大的可扩展性。当你第一次使用Spacemacs时会让你选择Vim世界还是Emacs世界,两大上古神奇竟以此种方式存在了下来…</p>
<p>使用Vim的历程,从排斥到爱不释手到离不开,Vim已成为工作生活的一部分,可谓一日Vim,终生Vim.</p>
</description>
<pubDate>Fri, 10 Dec 2021 22:30:12 +0400</pubDate>
<link>https://longlinht.github.io//live-in-the-vim</link>
<guid isPermaLink="true">https://longlinht.github.io//live-in-the-vim</guid>
</item>
<item>
<title>BaseQuickAdapter使用tips</title>
<description><p>此文记录在实际工作中使用BaseQuickAdapter的一些经验和心得,以期新同学在第一次使用时免去踩坑的风险。</p>
<p>Tips:</p>
<ul>
<li>如果adapter只有一种类型的item,则直接继承自BaseQuickAdapter,提供布局文件即可,例如:</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
class SelectedContactAdapter : BaseQuickAdapter&lt;ContactUIItemData, BaseViewHolder&gt;(layoutResId = R.layout.s_item_select_user_normal){
override fun convert(holder: BaseViewHolder, item: ContactUIItemData) {
holder.getView&lt;UserFaceView&gt;(R.id.ufv_avatar).bindUid(item.bean.account)
addChildClickViewIds(R.id.ll_item)
}
}
</code></pre></div></div>
<ul>
<li>如果adapter需要多种类型的item,则需要继承自BaseMultiItemQuickAdapter,例如:</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
class ContactAdapter : BaseMultiItemQuickAdapter&lt;ContactUIItemData, BaseViewHolder&gt;() {
var actionType = AppConstants.User.TYPE_CONTACT_NEW_MESSAGE
init {
addItemType(ITEM_TYPE_HEAD, R.layout.s_item_contact_head)
addItemType(ITEM_TYPE_TITLE, R.layout.s_item_contact_title)
addItemType(ITEM_TYPE_CONTACT, R.layout.s_item_single_contact)
setDiffCallback(object : DiffUtil.ItemCallback&lt;ContactUIItemData&gt;() {
override fun areItemsTheSame(
oldItem: ContactUIItemData,
newItem: ContactUIItemData
): Boolean {
return oldItem.viewType == newItem.viewType
}
override fun areContentsTheSame(
oldItem: ContactUIItemData,
newItem: ContactUIItemData
): Boolean {
if (newItem.viewType == ITEM_TYPE_CONTACT) {
return TextUtils.equals(newItem.bean.account, oldItem.bean.account) &amp;&amp; TextUtils.equals(newItem.bean.name, oldItem.bean.name)
&amp;&amp; TextUtils.equals(newItem.searchText, oldItem.searchText)
}
return true;
}
})
}
....
}
</code></pre></div></div>
<p>这里需要注意的是数据item必须实现MultiItemEntity接口:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
public class ContactUIItemData implements MultiItemEntity {
...
@Override
public int getItemType() {
return viewType;
}
}
</code></pre></div></div>
<p>并且需要实现DiffCallback,DiffCallback有两个方法需要实现,第一个用来判断两个item是否同一类型,如果判断是,则调用第二个方法判断两个item内容是否相等,这两个方法需要根据实际业务场景谨慎实现。</p>
<ul>
<li>
<p>刷新数据统一调用setDiffNewData,无论是第一次加载数据还是后续数据变更刷新,这里要注意的是,刷新时调用setDiffNewData需要传入新的数据列表才能实现刷新。</p>
</li>
<li>
<p>如只需刷新某个item,则可以通过notifyItemChanged来实现,当然添加和删除数据都有对应的方法,但是添加和删除还是统一走setDiffNewData比较好。</p>
</li>
<li>
<p>如只需刷新某个item中的某个元素,而不是刷新整个item,则可以通过payload的方式来实现局部刷新,例如:</p>
</li>
</ul>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
override fun convert(holder: BaseViewHolder, item: GroupUIItemData, payloads: List&lt;Any&gt;) {
super.convert(holder, item, payloads)
when(holder.itemViewType) {
GroupContactItemConstants.ITEM_TYPE_CONTACT -&gt; {
if (payloads.isEmpty()) {
return
}
val payload = payloads[0];
if (payload == EDIT_MODE_PAYLOAD) {
val cbSelect = holder.getView&lt;CheckBox&gt;(R.id.cb_select)
cbSelect.isChecked = item.checked
cbSelect.isEnabled = item.enabled
if (item.canSelect) {
cbSelect.visibility = View.VISIBLE
} else {
cbSelect.visibility = View.GONE
}
}
}
}
}
</code></pre></div></div>
<p>对需要局部刷新的item调用contactsAdapter.notifyItemChanged(position, GroupContactAdapter.EDIT_MODE_PAYLOAD).</p>
<ul>
<li>
<p>如遇到列表不刷新的问题,则需要检查调用setDiffNewData时传入的是否时新的列表,数据源对象是不是新对象,从多个方面来排查,理论上更新列表就统一使用这个方法,避免调用notifyDataSetChanged.</p>
</li>
<li>
<p>要注意DiffCallback的实现,如果遇到问题,可调试此接口两个方法实现的返回值。</p>
</li>
<li>
<p>Item的点击事件响应都是通过setOnItemClickListener和setOnItemChildClickListener分别实现,前者是注册整个item,后者是注册item上的子view,子view的响应需要调用addChildClickViewIds来分别注册。</p>
</li>
<li>
<p>Item的长按与点击相同,分别对应setOnItemLongClickListener和setOnItemChildLongClickListener两个方法。</p>
</li>
</ul>
</description>
<pubDate>Wed, 10 Nov 2021 18:00:00 +0400</pubDate>
<link>https://longlinht.github.io//base-quick-adapter-tips</link>
<guid isPermaLink="true">https://longlinht.github.io//base-quick-adapter-tips</guid>
</item>
<item>
<title>Kotlin使用小计</title>
<description><p>此文记录一次对Kotlin的技术分享,显然无法对Kotlin的方方面面都涉及到,只将一些在实际工作中频繁涉及到的要点做一个梳理,以期对Kotlin这们JVM语言有一个整体的认识。</p>
<h4 id="为什么使用kotlin">为什么使用Kotlin</h4>
<ul>
<li>静态类型语言</li>
<li>同时支持面向对象和函数式编程范式</li>
<li>更强大语言表达能力</li>
<li>解决Java NPE问题,更安全</li>
<li>支持扩展函数</li>
<li>与Java的高互操作性</li>
</ul>
<h3 id="类和函数">类和函数</h3>
<ul>
<li>我们只能继承声明为open 或 obstract的类</li>
<li>Unit 类似Java中的void</li>
<li>每一个函数都返回一个值</li>
<li>函数参数支持默认值,类似C++</li>
</ul>
<h3 id="变量和属性">变量和属性</h3>
<ul>
<li>一切都是对象,包括基础类型,比Java更加彻底</li>
<li>对于var和val的使用,最佳实践是: 尽可能多的使用val</li>
<li>Property类似java中的field,但更强大:</li>
</ul>
<p>In Java:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Person person = new Person();
person.setName("name");
String name = person.getName();
</code></pre></div></div>
<p>In Kotlin:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Person {
var name: String = ""
}
val person = Person()
person.name = "name"
val name = person.name
</code></pre></div></div>
<p>定制getter,setter行为:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Person {
var name: String = ""
get() = field.toUpperCase()
set(value) {
field = "Name: $value"
}
}
</code></pre></div></div>
<h4 id="data-classes">Data Classes</h4>
<p>强大的一种类,可以帮助我们避免一些模板代码和避免出错</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data class Movie(var name: String, var studio: String, var rating: Float)
</code></pre></div></div>
<p>等价于Java Pojo:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
public class Movie {
private String name;
private String studio;
private float rating;
public Movie(String name, String studio, float rating) {
this.name = name;
this.studio = studio;
this.rating = rating;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStudio() {
return studio;
}
public void setStudio(String studio) {
this.studio = studio;
}
public float getRating() {
return rating;
}
public void setRating(float rating) {
this.rating = rating;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + Float.floatToIntBits(rating);
result = prime * result + ((studio == null) ? 0 : studio.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Movie other = (Movie) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Float.floatToIntBits(rating) != Float.floatToIntBits(other.rating))
return false;
if (studio == null) {
if (other.studio != null)
return false;
} else if (!studio.equals(other.studio))
return false;
return true;
}
@Override
public String toString() {
return "Movie [name=" + name + ", studio=" + studio + ", rating=" + rating + "]";
}
}
</code></pre></div></div>
<p>Copy数据类对象:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val f1 = Forecast(Date(), 27.5f, "Shiny day")
val f2 = f1.copy(temperature = 30f)
</code></pre></div></div>
<p>把一个对象的多个字段映射到多个变量中</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val f1 = Forecast(Date(), 27.5f, "Shiny day")
val (date, temperature, details) = f1
</code></pre></div></div>
<h4 id="操作符重载">操作符重载</h4>
<ul>
<li>类似C++</li>
<li>===和!==不能被重载</li>
</ul>
<h4 id="lambdas">Lambdas</h4>
<ul>
<li>Java也支持,但是Kotlin中lambdas表达式可以变得非常简单,语法糖,便利的同时也要特别小心</li>
<li>在Kotlin中,函数可以作为一个类型</li>
<li>类似C++中的函数指针</li>
</ul>
<h4 id="visibility-modifiers">Visibility Modifiers</h4>
<ul>
<li>默认的可见性是public</li>
<li>private, protected, internal可见官方文档定义</li>
</ul>
<h4 id="集合和函数操作">集合和函数操作</h4>
<p>大概有如下几类操作,具体见官方文档</p>
<ul>
<li>Aggregate operations:</li>
</ul>