<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>S先生の筆記📒</title><description>A minimal hugo theme focus on content</description><link>https://danielsunyu.github.io/myblog-site/</link><language>en</language><copyright>Copyright 2026, Calvin Tran</copyright><lastBuildDate>Mon, 30 Mar 2026 15:30:04 -0600</lastBuildDate><generator>Hugo - gohugo.io</generator><docs>http://cyber.harvard.edu/rss/rss.html</docs><atom:link href="https://danielsunyu.github.io/myblog-site//atom.xml" rel="self" type="application/atom+xml"/><item><title>Run xv6-x86-64 on macOS M</title><link>https://danielsunyu.github.io/myblog-site/posts/run-xv6-x86-64-on-mac-m/</link><description>&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Xv6">https://en.wikipedia.org/wiki/Xv6&lt;/a>&lt;/p>
&lt;p>I used to believe it&amp;rsquo;s not possible to run &lt;code>xv6-x86-64&lt;/code> version on macOS with arm chip. It turns out that it is not
that hard to do that with &lt;code>qemu&lt;/code>.&lt;/p>
&lt;p>All we need is to install &lt;code>qemu&lt;/code> on your macOS.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>brew install qemu
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Verify:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>which qemu-system-x86_64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ /opt/homebrew/bin/qemu-system-x86_64
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Install cross-compilation toolchain:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>$ brew install x86_64-elf-gcc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ which x86_64-elf-gcc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ /opt/homebrew/bin/x86_64-elf-gcc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>make qemu-nox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/run-xv6-x86-64-on-mac-m/</guid><pubDate>Thu, 05 Mar 2026 21:41:33 -0700</pubDate></item><item><title>Assembly Word</title><link>https://danielsunyu.github.io/myblog-site/posts/assembly-word/</link><description>&lt;p>在 x86 体系里——不管 16 位、32 位、还是 64 位模式——
WORD 永远是 16 位 = 2 字节。
这是历史遗产。
早期 8086 是 16 位 CPU。
当时“word”就是机器的自然数据宽度——16 位。
后来扩展到 32 位：
原来的 word 仍然是 16 位
新的 32 位被叫做 double word（DWORD）
再到 64 位：
64 位叫 quad word（QWORD）
所以单位一直叠加：
BYTE = 8 bit
WORD = 16 bit
DWORD = 32 bit
QWORD = 64 bit&lt;/p>
&lt;p>这里的“double”不是“相对当前模式”，
而是相对最初的 16 位 word。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/assembly-word/</guid><pubDate>Tue, 03 Mar 2026 19:26:59 -0700</pubDate></item><item><title>Useful Uou Resources</title><link>https://danielsunyu.github.io/myblog-site/posts/useful-uou-resources/</link><description>&lt;p>Student Health Center
&lt;a href="https://studenthealth.utah.edu/">https://studenthealth.utah.edu/&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/useful-uou-resources/</guid><pubDate>Sun, 22 Feb 2026 14:06:32 -0700</pubDate></item><item><title>Run x86-64 Docker on Macos</title><link>https://danielsunyu.github.io/myblog-site/posts/run-x86-64-docker-on-macos/</link><description/><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/run-x86-64-docker-on-macos/</guid><pubDate>Tue, 17 Feb 2026 16:25:29 -0700</pubDate></item><item><title>决定不玩SRS账户了</title><link>https://danielsunyu.github.io/myblog-site/posts/done-with-srs/</link><description>&lt;p>向SRS账户转入一笔钱的那刻，注定是给自己找麻烦。&lt;/p>
&lt;p>新加坡很多理专忽悠我开通SRS账户。基本上连新加坡人也很少玩SRS。&lt;/p>
&lt;p>钱转入后，看似可以避税，但是打理这个账户非常麻烦。&lt;/p>
&lt;p>首先，SRS需要挂靠在一家银行账户下。为了增值，还需要开通银行的证券账户，所以我还得安装银行的证券App。&lt;/p>
&lt;p>本来SRS就那么点钱，还要用专门的App去运作，真是麻烦的很。而且银行证券服务的交易手续费也比在线券商高很多。&lt;/p>
&lt;p>终于，三思后，打算把余额转出SRS，此生不碰SRS。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/done-with-srs/</guid><pubDate>Sat, 14 Feb 2026 17:58:49 -0700</pubDate></item><item><title>Ampcode</title><link>https://danielsunyu.github.io/myblog-site/posts/ampcode/</link><description>&lt;p>&lt;code>Ampcode&lt;/code>是我入门Vibe Coding，也几乎成为了日常开发工作的重要工具。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://ampcode.com/news/amp-free">https://ampcode.com/news/amp-free&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://ampcode.com/free">https://ampcode.com/free&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://ampcode.com/manual">https://ampcode.com/manual&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://ampcode.com/news/liberating-code-review">https://ampcode.com/news/liberating-code-review&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/ampcode/</guid><pubDate>Wed, 11 Feb 2026 10:48:29 -0700</pubDate></item><item><title>两种几何随机变量的定义</title><link>https://danielsunyu.github.io/myblog-site/posts/geometric-random-variable-note/</link><description>&lt;p>发现在一些主流教材中，几何型随机变量(Geometric Random Variable)的定义有细微的分歧。主流教材中给的定义是，重复多次的抛硬币试验
(单次试验是Bernoulli experiment)，&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Number of flips (failures) until the first heads (success)&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>但有有些教材会定义为：&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Number of flips (failures) before the first heads (success)&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>虽然中外主流教材都是采用第一种定义，但是遗憾的是&lt;strong>R&lt;/strong>和&lt;strong>Python&lt;/strong>中的概率计算库使用的是第二种定义。&lt;/p>
&lt;p>比如为要计算X ~ Geo(0.5)，X = 1的概率，需要传入0：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-R" data-lang="R">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">dgeom&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">0.5&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这种定义的不一致带来毫无必要的麻烦。&lt;/p>
&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Geometric_distribution">https://en.wikipedia.org/wiki/Geometric_distribution&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/geometric-random-variable-note/</guid><pubDate>Mon, 03 Nov 2025 21:50:59 -0700</pubDate></item><item><title>Hello World</title><link>https://danielsunyu.github.io/myblog-site/posts/hello-world/</link><description/><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/hello-world/</guid><pubDate>Sat, 04 Oct 2025 12:11:53 -0600</pubDate></item><item><title>有用的Google Colab命令</title><link>https://danielsunyu.github.io/myblog-site/posts/useful-colab-commands/</link><description>&lt;h4 id="如何将jupyter-notebook转成pdf">如何将Jupyter Notebook转成PDF&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>!sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-plain-generic
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>!sudo apt-get install pandoc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>!jupyter nbconvert --to pdf &amp;lt;path to jupyter notebook&amp;gt;.ipynb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/useful-colab-commands/</guid><pubDate>Sat, 06 Sep 2025 16:52:09 -0600</pubDate></item><item><title>犹他大学CS6353：Deep Learning</title><link>https://danielsunyu.github.io/myblog-site/posts/utah-cs-6353-deep-learning/</link><description>&lt;p>&lt;a href="https://d2l.ai/index.html">https://d2l.ai/index.html&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/utah-cs-6353-deep-learning/</guid><pubDate>Fri, 22 Aug 2025 11:26:51 -0600</pubDate></item><item><title>犹他大学CS 6300：Artificial Intelligence</title><link>https://danielsunyu.github.io/myblog-site/posts/utah-cs6300-ai/</link><description>&lt;p>课程主页：&lt;a href="https://dsbrown1331.github.io/intro-ai-class/">https://dsbrown1331.github.io/intro-ai-class/&lt;/a>&lt;/p>
&lt;p>基本不出所料，这本课程拷贝了Berkeley CS188。&lt;/p>
&lt;p>&lt;a href="https://inst.eecs.berkeley.edu/~cs188/su25/">https://inst.eecs.berkeley.edu/~cs188/su25/&lt;/a>&lt;/p>
&lt;p>Office hours: &lt;a href="https://docs.google.com/spreadsheets/d/1l8_Ao3nhnRuwWtWc2FHGDa45U35HzWy-PXrfO-VEAh4/edit?gid=0#gid=0">https://docs.google.com/spreadsheets/d/1l8_Ao3nhnRuwWtWc2FHGDa45U35HzWy-PXrfO-VEAh4/edit?gid=0#gid=0&lt;/a>&lt;/p>
&lt;p>Piazza: &lt;a href="https://piazza.com/class/me9fkw623gc52m">https://piazza.com/class/me9fkw623gc52m&lt;/a>&lt;/p>
&lt;p>第一章：绪论&lt;/p>
&lt;p>An agent is just something that acts. &lt;br>
A rational agent is one that acts so as to achieve the
best outcome or, when there is uncertainty, the best expected outcome.&lt;/p>
&lt;p>The rational-agent approach to AI has prevailed throughout most of the field’s history. In the early decades, rational
agents were built on logical foundations and formed definite plans to achieve specific goals. Later, methods based on
probability
theory and machine learning allowed the creation of agents that could make decisions under
uncertainty to attain the best expected outcome.&lt;/p>
&lt;p>In a nutshell, AI has focused on the study
and construction of agents that do the right thing. What counts as the right thing is defined
by the objective that we provide to the agent. This general paradigm is so pervasive that we
might call it the standard model.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/utah-cs6300-ai/</guid><pubDate>Fri, 22 Aug 2025 11:17:05 -0600</pubDate></item><item><title>Big Nerd Ranch React Programming笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/react-programming-notes/</link><description>&lt;p>第十三章&lt;/p>
&lt;p>&lt;code>SyntheticBaseEvent&lt;/code> is a wrapper that React puts around native events to ensure that events work the same across all
browsers. You can access the underlying native event through the &lt;code>nativeEvent&lt;/code> property. (However, it is unlikely
that you will ever need it.)&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/react-programming-notes/</guid><pubDate>Sun, 20 Jul 2025 14:43:44 +0800</pubDate></item><item><title>Bootstrap Microservices Ch4</title><link>https://danielsunyu.github.io/myblog-site/posts/bootstrap-microservices-ch4/</link><description>&lt;p>Testing an internal microservice from the outside is normally
only possible in development. Once we move this microservice to production, its
REST API is only available within the Kubernetes cluster. In this case, we’ll make it private because we don’t want the outside world having direct access to our video storage.
This is a security feature of microservices! We can control which microservices are
exposed to the outside world, and we can use that to restrict access to parts of the
application that should not be directly accessible by outsiders.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/bootstrap-microservices-ch4/</guid><pubDate>Wed, 09 Jul 2025 17:21:01 +0700</pubDate></item><item><title>Spring Boot的环境变量</title><link>https://danielsunyu.github.io/myblog-site/posts/spring-boots-env-vars/</link><description>&lt;p>在Spring Boot中，环境变量的定义，可以诸如在application.properties中：&lt;/p>
&lt;pre tabindex="0">&lt;code>server.port=${PORT}
&lt;/code>&lt;/pre>&lt;p>这里的$PORT是一个自定义的环境变量，它将绑定系统预设的server.port，就是服务的端口号。&lt;/p>
&lt;p>但是如果要自定义一个环境变量，而没有系统的某个key对应，那就不要在application.properties中绑定？&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/spring-boots-env-vars/</guid><pubDate>Tue, 08 Jul 2025 17:28:00 +0700</pubDate></item><item><title>Bootstrapping Microservices第三章笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/bm-ch3-notes/</link><description>&lt;p>A microservices application, however, isn’t a microservices application if it only consists of a single microservice!&lt;/p>
&lt;p>We’d like to add a database, that’s one container, but it’s not something we consider as a microservice.&lt;/p>
&lt;p>We could use the local version of Kubernetes that is included with Docker Desktop, but it’s kind of resource hungry
(try running it on a laptop if you want to see poor performance) and just not that convenient to use when we’re working
on multiple projects.&lt;/p>
&lt;p>For now, we can “simulate” Kubernetes on our development computer using Docker Compose, which is much easier and more
straightforward than trying to dive straight into Kubernetes.&lt;/p>
&lt;p>Why Docker Compose? In the same way that Docker allows us to build, run, and manage a single microservice, Docker
Compose gives us a convenient way to build, run, and manage multiple microservices in development. During development
and testing, we must frequently boot and reboot our entire application, which will eventually contain many
microservices. After each small increment of development, we also must test the changes to our code.&lt;/p>
&lt;p>Docker Compose revolves around the Docker Compose file. I like to think of this as a script file that builds a local
instance of a microservices application.&lt;/p>
&lt;p>The Docker Compose file is a script that specifies how to compose an application from multiple Docker containers.&lt;/p>
&lt;p>The Docker Compose file is like a script for building and launching a microservices&lt;/p>
&lt;p>Recall the Dockerfile we created, which was a script for building a single image. The Docker Compose file scales this up
and allows us to orchestrate the creation of a whole application from a collection of Dockerfiles. Docker Compose reads
the Docker Compose file and produces a running application&lt;/p>
&lt;p>We’re now building an application that will soon have more than one microservice. We must therefore put each
microservice into its own separate subdirectory. Our convention is that each subdirectory will be named after its
microservice.&lt;/p>
&lt;p>Our Docker Compose file, which is called &lt;code>docker-compose.yaml&lt;/code>. Because it doesn’t belong to any single microservice, it
lives in the root directory of our microservices application.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-docker" data-lang="docker">&lt;span style="display:flex;">&lt;span>services:&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> video-streaming:&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> image: video-streaming&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> build: &lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> context: ./video-streaming&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> dockerfile: Dockerfile&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> container_name: video-streaming&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> ports:&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> - &lt;span style="color:#d88200">&amp;#34;4000:8080&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> environment:&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> - &lt;span style="color:#111">PORT&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">8080&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">&lt;/span> restart: &lt;span style="color:#d88200">&amp;#34;no&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You might be wondering why we set the &lt;code>restart&lt;/code> option to no. When working in development, we don’t want our
microservices to automatically restart when they crash. If they did that, we could easily miss problems! Instead, if
these crash, we want them to stay that way so that we’ll notice the problem. This is the opposite of how we’d usually
like our microservices to work in production. We’ll see later in chapter 11 how we can have Kubernetes automatically
restart our production microservices that crash.&lt;/p>
&lt;p>The output of Docker commands such as &lt;code>docker ps&lt;/code> can be different from the output of &lt;code>docker compose ps&lt;/code>. That’s
because Docker commands relate to all images and containers on our development computer, whereas Docker Compose commands
only relate to the images and containers specified in our Docker Compose file.&lt;/p>
&lt;p>In this sense, we’re using Docker Compose like a scoping mechanism. It constrains the commands to apply only to images
and containers in our current project. Essentially, it restricts the scope of these commands to the current working
directory, which is another useful aspect of Docker Compose.&lt;/p>
&lt;p>Put another way, &lt;code>docker compose ps&lt;/code> shows us only the containers that are listed in our Docker Compose file, whereas,
&lt;code>docker ps&lt;/code> shows us all containers on our development computer.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/bm-ch3-notes/</guid><pubDate>Fri, 04 Jul 2025 13:21:14 +0700</pubDate></item><item><title>Bootstrapping Microservices V2</title><link>https://danielsunyu.github.io/myblog-site/posts/bootstrapping-microservices-v2/</link><description>&lt;h1 id="chapter-2">Chapter 2&lt;/h1>
&lt;p>Express is the de facto standard for building HTTP servers on Node.js.&lt;/p>
&lt;p>Of course, we could build an HTTP server directly on Node.js without Express,
but Express allows us to do this at a higher level of abstraction, with less code,
and without the nuts-and-bolts code we&amp;rsquo;d otherwise need using the low-level Node.js API.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>npm install --save express
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &amp;ndash;save argument causes the dependency to be added to and tracked in the package.json file. Note that &amp;ndash;save isn&amp;rsquo;t
necessary anymore. In older versions of Node.js, this was required; these days, it&amp;rsquo;s the default.&lt;/p>
&lt;p>The command npm install by itself (not specifying any particular package) installs all the dependencies listed in
package.json.&lt;/p>
&lt;p>The &lt;code>file index.js&lt;/code> is one of the standard names for the main entry point (&lt;em>main&lt;/em> file) of a Node.js application. We
could just as
easily have called it something else, such as main.js or server.js.&lt;/p>
&lt;p>We placed the file index.js under the src directory as a convenient way to keep our source code files separated and
easily distinguished from our configuration and other files. The directory doesn&amp;rsquo;t have to be called src —— you can
call it anything you like —— but src is a common name for it. Don&amp;rsquo;t forget to update your package.json file to include
the location of index.js within the src directory.&lt;/p>
&lt;p>It&amp;rsquo;s customary during development to set your Node.js application to listen on port 3000.&lt;/p>
&lt;p>Environment variables can be thought of as an input or parameter to our microservice.&lt;/p>
&lt;p>&lt;strong>Configuring a microservice&lt;/strong>&lt;/p>
&lt;p>We need a way to configure our microservice so it knows the port number to use when starting the HTTP server. There are
several techniques we might use to configure our microservice, such as configuration files or command-line arguments.
These techniques work, but another has emerged as the standard way to configure a microservice, and it’s well supported
by all the tools we’ll be using. We’ll configure our microservices using &lt;strong>environment variables&lt;/strong>.&lt;/p>
&lt;p>To run multiple different microservices at the same time, we’ll have to start them on separate &lt;strong>port&lt;/strong> numbers.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">export&lt;/span> &lt;span style="color:#111">PORT&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">3000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can also use environment variables to pass secret and sensitive data into a microservice (e.g., the password for our
database). We need to treat this information carefully, and we shouldn’t store it in the code where everyone in the
company can see it.&lt;/p>
&lt;p>Well, to get our microservice ready to run in production, we’ll use a slightly different version of this command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>npm install --omit&lt;span style="color:#f92672">=&lt;/span>dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We added the argument &lt;code>--omit=dev&lt;/code> to omit development dependencies and only install those dependencies that are
required
in production. This is important because when creating a Node.js project, we’ll usually have a bunch of these so-called
dev dependencies that we only need to support our development efforts—we don’t want to install these into our production
environment.&lt;/p>
&lt;p>&lt;strong>npm script&lt;/strong>&lt;/p>
&lt;p>Up until now, we’ve run our HTTP server on our dev computer like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>node src/index.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That’s OK, but now we’ll start running our microservice using the following standard convention for Node.js:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>npm start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注：npm start是启用生产环境的惯例。&lt;/p>
&lt;p>Invoking the command npm start is the conventional way to start a Node.js application. This is a special case of a npm
script.&lt;/p>
&lt;p>The nice thing about this convention is that for almost any Node.js project (at least those that follow this convention)
, we can run &lt;code>npm start&lt;/code> without actually knowing if the main file is called &lt;code>index.js&lt;/code> or if it has some other name. We
also don’t need to know if the application takes any special command-line arguments or configuration because those
details can be recorded here as well.&lt;/p>
&lt;p>This gives us a single command to remember regardless of whatever project we’re looking at and however the particular
application is started. This makes understanding how to use any Node.js project much easier, even those created by other
people.&lt;/p>
&lt;p>So far, we set up our microservice to run on our development computer. That’s all well
and good—we need that for ongoing development and testing—but before we get to
the fun stuff (Docker, Kubernetes, Terraform, etc.), we need to know how to set up
our microservice to run in the production environment.
When I say production environment, what I mean is our customer-facing environment.
That’s where our application is hosted so it can be accessed by our customers. For this
book, our production environment is Kubernetes, and we’re gearing up to run our
application in a Kubernetes cluster to make it publicly accessible.&lt;/p>
&lt;p>&lt;strong>Live reloading for fast iteration&lt;/strong>&lt;/p>
&lt;p>To create our live reload pipeline, we’ll install a package called nodemon. We use nodemon to run our microservice, and
it automatically watches for code changes in our project. When a code change is detected, nodemon automatically restarts
our microservice for us, saving us the effort of doing so manually. This might not sound like it does much at all, but
I’ve found that it makes for a fast and fluid development cycle. Once you’ve tried it, you might wonder how you ever did
without it.&lt;/p>
&lt;p>We can install nodemon in our Node.js project as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>npm install --save-dev nodemon
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that now we’re using the &lt;code>--save-dev&lt;/code> argument. This installs the package as a dev dependency rather than a
production dependency.&lt;/p>
&lt;h3 id="npx-command">npx command&lt;/h3>
&lt;p>Now that we’re going to be using nodemon instead, we’ll replace node with nodemon and run it like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>npx nodemon src/index.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The npx command that’s suddenly appeared is a useful command that comes with
Node.js and allows us to run locally installed packages directly from the command
line. Before npx was added to Node.js, we used to install modules such as nodemon
globally. &lt;a href="#">Now we can run tools like this directly from the current project’s dependencies.&lt;/a> This really helps us use
the right versions of modules for each project and prevents our computer from being cluttered up with globally installed
modules.&lt;/p>
&lt;h3 id="debugging-the-container">Debugging the container&lt;/h3>
&lt;p>When we’re running a container locally, especially one that is having problems, it can be useful to shell into it and
inspect it from the inside. This can help us understand what’s happening inside our container. We can open a shell into
our container like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>docker &lt;span style="color:#111">exec&lt;/span> -it &amp;lt;container-id&amp;gt; bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>From here, you can use common Linux commands such as &lt;code>cd&lt;/code>, &lt;code>ls&lt;/code>, and &lt;code>ps&lt;/code> to inspect the filesystem and process inside
the container. This is a valuable technique for debugging and understanding what is going on in your container, so
please spend some time exploring inside your container.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/bootstrapping-microservices-v2/</guid><pubDate>Sun, 29 Jun 2025 22:52:19 +0700</pubDate></item><item><title>创新思维与创业管理</title><link>https://danielsunyu.github.io/myblog-site/posts/entrepreneurship/</link><description>&lt;p>创新思维方式：敢于挑战常规和传统模式，用与众不同的思考方式提出全新的想法或者寻找更好解决方案的思维方式；Think different。&lt;/p>
&lt;p>要做到它需要：&lt;/p>
&lt;ol>
&lt;li>拆毁心理之墙&lt;/li>
&lt;li>多问为什么&lt;/li>
&lt;li>第一性原理&lt;/li>
&lt;li>多角度看问题&lt;/li>
&lt;/ol></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/entrepreneurship/</guid><pubDate>Fri, 27 Jun 2025 16:44:24 +0700</pubDate></item><item><title>Node Trick 1</title><link>https://danielsunyu.github.io/myblog-site/posts/node-trick-1/</link><description>&lt;p>在Node项目中，要运行npm install，必须要存在package.json。&lt;/p>
&lt;p>如果是手动从零新建一个项目，新建package.json后，加入个空的对象。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// package.json
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">{}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>否则，运行npm install foo会报错。&lt;/p>
&lt;p>或是用npm init -y来创建，参数-y避免在创建创木时需要回答的一些交互问题。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/node-trick-1/</guid><pubDate>Thu, 26 Jun 2025 17:32:47 +0700</pubDate></item><item><title>ETF并不一定是指数ETF</title><link>https://danielsunyu.github.io/myblog-site/posts/etf-might-not--be-index-etf/</link><description>&lt;p>ETF (Exchange-Traded Funds)被翻译为“交易所挂牌基金”或是“交易所交易基金”。&lt;/p>
&lt;p>不要误认为ETF就是挂钩某个指数(index)的ETF，甚至是宽基指数(broadband index)。&lt;/p>
&lt;p>比如&lt;a href="https://kraneshares.com/kweb/">KWEB&lt;/a>挂钩某个小众指数 — 中证海外中国互联网指数(CSI Overseas China Internet Index)。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/etf-might-not--be-index-etf/</guid><pubDate>Wed, 25 Jun 2025 12:59:22 +0700</pubDate></item><item><title>CMU: Intro to Ml Notes</title><link>https://danielsunyu.github.io/myblog-site/posts/cmu-intro-to-ml/</link><description>&lt;h1 id="第一课">第一课&lt;/h1>
&lt;p>Artificial Intelligence (AI): Getting Computers to Behave Intelligently&lt;/p>
&lt;p>Do things that people do well (better than computers)
A moving target! But usually involves:&lt;/p>
&lt;ul>
&lt;li>Perceptron&lt;/li>
&lt;li>Control&lt;/li>
&lt;li>Planning&lt;/li>
&lt;li>Human language (recognize, understand, respond to, generate)&lt;/li>
&lt;/ul>
&lt;h3 id="example-tasks">Example Tasks:&lt;/h3>
&lt;ul>
&lt;li>Identify objects in an image&lt;/li>
&lt;li>Translate from one huamn language to another&lt;/li>
&lt;li>Recognoize speech&lt;/li>
&lt;li>Assess risk (e.g. in loan application)&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;h3 id="1st-attempt-knowledge-based-ai-1960s--1980s">1st Attempt: &amp;ldquo;Knowledge-Based AI&amp;rdquo; (1960s — 1980s)&lt;/h3>
&lt;p>= Write programs that simulate how people do it.
Problems:&lt;/p>
&lt;ul>
&lt;li>Will never get better than a person&lt;/li>
&lt;li>Requires deep introspection&lt;/li>
&lt;li>Sometimes requires experts (&amp;ldquo;expert systems&amp;rdquo;, &amp;ldquo;knowledge elicitation&amp;rdquo;)&lt;/li>
&lt;li>Often we don&amp;rsquo;t know how we do things (e.g. ride bicycle)
&lt;ul>
&lt;li>Difference between knowing and knowing-how-we-know&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Sometimes we &lt;em>think&lt;/em> we know, but we&amp;rsquo;re wrong&lt;/li>
&lt;/ul>
&lt;p>Didn&amp;rsquo;t work as well as hoped.&lt;/p>
&lt;h3 id="alternative-data-based-ai-aka-machine-learning-1980s--today">Alternative: &amp;ldquo;Data-Based AI&amp;rdquo; (a.k.a Machine Learning) (1980s — today)&lt;/h3>
&lt;p>= Write programs that learn the task from examples.&lt;/p>
&lt;ul>
&lt;li>You don&amp;rsquo;t need to know how to do it yourself&lt;/li>
&lt;li>Performance (should) improve with more examples&lt;/li>
&lt;/ul>
&lt;p>But:&lt;/p>
&lt;ul>
&lt;li>Need lots of examples! (millions and billions)&lt;/li>
&lt;li>When it finally works, you may not understand how&lt;/li>
&lt;/ul>
&lt;h1 id="lecture-2">Lecture 2&lt;/h1>
&lt;p>ML: Learn a task from experience (examples)&lt;/p>
&lt;ul>
&lt;li>Get better at the task with experience&lt;/li>
&lt;/ul>
&lt;p>Medical Diagnosis:
f: Patient Info -&amp;gt; {Categories}, Classification&lt;/p>
&lt;p>Predict Tomorrow&amp;rsquo;s Temperature
f: (Input) -&amp;gt; R, Regular Regression&lt;/p>
&lt;p>&lt;strong>ML = Learning a function.&lt;/strong>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/cmu-intro-to-ml/</guid><pubDate>Sat, 26 Apr 2025 11:24:57 -0600</pubDate></item><item><title>Spring Security in Action 2 Notes</title><link>https://danielsunyu.github.io/myblog-site/posts/spring-security-in-action-2-notes/</link><description>&lt;h1 id="chapter-2">Chapter 2&lt;/h1>
&lt;p>For the apps that you develop with the Spring Framework, Spring Security is an excellent choice for application-level
security.&lt;/p>
&lt;p>To customize the handling of authentication and authorization, we’ll need to define a bean of type SecurityFilterChain.&lt;/p>
&lt;p>An object that implements a &lt;code>UserDetailsService&lt;/code> interface with Spring Security manages the details about users.&lt;/p>
&lt;p>It is good practice to separate the responsibilities even for the configuration classes.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/spring-security-in-action-2-notes/</guid><pubDate>Mon, 24 Mar 2025 21:49:33 -0600</pubDate></item><item><title>MongoDB in Action 2笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/notes-on-mongodb-in-action-2/</link><description>&lt;h3 id="chapter-1">Chapter 1&lt;/h3>
&lt;p>Perhaps the biggest reason developers use MongoDB isn&amp;rsquo;t because of its scaling strategy, but because of its intuitive
data model. MongoDB stores its information in &lt;strong>documents&lt;/strong> rather than rows.&lt;/p>
&lt;p>A document-based data model can represent rich, hierarchical data structures. It&amp;rsquo;s often possible to do without the
multitable joins common to relational databases.&lt;/p>
&lt;p>&amp;hellip; the distinction between a &lt;strong>tabular&lt;/strong> and &lt;strong>object&lt;/strong> representation of data &amp;hellip;&lt;/p>
&lt;p>The umbrella term &lt;strong>NoSQL&lt;/strong> was coined in 2009 to lump together the many relational database gaining in popularity at the
time, one of their commonalities being that they use a query language other than SQL.&lt;/p>
&lt;p>The most important thing to remember from its history is that MongoDB was intended to be an extremely simple, yet
flexible, part of a web-application stack.&lt;/p>
&lt;p>Internally, MongoDB stores documents in a format called Binary JSON, or &lt;strong>BSON&lt;/strong>.&lt;/p>
&lt;p>BSON has a similar structure (of JSON) but is intended for storing many documents.&lt;/p>
&lt;p>Where relational databases have tables, MongoDB has &lt;strong>collections&lt;/strong>.&lt;/p>
&lt;p>The data in a collection is stored to disk, and most queries require you to specify which collection you&amp;rsquo;d like to
target.&lt;/p>
&lt;p>The technique of separating an object&amp;rsquo;s data into multiple tables is known as &lt;strong>normalization&lt;/strong>. A normalized data set,
among other things, ensures that each unit of data is represented in one place only.&lt;/p>
&lt;p>But strict normalization isn&amp;rsquo;t without its costs. Notably, some &lt;em>assembly&lt;/em> is required.&lt;/p>
&lt;p>A document-oriented data model naturally represents data in an aggregate form, allowing you to work with an object
holistically.&lt;/p>
&lt;p>MongoDB groups documents into collections, containers that don’t impose any sort of schema. In theory, each document in
a collection can have a completely different structure; in practice, a collection’s document will be relatively uniform.&lt;/p>
&lt;p>Your application code, and not the database, enforces the data&amp;rsquo;s structure.&lt;/p>
&lt;p>To say that a system supports &lt;strong>ad hoc queries&lt;/strong> (即席查询) is to say that it isn’t necessary to define in advance what sorts of
queries the system will accept. Relational databases have this property; they’ll faithfully execute any well-formed SQL
query with any number of conditions.&lt;/p>
&lt;p>One of MongoDB’s design goals is to &lt;strong>&lt;em>preserve&lt;/em>&lt;/strong> most of the query power that’s been so fundamental to the relational
database world.&lt;/p>
&lt;p>With MongoDB, you can create up to 64 indexes per collection.&lt;/p>
&lt;p>MongoDB provides database replication via a topology known as a &lt;strong>replica set&lt;/strong>.&lt;/p>
&lt;p>Replica sets distribute data across two or more machines for redundancy and automate fail-over in the event of server
and network outages.&lt;/p>
&lt;p>Since MongoDB v2.0, &lt;strong>journaling&lt;/strong> is enabled by default. With journaling, every write is flushed to the journal file every
100ms. If the server is ever shut down uncleanly (say, in a power outage), the journal will be used to ensure that
MongoDB’s data files are restored to a consistent state when you restart the server. This is the safest way to run
MongoDB.&lt;/p>
&lt;p>MongoDB was designed to make horizontal scaling manageable. It does so via a range-based partitioning mechanism, known
as &lt;strong>sharding&lt;/strong>, which automatically manages the distribution of data across nodes. There’s also a hash- and tag-based
sharding mechanism, but it’s just another form of the range-based sharding mechanism.&lt;/p>
&lt;p>The core database server runs via an executable called &lt;code>mongod&lt;/code>. The &lt;code>mongod&lt;/code> server process receives commands over a
network socket using a custom binary protocol.&lt;/p>
&lt;p>The MongoDB command shell is a JavaScript-based tool for administering the database and manipulating data. The &lt;code>mongosh&lt;/code>
executable loads the shell and connects to a specified mongod process, or one running locally by default.&lt;/p>
&lt;h3 id="chapter-2">Chapter 2&lt;/h3>
&lt;p>MongoDB divides collections into separate databases. Unlike the usual overhead that databases produce in the SQL world,
databases in MongoDB are just &lt;em>namespaces&lt;/em> to distinguish between collections.&lt;/p>
&lt;p>Databases and collections are &lt;em>created only&lt;/em> when documents are first inserted.&lt;/p>
&lt;p>Every MongoDB document requires an &lt;code>_id&lt;/code>, and if one isn&amp;rsquo;t present when the document is created, a special MongoDB
&lt;code>ObjectID&lt;/code> will be generated and added to the document at that time.&lt;/p>
&lt;p>You can set your own &lt;code>_id&lt;/code> by setting it in the document you insert, the &lt;code>ObjectID&lt;/code> is just MongoDB&amp;rsquo;s default.&lt;/p>
&lt;p>A &lt;strong>query selector&lt;/strong> is a document that&amp;rsquo;s used to match against all documents in the collection.&lt;/p>
&lt;p>Note that calling the &lt;code>find&lt;/code> method without any argument is equivalent to passing in an empty predicate; &lt;code>db.user.find()&lt;/code>
is the same as &lt;code>db.users.find({})&lt;/code>.&lt;/p>
&lt;p>Rather, the query itself is a document. The idea of representing commands as documents is used often in MongoDB and may
come as a surprise if you&amp;rsquo;re used to relational databases.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/notes-on-mongodb-in-action-2/</guid><pubDate>Fri, 21 Mar 2025 16:47:35 -0600</pubDate></item><item><title>Programming in Python</title><link>https://danielsunyu.github.io/myblog-site/posts/programming-in-python/</link><description>&lt;p>Lists are an extension of an earlier, more primitive concept called &lt;strong>arrays&lt;/strong>.&lt;/p>
&lt;p>An older programming concept called a &lt;strong>record&lt;/strong>, which is any data structure that combines several distinct values into
an integrated whole.&lt;/p>
&lt;p>The individual components of a record are generally called &lt;strong>fields&lt;/strong>.&lt;/p>
&lt;p>The simplest way to represent a record in Python is to use a built-in data structure called &lt;strong>tuple&lt;/strong>, which is used in both computer science and mathematics to refer to an
ordered, immutable collection of elements.&lt;/p>
&lt;p>As it happens, Python programmers rarely refer to the elements of a tuple by their
index number because the language offers a convenient syntactic form called
&lt;strong>destructuring assignment&lt;/strong> for splitting a tuple into its component elements.&lt;/p>
&lt;p>Encode the information for each record as an object containing the
necessary fields, which are more often called &lt;strong>attributes&lt;/strong> in the context of a Python
object.&lt;/p>
&lt;p>In Python, having a reference to an object makes it possible to create new attributes within it.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/programming-in-python/</guid><pubDate>Tue, 18 Mar 2025 20:50:12 -0600</pubDate></item><item><title>Data Serialization Formats Useability</title><link>https://danielsunyu.github.io/myblog-site/posts/data-serialization-formats/</link><description>&lt;p>JSON
JSONC
JSON5
HJSON
YAML
TOML
XML
CSV&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/data-serialization-formats/</guid><pubDate>Fri, 14 Mar 2025 23:11:07 -0600</pubDate></item><item><title>Tableau With Postgres</title><link>https://danielsunyu.github.io/myblog-site/posts/tableau-with-postgres/</link><description/><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/tableau-with-postgres/</guid><pubDate>Sat, 08 Mar 2025 14:21:01 -0700</pubDate></item><item><title>本地安装MongoDB 8.0+</title><link>https://danielsunyu.github.io/myblog-site/posts/install-mongodb/</link><description>&lt;p>&lt;a href="https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#std-label-install-mdb-community-macos">https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#std-label-install-mdb-community-macos&lt;/a>&lt;/p>
&lt;h3 id="mongosh">mongosh&lt;/h3>
&lt;p>The MongoDB Shell, mongosh, is a JavaScript and Node.js REPL environment for interacting with MongoDB deployments.&lt;/p>
&lt;h3 id="mongodb-compass">MongoDB Compass&lt;/h3>
&lt;h3 id="用命令行启动mongodb服务器">用命令行启动MongoDB服务器&lt;/h3>
&lt;p>MongoDB needs a folder/directory to store the database.&lt;/p>
&lt;p>启动mongod，需要带上存储路径&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>% mongod --dbpath /opt/homebrew/var/mongodb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>--dbpath&lt;/code>参数：Directory for datafiles - defaults to &lt;code>/data/db&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>% mongod --config /opt/homebrew/etc/mongod.conf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>/opt/homebrew/etc/mongod.conf&lt;/code>是MongoDB的配置文件&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-textmate" data-lang="textmate">systemLog:
destination: file
path: /opt/homebrew/var/log/mongodb/mongo.log
logAppend: true
storage:
dbPath: /opt/homebrew/var/mongodb
net:
bindIp: 127.0.0.1, ::1
ipv6: true
&lt;/code>&lt;/pre>&lt;p>如果是用homebrew安装的MongoDB，可以这样启动和关闭：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>% brew services start mongodb-community
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>% brew services stop mongodb-community
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>you should be able to directly interact with the MongoDB database by running the command:&lt;/p>
&lt;pre tabindex="0">&lt;code>% mongosh
&lt;/code>&lt;/pre>&lt;h3 id="参考">参考&lt;/h3>
&lt;p>&lt;a href="https://web.stanford.edu/class/cs142/install.html">https://web.stanford.edu/class/cs142/install.html&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/install-mongodb/</guid><pubDate>Wed, 05 Mar 2025 15:13:15 -0700</pubDate></item><item><title>安装PostgreSQL</title><link>https://danielsunyu.github.io/myblog-site/posts/install-postgres/</link><description>&lt;blockquote>
&lt;p>Postgres似乎是比PostgreSQL更cool的称呼。&lt;/p>&lt;/blockquote>
&lt;p>上一份工作一直在和Postgres打交道。本地Mac开发环境里，Postgres跑在了Docker容器中，非侵入式地安装。然后使用DataGrip提供的可视化界面进行数据查询。&lt;/p>
&lt;p>而侵入式地安装Postgres，会把本地文件系统搞得乱糟糟。安装容易卸载难啊。&lt;/p>
&lt;p>如果想geek一些的，推荐&lt;a href="https://danielsunyu.github.io/myblog-site/posts/run-postgres-on-docker/">在Docker中运行Postgres&lt;/a>。&lt;/p>
&lt;h3 id="本地安装">本地安装&lt;/h3>
&lt;p>然而在大学课堂里，大部分教授都不懂Docker，所以课堂上要求侵入式地安装Postgres —— 我也老老实实地照做了。&lt;/p>
&lt;p>一种简单的安装方式是直接从Postgres官网下载，在&lt;a href="https://www.postgresql.org/download/">下载页面&lt;/a>可找到各平台的Installer安装包。目前最新的版本是17。&lt;/p>
&lt;p>初始安装后，界面只会显示默认的postgres数据库。&lt;/p>
&lt;blockquote>
&lt;p>注意，这里是指在Postgres中的一个叫postgres的数据库。&lt;/p>&lt;/blockquote>
&lt;figure>&lt;img src="https://danielsunyu.github.io/myblog-site/images/postgres-ui.png" width="480px" height="360px">
&lt;/figure>
&lt;p>直接安装Postgres也是有好处的，有一个操作Postgres的极简用户界面。界面上会列出了一个个本地创建的数据库。此外，可以用界面启动、暂停Postgres服务器。&lt;/p>
&lt;h3 id="设置path环境变量">设置PATH环境变量&lt;/h3>
&lt;p>此外，安装目录带了许多原生的命令行工具，其中有重要的&lt;strong>psql&lt;/strong>命令。它的所在位置如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>/Applications/Postgres.app/Contents/Versions/17/bin/psql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为了在Terminal运行这条命令，要把Postgres的bin目录放入PATH环境变量中。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">export&lt;/span> &lt;span style="color:#111">PATH&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">$PATH&lt;/span>:/Applications/Postgres.app/Contents/Versions/17/bin
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样就能运行psql命令了：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-zsh" data-lang="zsh">&lt;span style="display:flex;">&lt;span>% psql --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>psql &lt;span style="color:#f92672">(&lt;/span>PostgreSQL&lt;span style="color:#f92672">)&lt;/span> 17.4 &lt;span style="color:#f92672">(&lt;/span>Postgres.app&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>安装完毕后，与Postgres交互可以从psql命令行开始。需要掌握&lt;a href="https://danielsunyu.github.io/myblog-site/posts/essential-psql-commands">psql的常用命令&lt;/a>。&lt;/p>
&lt;p>&lt;em>请我喝杯咖啡吧！&lt;/em>&lt;/p>
&lt;p>&lt;a href="https://www.buymeacoffee.com/danielsun">&lt;img src="https://tinyurl.com/57dkxa4f" width="120"/>&lt;/a>&lt;/p>
&lt;p>完毕&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/install-postgres/</guid><pubDate>Mon, 03 Mar 2025 15:54:57 -0700</pubDate></item><item><title>Learning Numpy</title><link>https://danielsunyu.github.io/myblog-site/posts/learning-numpy/</link><description>&lt;p>这是找到的一个NumPy Tutorial
&lt;a href="https://cs231n.github.io/python-numpy-tutorial/">https://cs231n.github.io/python-numpy-tutorial/&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/learning-numpy/</guid><pubDate>Tue, 25 Feb 2025 09:39:42 -0700</pubDate></item><item><title>Data Wrangling</title><link>https://danielsunyu.github.io/myblog-site/posts/data-wrangling/</link><description>&lt;p>Data Analysis (Wikipedia&amp;rsquo;s definition): the process of converting data, with the help of tools, from one form to another to allow convenient
consumption of the data. This includes transformation, aggregation, visualization, and statistics.&lt;/p>
&lt;p>Data Wrangling (author&amp;rsquo;s definition): the whole process of working with data to get it into and through your pipeline, whatever that may be,
from data acquisition to your target audience, whoever they might be.&lt;/p>
&lt;p>Data Analysis (Wikipedia): the process of working with and inspecting data to support decision-making.&lt;/p>
&lt;p>Data Analysis (author): I view data analysis a subset of the data-wrangling process.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/data-wrangling/</guid><pubDate>Fri, 17 Jan 2025 23:19:33 -0700</pubDate></item><item><title>Monorepo和Microservices</title><link>https://danielsunyu.github.io/myblog-site/posts/monorepo-and-microservices/</link><description>&lt;p>&lt;a href="https://monorepo.tools/">https://monorepo.tools/&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://www.atlassian.com/git/tutorials/monorepos">https://www.atlassian.com/git/tutorials/monorepos&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://danluu.com/monorepo/">https://danluu.com/monorepo/&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://news.ycombinator.com/item?id=33587622">https://news.ycombinator.com/item?id=33587622&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/monorepo-and-microservices/</guid><pubDate>Wed, 15 Jan 2025 15:20:28 -0700</pubDate></item><item><title>Book Troubleshooting Java</title><link>https://danielsunyu.github.io/myblog-site/posts/book-troubleshooting-java/</link><description>&lt;p>最近在读一本Larentiu Spilca写的关于Java的调试和性能刨析的书。&lt;/p>
&lt;figure>&lt;img src="https://m.media-amazon.com/images/I/61BaCofsSyL._SL1500_.jpg" width="400px" height="720px">
&lt;/figure>
&lt;h1 id="第六章identifying-resource-consumption-problems-using-profiling-techniques">第六章：Identifying resource consumption problems using profiling techniques&lt;/h1>
&lt;blockquote>
&lt;p>I consider learning to use a profiler a must for all developers, as it can be a compass to guide you to the cause of a
seemingly hopeless problem.&lt;/p>&lt;/blockquote>
&lt;p>作者推荐&lt;a href="https://visualvm.github.io/index.html">VisualVM&lt;/a>，一款免费的profiler。此外还可以选：&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://jdk.java.net/jmc/8/">Java Mission Control&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.ej-technologies.com/jprofiler">JProfiler&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>A memory leak is when an app stores and keeps references to unused objects.&lt;/p>
&lt;p>&lt;a href="https://square.github.io/leakcanary/">LeakCanary&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/book-troubleshooting-java/</guid><pubDate>Fri, 16 Aug 2024 19:35:23 +0800</pubDate></item><item><title>MapStruct介绍</title><link>https://danielsunyu.github.io/myblog-site/posts/mapstruct-introduction/</link><description>&lt;blockquote>
&lt;p>所谓的成为一位后端工程师，无非就是要掌握一系列的后端技术。学习了一门小的技术，并会拆解它，这样，就朝着后端工程师迈入坚实的一步。&lt;/p>&lt;/blockquote>
&lt;p>我司的Spring Boot项目中，有引用一个第三方依赖 — &lt;a href="https://mapstruct.org/">MapStruct&lt;/a>，属于工具类的库。&lt;/p>
&lt;figure>&lt;img src="https://mapstruct.org/images/mapstruct.png" width="360px" height="200px">
&lt;/figure>
&lt;p>引用官网的介绍：&lt;/p>
&lt;blockquote>
&lt;p>MapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based
on a convention over configuration approach.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/mapstruct-introduction/</guid><pubDate>Sat, 10 Aug 2024 14:55:53 +0800</pubDate></item><item><title>Git笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/git-notes/</link><description>&lt;p>&lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">安装Git&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">首次配置Git&lt;/a>&lt;/p>
&lt;p>Git从2.28.0版本（2020年7月）开始将默认的初始分支名称从&amp;quot;master&amp;quot;改为&amp;quot;main&amp;quot;。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/git-notes/</guid><pubDate>Thu, 06 Jun 2024 20:34:54 +0800</pubDate></item><item><title>Leanring Kotlin Coroutines</title><link>https://danielsunyu.github.io/myblog-site/posts/leanring-kotlin-coroutines/</link><description>&lt;blockquote>
&lt;p>Suspending functions, like &lt;code>withContext&lt;/code>, can only be called from other suspending functions or inside a coroutine builder.&lt;/p>&lt;/blockquote>
&lt;p>对于Kotlin的Coroutines，不应该参考维基百科的协程定义。&lt;/p>
&lt;blockquote>
&lt;p>Kotlin&amp;rsquo;s coroutines are a language-level feature designed for structured concurrency, while operating system coroutines
are a low-level mechanism for cooperative multitasking provided by the operating system or user-level libraries.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/leanring-kotlin-coroutines/</guid><pubDate>Sat, 25 May 2024 22:16:56 +0800</pubDate></item><item><title>学习Kotlin</title><link>https://danielsunyu.github.io/myblog-site/posts/learning-kotlin/</link><description>&lt;p>Kotlin的杀手锏是与Java的互操作性。&lt;/p>
&lt;p>&lt;strong>Kotlinx&lt;/strong> — a set of optional, first-party libraries provided by JetBrains that extend on the base functionality in the
Kotlin language and standard library. The &lt;strong>Coroutines&lt;/strong> library is also part of Kotlinx.&lt;/p>
&lt;p>&lt;strong>CIO&lt;/strong> — coroutine-based I/O.&lt;/p>
&lt;p>&lt;strong>Structured Concurrency&lt;/strong> — A paradigm for managing batches of coroutines and handling them collectively as resources.&lt;/p>
&lt;p>&lt;strong>async&lt;/strong> — A coroutine builder that can be used as an alternative to launch. Much like launch, async accepts a lambda
expression as an argument, which is where you can call other code that suspends. The big difference between these two
functions is their return types:&lt;/p>
&lt;h1 id="coroutines">Coroutines&lt;/h1>
&lt;blockquote>
&lt;p>Unlike threads, coroutines can execute and wait for the completion of other work without blocking the thread they are
launched on – thanks to the magic of suspending functions.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Kotlin 1.3 introduced stable support for coroutines, but coroutines are not new or exclusive to Kotlin. The concept of
a coroutine dates back to the 1950s, and they have been implemented in many programming languages.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Coroutines are based on the idea of functions being able to suspend, meaning that a function can be paused until a
long-running operation completes.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Coroutines provide a high-level and safer set of tools to help you build asynchronous code. Under the hood, Kotlin’s
coroutines use threads to perform work in parallel, but you often do not have to worry about this detail.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Kotlin does not ship with support for coroutines.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/learning-kotlin/</guid><pubDate>Fri, 24 May 2024 18:05:54 +0800</pubDate></item><item><title>F公司的Backend Tech Stack</title><link>https://danielsunyu.github.io/myblog-site/posts/company-f-backend-tech-stack/</link><description>&lt;p>很感恩，差不多三月底拿到F公司的的offer，并于4月15日入职。那天是周三，一个值得纪念的日子。&lt;/p>
&lt;p>算来刚满了一月。我想聊聊技术栈。公司主要使用Kotlin和TypeScript&lt;/p>
&lt;h1 id="基础技能">基础技能：&lt;/h1>
&lt;p>&lt;a href="https://danielsunyu.github.io/myblog-site/posts/git-notes">Git&lt;/a>：the popular version control system&lt;br>
Docker&lt;br>
REST API&lt;br>
Postman/cURL&lt;br>
SQL&lt;br>
IntelliJ IDEA&lt;br>
&lt;a href="https://docs.gradle.org/current/userguide/userguide.html">Gradle&lt;/a>&lt;br>
Linux basics&lt;br>
TypeScript&lt;br>
Node.js&lt;br>
&lt;a href="https://kotlinlang.org/">Kotlin&lt;/a>&lt;/p>
&lt;h1 id="进阶技能">进阶技能&lt;/h1>
&lt;h2 id="unit-testing">Unit Testing&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://kotest.io/">Kotest&lt;/a>：Kotest is a flexible and elegant multi-platform test framework for Kotlin with extensive
assertions and integrated property testing&lt;/li>
&lt;li>JUnit 5&lt;/li>
&lt;/ul>
&lt;p>Spring Boot&lt;br>
PostgreSQL&lt;br>
Kafka\&lt;/p>
&lt;h2 id="graphql">&lt;a href="https://graphql.org/">GraphQL&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://opensource.expediagroup.com/graphql-kotlin/docs">Expedia™️ GraphQL Kotlin&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://the-guild.dev/graphql/tools">GraphQL Tools&lt;/a>：A set of utilities for faster GraphQL development.&lt;/li>
&lt;li>&lt;a href="https://the-guild.dev/graphql/gateway">The Guild/Conductor&lt;/a>：A Fully-Featured, Open-Source
GraphQL Gateway for Your Project&lt;/li>
&lt;li>&lt;a href="https://the-guild.dev/graphql/codegen">The Guild/GraphQL Codegen&lt;/a>：Generate code from your GraphQL schema and operations with a simple CLI&lt;/li>
&lt;/ul>
&lt;h2 id="exposed">&lt;a href="https://jetbrains.github.io/Exposed/home.html">Exposed&lt;/a>&lt;/h2>
&lt;p>Exposed is a Kotlin SQL database library with two flavors: a lightweight ORM (using DAO) and type-safe SQL (using DSL).&lt;br>
AWS&lt;br>
Camunda&lt;/p>
&lt;h2 id="高阶技能">高阶技能&lt;/h2>
&lt;p>TimescaleDB&lt;br>
nginx&lt;br>
Flyway&lt;br>
Terraform&lt;br>
&lt;a href="https://www.keycloak.org/">Keycloak&lt;/a>：一个开源的身份和访问管理系统,提供了完整的认证、授权、用户管理等功能。它是一个独立的认证服务器,可以与多种应用程序集成。&lt;br>
&lt;a href="https://kubernetes.io/">Kubernetes&lt;/a>&lt;/p>
&lt;p>TBC&amp;hellip;&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/company-f-backend-tech-stack/</guid><pubDate>Wed, 22 May 2024 19:51:10 +0800</pubDate></item><item><title>新加坡是福利国家吗？</title><link>https://danielsunyu.github.io/myblog-site/posts/is-singapore-a-welfare-state/</link><description>&lt;p>很多人会认为新加坡不是一个福利国家。它独特的公积金制度，是一个以受雇者薪水作为福利来源的方式。
确实，和西方发达国家在福利上支出相比，新加坡政府每年在福利项目上的支出，仅占总支出的2.15%和GDP的0.49%。
与此相比，美国政府在医疗福利上每年的支出竟高达GDP的17.3%。
这样福利制度的顶层设计，背后的指导思想是极小化福利支出在财政上的负担，让新加坡藉以保持竞争力。
反观很多欧美国家，受雇者一旦失业，可以向政府每月领取失业金，即使不用上班也可以过着体面的生活。当然这样从宏观上看，是降低了社会的竞争力。&lt;/p>
&lt;p>既然新加坡人在医疗和养老上是以自助为基础的，我为何认为它是个福利国家呢？&lt;/p>
&lt;p>原因就在于新加坡独特的公屋制度。按照住建局的公屋制度，每一对新加坡夫妇（有一方得是公民）有生之年，有一次申请新屋(BTO)的机会。
新屋的价格非常低廉，以至于低收入家庭也能够负担得起。
申请新屋大致流程是向住建局提出申请。住建局提供一些候选的地点和户型。其中户型大小和家庭大小有一定关联，人口多的家庭有资格申请较大的户型。
选定后，住建局下单开始兴建新屋。&lt;/p>
&lt;blockquote>
&lt;p>经过几十年的密集建设，现在新加坡的23个城镇共有100多万套组屋。1960年，只有9%的新加坡人住在公共住房，如今接近80%，超过90%的组屋居民买下了房子。&lt;br>
有订单才会建新房，售价均低于市场价格，但要等上至少3、4年才能入住，不过低收入家庭也可以获得大量租房补贴。最新数据显示，组屋数量占新加坡住房总量的73%。&lt;br>
&lt;em>摘自BBC：https://www.bbc.com/ukchina/simp/vert-cap-46773103&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>由于新加坡的600百万人口里，有40%是外国人。这些人通常会租房。
这样公屋屋主就很容易将空余的房间出租给外国人，赚取一定的租金。
现在按照市价，一间单间的房间，租金均价在1000新币。如果能把一套三室户整体出租，租金甚至可以高达4000新币。这实在是一笔可观的收入。&lt;/p>
&lt;p>假若退休之后，这对夫妇选择出国定居，比如赴临近的马来西亚或是泰国养老。他们将整套公屋出租。
租金的收入基本上可以让他们在泰国租到一套房，并能覆盖日常的开销。&lt;/p>
&lt;p>既然按照公屋制度，新加坡人可以以相对低廉的价格获得公寓，那必然可以把赚来的工资分配在别的事项上，比如旅游、医疗、教育&amp;hellip;，这样即使新加坡不是
传统意义上的福利国家，仍然可以过着一定有保障的生活。&lt;/p>
&lt;p>当然，新加坡中产阶级普遍生活质量比不上欧美国家，这个话题将在日后撰文讨论。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/is-singapore-a-welfare-state/</guid><pubDate>Sun, 19 May 2024 18:32:22 +0800</pubDate></item><item><title>学习GraphQL</title><link>https://danielsunyu.github.io/myblog-site/posts/learning-graphql/</link><description>&lt;p>GraphQL官方文档：https://graphql.org/&lt;/p>
&lt;p>GraphQL over HTTP: &lt;a href="https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md">https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md&lt;/a>&lt;/p>
&lt;h1 id="the-graphql-first-philosophy">&lt;a href="https://the-guild.dev/graphql/tools/docs/introduction#the-graphql-first-philosophy">The GraphQL-First Philosophy&lt;/a>&lt;/h1>
&lt;blockquote>
&lt;p>A specific workflow for developing a GraphQL server, where the GraphQL schema is the first thing you design, and acts
as the contract between your frontend and backend. It’s not necessarily for everyone, but it can be a great way to get
a server up and running with a very clear separation of concerns.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/learning-graphql/</guid><pubDate>Sat, 11 May 2024 23:23:24 +0800</pubDate></item><item><title>UBS/TCS的最终轮面试</title><link>https://danielsunyu.github.io/myblog-site/posts/tech/3rd-round-interview-with-ubs/</link><description>&lt;ol>
&lt;li>
&lt;p>What&amp;rsquo;s the Java version used in your project?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Have you used any recent version of Java?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>What frontend framework do you use?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Do you use Redux to manage state?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Do you use BDD or TDD for your development?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>How do you configure your project to enable test coverage?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Which directory of your project stores the test configuration?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Elaborate how you carried out your project development?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Does your team use Agile/Scrum?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Solve &lt;a href="https://leetcode.com/problems/kth-largest-element-in-an-array/description/">215. Kth Largest Element in an Array&lt;/a>.&lt;/p>
&lt;/li>
&lt;/ol></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/tech/3rd-round-interview-with-ubs/</guid><pubDate>Thu, 04 Apr 2024 13:43:55 +0800</pubDate></item><item><title>TATA咨询/瑞银的第二轮面试</title><link>https://danielsunyu.github.io/myblog-site/posts/tcs-interview-round2/</link><description>&lt;ol>
&lt;li>
&lt;p>最近的Java版本中引入了哪些变化？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Java中的record是什么？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是Immutable，它有什么好处？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>如何设计一个Immutable类？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Java 8带来了哪些变化？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>谈一下ConcurrentHashMap的实现。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Spring Boot是什么？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>过去用过哪些Spring Boot Starter Dependencies？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是Dependency Injection？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Spring Boot中有哪几种Depedency Injection？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>SOLID Principles中的&lt;strong>L&lt;/strong>是指哪个原则？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Write a function that checks if all elements in an array are odd numbers.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>手写&lt;a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/">Leetcode 121. Best Time to Buy and Sell Stock&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/tcs-interview-round2/</guid><pubDate>Thu, 28 Mar 2024 23:08:33 +0800</pubDate></item><item><title>聊聊Spring WebFlux</title><link>https://danielsunyu.github.io/myblog-site/posts/spring-webflux/</link><description>&lt;p>先来梳理一下关系。&lt;/p>
&lt;h1 id="reactive-streams">Reactive Streams&lt;/h1>
&lt;p>&lt;a href="http://www.reactive-streams.org/">Reactive Streams&lt;/a>是一个规范，定义了处理异步数据流的标准，包括了发布者(Publisher)、订阅者(Subscriber)、订阅(Subscription)、处理
器(Processor)等核心接口和规则。
它为异步编程提供了一个统一的基础，解决了背压(Back Pressure)等问题。&lt;/p>
&lt;p>详细见：https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.4/README.md&lt;/p>
&lt;h1 id="java-9-flow-api">Java 9 Flow API&lt;/h1>
&lt;p>此外，Java 9引入的java.util.concurrent.Flow与Reactive Streams在语义上是1：1等价的。&lt;/p>
&lt;p>&lt;em>JDK9 java.util.concurrent.Flow&lt;/em>&lt;/p>
&lt;blockquote>
&lt;p>The interfaces available in JDK &amp;gt;= 9 java.util.concurrent.Flow, are 1:1 semantically equivalent to their respective
Reactive Streams counterparts. This means that there will be a migratory period, while libraries move to adopt the new
types in the JDK, however this period is expected to be short - due to the full semantic equivalence of the libraries,
as well as the Reactive Streams &amp;lt;-&amp;gt; Flow adapter library as well as a TCK compatible directly with the JDK Flow types.&lt;/p>&lt;/blockquote>
&lt;h1 id="project-reactor">Project Reactor&lt;/h1>
&lt;p>而&lt;a href="https://projectreactor.io/">Project Reactor&lt;/a>则是这个规范的一种具体实现。它提供了Reactive Streams规范接口的不同实现，以及一组符合
规范的操作符，从而让开发者能够方便地进行响应式编程。&lt;/p>
&lt;p>有关Project Reactor的书很少，分享一本免费的&lt;a href="https://eherrera.net/project-reactor-course/">在线电子书&lt;/a>。
&lt;figure>&lt;img src="https://d2sofvawe08yqg.cloudfront.net/unraveling-project-reactor/s_hero2x?1682559252" width="200px" height="360px">&lt;figcaption>
&lt;h4>Unraveling Project Reactor&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;/p>
&lt;h1 id="rxjava">RxJava&lt;/h1>
&lt;p>&lt;a href="https://github.com/ReactiveX/RxJava">RxJava 3&lt;/a>是一个基于观察者模式的Java编程库，用于实现异步、基于事件的程序。作为Reactive Streams规范的实现之一，RxJava 3遵循了
Reactive Streams的接口和协议。&lt;/p>
&lt;h1 id="spring-webflux">Spring WebFlux&lt;/h1></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/spring-webflux/</guid><pubDate>Thu, 28 Mar 2024 13:17:41 +0800</pubDate></item><item><title>Beyond Java8</title><link>https://danielsunyu.github.io/myblog-site/posts/beyond-java8/</link><description>&lt;p>在入职Grab后就开始专注Kotlin，我就没碰过Java了，所以Java 8之后语言的新变化知之甚少。但有点是肯定的，这门语言变得越来越复杂。&lt;/p>
&lt;p>当时我甚至觉得Kotlin这样新的JVM语言优于Java。Java已经不再是一门值得关注的语言。甚至我觉得我以后不太可能用Java了。&lt;/p>
&lt;p>Compiler bugs
All software has bugs, and sometimes the JVM, the Java compiler, or both have bugs. When you are using a 10-year-old version of the JVM and Java compiler, you run a much greater risk of compiler bugs, especially around features introduced near to that release.&lt;/p>
&lt;p>There were many compilation problems around lambdas which were introduced in Java 8. If you are using the Java compiler from JDK 8 to target Java 8 JVMs you can still run into those bugs. Even if you are keeping your JDK 8 up-to-date many fixes are not backported. You can find ones on the issue tracker without much effort.&lt;/p>
&lt;p>Now is the Java compiler in JDK 22 completely bug-free? No. But is using the Java compiler from JDK 22 on sources targeting Java 8 using only Java 8 language features much safer than using one from JDK 8? Absolutely.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/beyond-java8/</guid><pubDate>Mon, 25 Mar 2024 17:43:54 +0800</pubDate></item><item><title>Kotlin书单</title><link>https://danielsunyu.github.io/myblog-site/posts/kotlin-books/</link><description>&lt;p>从2018年开始使用Kotlin至今，Kotlin已经伴随我在大型Android应用和后端的项目中，成为我主要使用的编程语言。&lt;/p>
&lt;p>除了透过Kotlin官网来学习Kotlin外，以下是我整理的优秀的Kotlin书单。&lt;/p>
&lt;h1 id="第一本入门书">第一本入门书&lt;/h1>
&lt;p>这是一本极佳的入门书。我正是读了它的第一版入门Kotlin的。&lt;a href="https://bignerdranch.com/books/kotlin-programming-the-big-nerd-ranch-guide-2nd/">Kotlin Programming The Big Nerd Ranch Guide, 2nd Edition&lt;/a>&lt;/p>
&lt;figure>&lt;img src="https://bignerdranch.com/wp-content/uploads/2021/09/BNR_Kotlin_2E_mech-110241024_1.jpg" width="300px" height="480px">
&lt;/figure>
&lt;p>本书出版于2021年底，覆盖了Kotlin 1.5。由于已经有三年，并且Kotlin 2.0也已经发布，我认为大约在2025年会出版该书的第三版。&lt;/p>
&lt;p>读了它的第20章Coroutine，觉得信息量很大。不重复读几遍很难读懂。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/kotlin-books/</guid><pubDate>Fri, 22 Mar 2024 18:54:58 +0800</pubDate></item><item><title>阅读「Web 3大趋势」</title><link>https://danielsunyu.github.io/myblog-site/posts/reading-web3-big-trend/</link><description>&lt;figure>&lt;img src="https://danielsunyu.github.io/myblog-site/images/web3_book.jpg" width="200px" height="360px">
&lt;/figure>
&lt;p>&lt;a href="https://readmoo.com/book/210284743000101" target="_blank">本书&lt;/a>的副标题是——日本网路教父教你一次看懂元宇宙、区块链、NFT。本书的作者是伊藤穰一。&lt;/p>
&lt;p>本书以&lt;strong>Web 3&lt;/strong>、&lt;strong>元宇宙&lt;/strong>和&lt;strong>NFT&lt;/strong>作为最重要的三个关键字。&lt;/p>
&lt;p>伊藤给出了他认为最适合的&lt;strong>元宇宙&lt;/strong>的定义——以网路即时沟通为前提，进行某种价值交换的空间。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/reading-web3-big-trend/</guid><pubDate>Thu, 21 Mar 2024 19:13:53 +0800</pubDate></item><item><title>零成本开DBS账户 - My Account</title><link>https://danielsunyu.github.io/myblog-site/posts/open-my-account-in-dbs/</link><description>&lt;p>我一直以为，开通DBS账户需要维持3000新币的最低存款要求，否则会被收取每月5新币的账户管理费。&lt;/p>
&lt;p>这也是为何我去年关闭了我的Multiplier Account。我认为为了拥有DBS账户而维持3000新币划不来。毕竟在高利率时代，3000新币一年能带来100新币的利息。相当于为了持有账户会让我每月损失8新币。&lt;/p>
&lt;p>因为我的Moomoo和Tiger证券账户有美元和港币想要出金，只有DBS是对外币免手续费。主要的原因是Moomoo和Tiger的银行账户是在DBS托管的。&lt;/p>
&lt;p>我本来是打算重新开DBS账户，并存入3000新币。在与DBS的工作人员交涉时，他解释了为何Multiplier Account要维持最低3000元的活期存款。因为只要credit your salaries，这个账户的活期存款有可观的利息收入的。他推荐我（重新）开通这个账户。&lt;/p>
&lt;p>此外，他也提到有一种活期账户（current account）类型叫&lt;strong>My Account&lt;/strong>，且支持&lt;strong>多种货币&lt;/strong>。我欣喜地发现，这个账户没有最低存款要求。他解释道：&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>This account caters to people who can&amp;rsquo;t manage to deposit even hundreds of dollars.&lt;/em>&lt;/p>&lt;/blockquote>
&lt;p>于是，我开了My Account账户，只存入了50新币，并成功把Tiger上的港币出金到这个账户上，没有收取手续费。&lt;/p>
&lt;p>虽然不知道其他新加坡银行的情况，但我相信也是有这种没有最低存款要求的账户的。&lt;/p>
&lt;p>我会持续更新我的博文，让大家能够以最低成本持有银行账户。&lt;/p>
&lt;p>&lt;em>请我喝杯咖啡吧！&lt;/em>&lt;/p>
&lt;p>&lt;a href="https://www.buymeacoffee.com/danielsun">&lt;img src="https://tinyurl.com/57dkxa4f" width="120"/>&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/open-my-account-in-dbs/</guid><pubDate>Thu, 21 Mar 2024 13:15:23 +0800</pubDate></item><item><title>新加坡交易所上值得买入的ETFs</title><link>https://danielsunyu.github.io/myblog-site/posts/etfs-listed-on-sg-stock-exchange/</link><description>&lt;p>第一个是追踪&lt;a href="https://en.wikipedia.org/wiki/Straits_Times_Index">新加坡海峡时报指数&lt;/a>的一款&lt;a href="https://www.ssga.com/sg/en/institutional/etfs/funds/spdr-straits-times-index-etf-es3">SPDR® Straits Times Index ETF&lt;/a>；&lt;/p>
&lt;p>证券代号：ES3&lt;/p>
&lt;p>管理费：0.26%（年）&lt;/p>
&lt;p>交易货币：SGD&lt;/p>
&lt;p>挂牌日： 2002年4月17日&lt;/p>
&lt;p>规模：15亿新币&lt;/p>
&lt;p>派息率：4.60%&lt;/p>
&lt;p>派息日：每年的2月和8月&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/etfs-listed-on-sg-stock-exchange/</guid><pubDate>Mon, 18 Mar 2024 14:40:06 +0800</pubDate></item><item><title>塔塔咨询服务的Java后端面试记录</title><link>https://danielsunyu.github.io/myblog-site/posts/an-interview-with-tcs/</link><description>&lt;p>最近面了一家叫&lt;a href="https://www.tcs.com/">Tata Consultancy Services&lt;/a>的咨询公司，面试的岗位是Java后端工程师。&lt;/p>
&lt;p>这家国际(印度)咨询公司有许多的客户。我猜这个岗位的客户是UBS。&lt;/p>
&lt;p>面试进行了35分钟左右。这里记录一下面试题。&lt;/p>
&lt;p>面试题围绕着Java、Spring Boot和Microservices展开。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Java 8（2014年3月发布的）带来了哪些新功能？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Java接口的default methods有啥作用；Java 8为何要加入这个特性？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是Functional Interfaces？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Java 8中的HashMap有啥改变？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>解释下Immutability/Immutable？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>如何设计一个Immutable类？比如一个Employee类。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>有一组Employee，每个Employee属于某个Department的集合，如何用Java Stream API找出属于IT Department的所有Employee？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Spring Boot为Spring framework带来了哪些新特性？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>解释一下@SpringBootApplication的作用。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>解释一下@RestController的作用。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>谈一下Spring Data JPA。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Spring Boot应用如何做Health Check？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>微服务中的&lt;a href="https://microservices.io/patterns/reliability/circuit-breaker.html">Circuit Breaker&lt;/a>是做什么的？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>微服务彼此之间是如何通信的？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>如何设计一个OpenFeign的类？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是&lt;a href="https://simple.wikipedia.org/wiki/SOLID_(object-oriented_design)">Solid Principles&lt;/a>？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是&lt;a href="https://12factor.net/">Twelve-Factor App&lt;/a>？&lt;/p>
&lt;/li>
&lt;/ol></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/an-interview-with-tcs/</guid><pubDate>Fri, 15 Mar 2024 18:35:12 +0800</pubDate></item><item><title>「Spring Security in Action」读书笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/reading-spring-security-in-action/</link><description>&lt;p>Java专家Laurentiu Spilca于2020年出版了「Spring Security in Action」一书。&lt;/p>
&lt;p>这本书以Spring Boot v2.3.0和Java 11版本为基础。&lt;/p>
&lt;p>根据Manning Publications官方和Amazon上的讯息，他将于2024年4月出版本书第二版。&lt;/p>
&lt;figure>&lt;img src="https://images.manning.com/360/480/resize/book/6/e751b54-0e51-4676-b05f-c0f023d152b9/Spilca-Spring-HI.png" width="300px" height="480px">&lt;figcaption>
&lt;h4>Spring Security in Action&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>虽然我没有第二版的书，但是读一下2020年版的应该不会太过时。&lt;/p>
&lt;p>这篇博文记录书中的摘录、我的笔记和感想。&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Spring Security&lt;/strong> is a framework that belongs to &lt;strong>application-level security&lt;/strong>.&lt;/em>&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Application-level security&lt;/strong> refers to everything that an application should do to protect the environment it executes in, as well as the data it processes and stores. Mind that this isn’t only about the data affected and used by the application. An application might contain vulnerabilities that allow a malicious individual to affect the entire system!&lt;/em>&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>Through &lt;strong>authentication&lt;/strong>, an application identifies a user (a person or another application). The purpose of identifying these is to be able to decide afterward what they should be allowed to do—that’s &lt;strong>authorization&lt;/strong>.&lt;/em>&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/reading-spring-security-in-action/</guid><pubDate>Thu, 14 Mar 2024 14:27:10 +0800</pubDate></item><item><title>「Spring Start Here」读书笔记📒</title><link>https://danielsunyu.github.io/myblog-site/posts/reading-spring-start-here/</link><description>&lt;p>这本书是我见过质量最好的Spring入门书籍，真的是没有之一，我花了整整两周读完。但是价格要$49.99，真是不便宜啊。&lt;/p>
&lt;p>一直很稀奇，为何Spring这个流行的框架，社区中没有产出香Rails Tutorials那么高质量的入门实作读物。&lt;/p>
&lt;p>此外，作者有些书目的推荐。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">@RestController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">HelloController&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">@GetMapping&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;/hello&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#75af00">hello&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#d88200">&amp;#34;Hello!&amp;#34;&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>@RestController&lt;/code> annotation registers the bean in the context and tells Spring that the application uses this instance as a web controller.&lt;/p>
&lt;h1 id="微服务">微服务&lt;/h1>
&lt;blockquote>
&lt;p>Software architecture and its evolution is such a fantastic and complex subject. I don’t think there’ll ever be too many books to cover this subject thoroughly. I’ve added this discussion to the book to help you understand the references I’ll make to these notions. Still, you might want to go deeper into the subjects, so here’s a list of books from my shelf. The books are in the order I recommend you read them.&lt;/p>&lt;/blockquote>
&lt;ol>
&lt;li>Microservices in Action&lt;/li>
&lt;li>Microservices Patterns&lt;/li>
&lt;li>Spring Microservices in Action&lt;/li>
&lt;li>Microservices Security in Action&lt;/li>
&lt;li>Monolith to Microservices&lt;/li>
&lt;/ol></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/reading-spring-start-here/</guid><pubDate>Tue, 12 Mar 2024 13:14:33 +0800</pubDate></item><item><title>Hands on Learning Postgresql</title><link>https://danielsunyu.github.io/myblog-site/posts/hands-on-learning-postgresql/</link><description>&lt;p>这是记录我学习的Open Full Stack上的一门小课程&lt;a href="https://fullstackopen.com/en/part13">&lt;strong>Part 13 - Using relational databases&lt;/strong>&lt;/a>。&lt;/p>
&lt;p>这本课程是用&lt;a href="https://www.postgresql.org/">&lt;strong>PostgreSQL&lt;/strong>&lt;/a>。&lt;/p>
&lt;p>类似Mongoose，这门课程用到了&lt;a href="https://sequelize.org/">&lt;strong>Sequelize&lt;/strong>&lt;/a>。官网的描述是：&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Sequelize&lt;/strong> is a modern TypeScript and Node.js ORM for Oracle, Postgres, MySQL, MariaDB, SQLite and SQL Server, and more. Featuring solid transaction support, relations, eager and lazy loading, read replication and more.&lt;/em>&lt;/p>&lt;/blockquote>
&lt;figure>&lt;img src="https://sequelize.org/img/logo.svg" width="200px" height="360px">&lt;figcaption>
&lt;h4>Spring Security in Action&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>这里首先讲到之前课程用到的MongoDB。&lt;/p>
&lt;blockquote>
&lt;p>Mongo is a document database and one of its most characteristic features is that it is schemaless, i.e. the database has only a very limited awareness of what kind of data is stored in its collections. The schema of the database exists only in the program code, which interprets the data in a specific way, e.g. by identifying that some of the fields are references to objects in another collection.&lt;/p>&lt;/blockquote>
&lt;p>The &lt;code>\d&lt;/code> command, which tells us what tables are in the database.&lt;/p>
&lt;pre tabindex="0">&lt;code>postgres=# \d
List of relations
Schema | Name | Type | Owner
--------+--------------+----------+----------
public | notes | table | username
public | notes_id_seq | sequence | username
(2 rows)
&lt;/code>&lt;/pre>&lt;p>With the command &lt;code>\d&lt;/code> notes, we can see how the notes table is defined:&lt;/p>
&lt;pre tabindex="0">&lt;code>postgres=# \d notes
Table &amp;#34;public.notes&amp;#34;
Column | Type | Collation | Nullable | Default
-----------+------------------------+-----------+----------+-----------------------------------
id | integer | | not null | nextval(&amp;#39;notes_id_seq&amp;#39;::regclass)
content | text | | not null |
important | boolean | | |
date | time without time zone | | |
Indexes:
&amp;#34;notes_pkey&amp;#34; PRIMARY KEY, btree (id)
&lt;/code>&lt;/pre>&lt;blockquote>
&lt;p>&lt;em>In practice, a &lt;em>migration&lt;/em> is a single JavaScript file that describes some modification to a database. A separate migration file is created for each single or multiple changes at once.&lt;/em>&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/hands-on-learning-postgresql/</guid><pubDate>Mon, 11 Mar 2024 21:22:44 +0800</pubDate></item><item><title>「Redis for Dummies」第二版读书摘要</title><link>https://danielsunyu.github.io/myblog-site/posts/reading-redis-for-dummies-2nd/</link><description>&lt;p>&lt;strong>Redis&lt;/strong> is a popular multi-model database server.&lt;/p>
&lt;p>NoSQL数据库有四个主要的类型：key/value、column、document和graph。&lt;/p>
&lt;p>有两个易混淆的术语：&lt;/p>
&lt;p>&lt;strong>Data Store&lt;/strong>是专门的数据库系统，提供高效的数据组织和访问能力。&lt;/p>
&lt;p>&lt;strong>Data Storage&lt;/strong>是通用的数据存储介质和设备，为Data Store等上层系统提供存储容量。&lt;/p>
&lt;p>&lt;strong>Durability&lt;/strong> is the ability to ensure that data is available in the event of a failure of a database component.&lt;/p>
&lt;h1 id="第三章">第三章&lt;/h1>
&lt;blockquote>
&lt;p>There is no formal database creation step with Redis. There isn’t a formal table creation step with Redis either. The SET command is used to create data within the current database.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Those familiar with formalized database creation and definition may be uncomfortable with the seemingly informal process of Redis database creation and data handling. However, it’s through this flexibility that the true power of Redis is found.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/reading-redis-for-dummies-2nd/</guid><pubDate>Mon, 11 Mar 2024 17:30:24 +0800</pubDate></item><item><title>学习Redis</title><link>https://danielsunyu.github.io/myblog-site/posts/learning-redis/</link><description>&lt;p>最近打算系统地学习Redis。想花最少的时间快速地入门Redis。尝试在网上搜些优质的资源，结果发现好的不多，整理如下：&lt;/p>
&lt;h1 id="好书">好书&lt;/h1>
&lt;p>第一本书是&lt;a href="https://redis.com/redis-for-dummies/">「Redis for Dummies」&lt;/a>第二版，可以从&lt;a href="https://redis.com/">redis.com&lt;/a>官网免费下载。&lt;/p>
&lt;figure>&lt;img src="https://m.media-amazon.com/images/I/419SUZus&amp;#43;4L.jpg" width="300px" height="480px">&lt;figcaption>
&lt;h4>Redis for Dummies&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>我会把读书的笔记整理到一篇博文中。&lt;/p>
&lt;p>第二本叫&lt;a href="https://www.manning.com/books/redis-in-action">「Redis in Action」&lt;/a>,2013年出版的。这本书居然直到如今都没有更新，可能因为内容并没有过时。&lt;/p>
&lt;figure>&lt;img src="https://images.manning.com/360/480/resize/book/8/00f2522-76ce-4594-8564-541254e6d8f0/carlson.png" width="300px" height="480px">&lt;figcaption>
&lt;h4>Redis in Action&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>配套的源码放在&lt;a href="https://github.com/josiahcarlson/redis-in-action/">GitHub&lt;/a>，并有多种语言的实现。&lt;/p>
&lt;h1 id="redis云服务提供商">Redis云服务提供商&lt;/h1>
&lt;p>介绍一个叫&lt;a href="https://redis.com/cloud/overview/">Redis Cloud&lt;/a>的云产品。可以免费试用30天来创建一个数据库，用来学习是足够了。最基本的套餐也只要5美元/月。推荐使用这个云环境使用起来非常方便。我是懒得在本地安装、配置一个Redis实例了。&lt;/p>
&lt;h1 id="工具">工具&lt;/h1>
&lt;p>推荐从Redis官网下载一款叫&lt;a href="https://redis.com/redis-enterprise/redis-insight/">RedisInsight&lt;/a>的GUI工具。可以直接连接一个本地或是远程的多个Redis实例。&lt;/p>
&lt;figure>&lt;img src="https://redis.com/wp-content/uploads/2022/11/redisinsight-dashboard-illustration-2.svg?&amp;amp;auto=webp&amp;amp;quality=85,75&amp;amp;width=600" width="600px">&lt;figcaption>
&lt;h4>RedisInsight&lt;/h4>
&lt;/figcaption>
&lt;/figure>
&lt;p>此外，黑马程序员的Redis课程也不错。&lt;/p>
&lt;h1 id="认证考试">认证考试&lt;/h1>
&lt;p>没想到Redis生态真是健全，还有&lt;a href="https://university.redis.com/certification/">认证考试&lt;/a>，不知道含金量如何。&lt;/p>
&lt;p>Claude AI给我我如下的回复：&lt;/p>
&lt;blockquote>
&lt;p>Redis Certification考试的费用和考试方式情况如下:
Redis认证考试分为两个级别:Redis Certified Developer（149美元）和Redis Certified Data
Persistence Specialist（249美元）。&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/learning-redis/</guid><pubDate>Sun, 10 Mar 2024 20:52:43 +0800</pubDate></item><item><title>Introduction to JDBC</title><link>https://danielsunyu.github.io/myblog-site/posts/jdbc/</link><description>&lt;p>This document illustrates the basics of the JDBC (Java Database Connectivity) API (Application Program Interface). Here, you will learn to use the basic JDBC API to create tables, insert values, query tables, retrieve results, update tables, create prepared statements, perform transactions on a database system from a Java program.&lt;/p>
&lt;p>This document draws from the official Sun tutorial on JDBC Basics.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/jdbc/</guid><pubDate>Thu, 22 Feb 2024 19:12:29 +0800</pubDate></item><item><title>Head First SQL的精要</title><link>https://danielsunyu.github.io/myblog-site/posts/head_first_sql_gist/</link><description>&lt;p>这是一本很好的SQL入门书。&lt;/p>
&lt;p>很好的SQL练习题：https://leetcode.com/studyplan/top-sql-50/&lt;/p>
&lt;p>第一章&lt;/p>
&lt;p>SQL is case-insensitive. But it&amp;rsquo;s considered a good programming practice in SQL.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">CREATE&lt;/span> &lt;span style="color:#00a8c8">DATABASE&lt;/span> &lt;span style="color:#111">gregs_list&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;strong>semicolon&lt;/strong> is there to indicate that the command has ended.&lt;/p>
&lt;p>&lt;strong>TIMESTAMP&lt;/strong> is usually used to capture the current time. &lt;strong>DATETIME&lt;/strong> is best used to store a future event.&lt;/p>
&lt;h1 id="desc命令">DESC命令&lt;/h1>
&lt;p>To see how &lt;em>my_contacts&lt;/em> table you created looks, you can use the &lt;strong>DESC&lt;/strong> command to view it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">DESC&lt;/span> &lt;span style="color:#111">my_contacts&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>DESC&lt;/strong> is short for &lt;em>DESCRIBE&lt;/em>.&lt;/p>
&lt;h1 id="insert语句">INSERT语句&lt;/h1>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">INSERT&lt;/span> &lt;span style="color:#00a8c8">INTO&lt;/span> &lt;span style="color:#111">your_table&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">column_name1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">column_name2&lt;/span>&lt;span style="color:#111">,...)&lt;/span> &lt;span style="color:#00a8c8">VALUES&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#39;value1&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;value2&amp;#39;&lt;/span>&lt;span style="color:#111">,...);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>IMPORTANT: the values need to be in the same order as the column names.&lt;/p>
&lt;p>Any value that goes into a VARCHAR, CHAR, DATE, or BLOB column has single quotes around it.&lt;/p>
&lt;p>NULL相当于undefined。&lt;/p>
&lt;blockquote>
&lt;p>You can’t compare one NULL to another. A value can be NULL, but it never equals NULL because NULL is an undefined value!&lt;/p>&lt;/blockquote>
&lt;h1 id="第四章">第四章&lt;/h1>
&lt;p>&lt;strong>LIKE&lt;/strong> isn’t specific enough to target precise data.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;hellip; consider how much room on your hard drive it will take up when your database grows to an enormous size.&lt;/em>&lt;/p>&lt;/blockquote>
&lt;h1 id="cartesian-join亦称cross-join或cartesian-product">Cartesian join（亦称Cross join或Cartesian product）&lt;/h1>
&lt;p>A Cartesian join is a type of inner join. An inner join is basically just a Cartesian join where some results rows are removed by a condition in the query.&lt;/p>
&lt;p>An &lt;b>outer joins&lt;/b> returns all rows from one of the tables, along with matching information from another table.&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/head_first_sql_gist/</guid><pubDate>Sat, 17 Feb 2024 22:30:10 +0800</pubDate></item><item><title>Spring的容器中获取Bean</title><link>https://danielsunyu.github.io/myblog-site/posts/spring-bean-management/</link><description>&lt;p>默认情况下，Spring项目启动时，会把Beans都创建好放在IOC容器中。如果想要主动获取这些Beans，可以通过如下方式：&lt;/p>
&lt;h2 id="根据name获取bean">根据name获取Bean&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">Object&lt;/span> &lt;span style="color:#75af00">getBean&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="根据类型获取bean">根据类型获取Bean&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">T&lt;/span> &lt;span style="color:#75af00">getBean&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Class&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">requiredType&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="根据name获取bean带类型转换">根据name获取Bean（带类型转换）&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">T&lt;/span> &lt;span style="color:#75af00">getBean&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Class&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">requiredType&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/spring-bean-management/</guid><pubDate>Wed, 14 Feb 2024 12:40:18 +0800</pubDate></item><item><title>在中国，使用npm需要替换registry</title><link>https://danielsunyu.github.io/myblog-site/posts/switch-npm-registry-in-china/</link><description>&lt;p>是在国外开始把玩Node.js，回国后发现npm install速度很慢&amp;hellip;&lt;/p>
&lt;p>这又是一个解决别的制度不存在的问题…&lt;/p>
&lt;p>总之，npm默认的registry是 &lt;a href="https://registry.npmjs.org">https://registry.npmjs.org&lt;/a> 。可是在中国，这个源似乎访问速度很慢。&lt;/p>
&lt;pre tabindex="0">&lt;code>npm config get registry
&lt;/code>&lt;/pre>&lt;p>可以返回当前源设置&lt;/p>
&lt;p>设置淘宝源：&lt;/p>
&lt;pre tabindex="0">&lt;code>npm config set registry https://registry.npmmirror.com
&lt;/code>&lt;/pre></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/switch-npm-registry-in-china/</guid><pubDate>Tue, 02 Jan 2024 21:10:24 +0800</pubDate></item><item><title>JavaScript怪癖</title><link>https://danielsunyu.github.io/myblog-site/posts/javascript-quirks/</link><description>&lt;h3 id="1-javascript里的空指针异常其实是一种typeerror">1. &lt;code>JavaScript&lt;/code>里的空指针异常其实是一种&lt;code>TypeError&lt;/code>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">null&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">toString&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>回显&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-textmate" data-lang="textmate">&amp;#34;TypeError: Cannot read property &amp;#39;toString&amp;#39; of null&amp;#34;
&lt;/code>&lt;/pre></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/javascript-quirks/</guid><pubDate>Fri, 15 Apr 2022 21:52:20 +0800</pubDate></item><item><title>超有用的Flutter命令行</title><link>https://danielsunyu.github.io/myblog-site/posts/useful-flutter-commands/</link><description>&lt;h2 id="自动生成的代码">自动生成的代码&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>flutter packages pub run build_runner build --delete-conflicting-outputs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="获取依赖">获取依赖&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>flutter pub get
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="静态分析">静态分析&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>flutter analyze
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="格式化">格式化&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>flutter format -n --set-exit-if-changed path/to/project --line-length &lt;span style="color:#ae81ff">140&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/useful-flutter-commands/</guid><pubDate>Thu, 14 Apr 2022 13:51:33 +0800</pubDate></item><item><title>用命令行在iOS模拟器上打开Deeplink</title><link>https://danielsunyu.github.io/myblog-site/posts/launch-deeplink-on-ios-simulator/</link><description>&lt;p>比想象中简单，只需要打开Terminal输入如下咒语：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>xcrun simctl openurl booted &lt;span style="color:#d88200">&amp;#34;some url&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/launch-deeplink-on-ios-simulator/</guid><pubDate>Mon, 04 Apr 2022 14:55:32 +0800</pubDate></item><item><title>在Big Sur上安装Ruby的经历</title><link>https://danielsunyu.github.io/myblog-site/posts/install-ruby-on-mac/</link><description>&lt;p>&lt;strong>TL;DR&lt;/strong>: macOS Big Sur貌似对安装Ruby不太友好。不推荐&lt;code>rvm&lt;/code>；推荐&lt;code>rbenv&lt;/code>&amp;hellip;&lt;/p>
&lt;p>我是在macOS Big Sur上安装Ruby的，从来没有那么折腾过，花费了大半天时间。最后虽然安装成功，但却有很多点值得记录。
这是是要安装&lt;code>2.7.5&lt;/code>版本，LTS版本。输入&lt;code>ruby -v&lt;/code>后会发现Mac是自带Ruby的，只是版本滞后，满足不了灵活需要。&lt;/p>
&lt;p>最好不要直接安装Ruby，而是通过Ruby版本管理工具。&lt;/p>
&lt;h2 id="藉rvm安装ruby">藉rvm安装Ruby&lt;/h2>
&lt;p>首先尝试安装&lt;a href="https://rvm.io/">rvm&lt;/a>，用rvm管理不同的本地Ruby版本应该很简单，然而却不然。rvm很容易安装，但要手动设置环境变量。
具体步骤可以参考RVM官网。&lt;/p>
&lt;p>YouTube上有个很好的&lt;a href="https://www.youtube.com/watch?v=SL64tWlpwSE">视频讲解&lt;/a>&lt;/p>
&lt;p>安装某个Ruby版本只要&lt;code>rvm install 2.7.5&lt;/code>；安装后设置成默认是用&lt;code>rvm --default use 2.7.5 &lt;/code>，但是却报错。&lt;/p>
&lt;h2 id="藉rbenv安装ruby">藉rbenv安装Ruby&lt;/h2>
&lt;p>rbenv似乎没有官方主页，只有&lt;a href="https://github.com/rbenv/rbenv#installing-ruby-versions">Github项目地址&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>brew install rbenv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>rbenv install 2.7.5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这条命令居然也失败了&amp;hellip;&lt;/p>
&lt;p>参考了&lt;a href="https://gist.github.com/Neutrollized/37841827940b28b27ec2e54abbbcc408">这篇Github Gist&lt;/a>，找到了解决方法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">RUBY_CONFIGURE_OPTS&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;--with-openssl-dir=&lt;/span>&lt;span style="color:#00a8c8">$(&lt;/span>brew --prefix openssl@1.1&lt;span style="color:#00a8c8">)&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span> &lt;span style="color:#111">RUBY_CFLAGS&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;-w&amp;#34;&lt;/span> rbenv install 2.7.5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>rbenv global 2.7.5
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关闭Terminal后，&lt;code>ruby -v&lt;/code>还是输出老版本，设置一下环境变量&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">export&lt;/span> &lt;span style="color:#111">PATH&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">$HOME&lt;/span>&lt;span style="color:#d88200">/.rbenv/bin:&lt;/span>&lt;span style="color:#111">$PATH&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">eval&lt;/span> &lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#00a8c8">$(&lt;/span>rbenv init -&lt;span style="color:#00a8c8">)&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/install-ruby-on-mac/</guid><pubDate>Fri, 01 Apr 2022 18:19:07 +0800</pubDate></item><item><title>Stack in Java</title><link>https://danielsunyu.github.io/myblog-site/posts/stack-in-java/</link><description>&lt;p>##前言
堆栈作为最基础的数据结构之一，在Java的最初版本就有了纯粹的标准实现：&lt;code>java.util.Stack&lt;/code>。只可惜该实现存在性能缺陷，主要是由于主要的操作都加上了synchronized线程安全保护机制，导致无法被应用于对性能要求颇高的生产环境。&lt;/p>
&lt;blockquote>
&lt;p>A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class. For example: Deque&lt;Integer> stack = new ArrayDeque&lt;Integer>();&lt;/p>&lt;/blockquote>
&lt;p>在Java Collections类发布后就和&lt;code>java.util.Vector&lt;/code>类被一起被废弃了，取代之的是&lt;code>java.util.Deque&lt;/code>接口。之所以设计成接口，是不想与某一个&lt;code>Deque&lt;/code>的实现绑定。Java提供了&lt;code>LinkedList&lt;/code>和&lt;code>ArrayDeque&lt;/code>即可按照使用场景不同，采纳基于数组或是链表的&lt;code>Deque&lt;/code>实现，提供了灵活性。&lt;/p>
&lt;blockquote>
&lt;p>Deques can also be used as LIFO (Last-In-First-Out) stacks. This interface should be used in preference to the legacy Stack class. When a deque is used as a stack, elements are pushed and popped from the beginning of the deque.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/stack-in-java/</guid><pubDate>Sun, 02 Sep 2018 20:17:01 +0800</pubDate></item><item><title>how to maintain octopress</title><link>https://danielsunyu.github.io/myblog-site/posts/how-to-maintain-octopress/</link><description>&lt;p>&lt;a href="https://www.didiksetiawan.com/blog/2016/06/02/octopress-setup-and-deployment/">https://www.didiksetiawan.com/blog/2016/06/02/octopress-setup-and-deployment/&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/how-to-maintain-octopress/</guid><pubDate>Sat, 01 Sep 2018 19:19:01 +0800</pubDate></item><item><title>top k algorithms</title><link>https://danielsunyu.github.io/myblog-site/posts/top-k-algorithms/</link><description>&lt;p>##背景&lt;/p>
&lt;p>去年面试Facebook时，被问到了一道Top K的问题，这类的问题解法往往具有共通性。今天在LeetCode上又遇到了一道&lt;a href="https://leetcode.com/problems/top-k-frequent-words/description/">类似的问题&lt;/a>，于是网上搜了一下&lt;a href="https://www.programcreek.com/2014/05/leetcode-top-k-frequent-elements-java/">解题思路&lt;/a>，摘录留下备用。&lt;/p>
&lt;p>JDK里有一个强大的集合类 &amp;ndash; &lt;em>PriorityQueue&lt;/em>，掌握了它的用法便能迎刃而解这类问题。&lt;/p>
&lt;p>值得注意的是&lt;em>PriorityQueue&lt;/em>没有继承自&lt;em>List&lt;/em>，不具有随机访问第i个元素的方法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">E&lt;/span> &lt;span style="color:#75af00">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">index&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Given a non-empty array of integers, return the k most frequent elements.&lt;/p>&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">Pair&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">count&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Pair&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">count&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">this&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">num&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">this&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">count&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">count&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">Solution&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#111">List&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#75af00">topKFrequent&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span>&lt;span style="color:#f92672">[]&lt;/span> &lt;span style="color:#111">nums&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//count the frequency for each element&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">HashMap&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">map&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">HashMap&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">nums&lt;/span>&lt;span style="color:#111">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">containsKey&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">))&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">put&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#111">1&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">put&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">num&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">1&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// create a min heap&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">PriorityQueue&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Pair&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">queue&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">PriorityQueue&lt;/span>&lt;span style="color:#f92672">&amp;lt;&amp;gt;&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">Comparator&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Pair&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#75af00">compare&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Pair&lt;/span> &lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Pair&lt;/span> &lt;span style="color:#111">b&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">count&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#111">b&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">count&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//maintain a heap of size k.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">Entry&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">entry&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">entrySet&lt;/span>&lt;span style="color:#111">())&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Pair&lt;/span> &lt;span style="color:#111">p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">Pair&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">entry&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">getKey&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#111">entry&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">getValue&lt;/span>&lt;span style="color:#111">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">queue&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">offer&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">queue&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">size&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">queue&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">poll&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//get all elements from the heap&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">List&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">ArrayList&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">while&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">queue&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">size&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">0&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">add&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">queue&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">poll&lt;/span>&lt;span style="color:#111">().&lt;/span>&lt;span style="color:#75af00">num&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//reverse the order&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Collections&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">reverse&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/top-k-algorithms/</guid><pubDate>Sat, 01 Sep 2018 18:46:00 +0800</pubDate></item><item><title>Java Concurrency</title><link>https://danielsunyu.github.io/myblog-site/posts/java-concurrency/</link><description>&lt;h2 id="为何要同步线程">为何要同步线程？&lt;/h2>
&lt;blockquote>
&lt;p>Since all threads run in the same address space, they all have access to the same data and variables. If two threads simultaneously attempt to update a global counter variable, it is possible for their operations to interleave in such way that the global state is not correctly modified. Although such a case may only arise only one time out of thousands, a concurrent program needs to coordinate the activities of multiple threads using something more reliable that just depending on the fact that such interference is rare.&lt;/p>&lt;/blockquote>
&lt;p>&lt;code>Executor&lt;/code>: An object that executes submitted &lt;code>Runnable&lt;/code> tasks. &lt;br>
&lt;code>ExecutorService&lt;/code>: A more extensive interface. &lt;br>
&lt;code>ThreadPoolExecutor&lt;/code>: Provides an extensible thread pool implementation. &lt;br>
&lt;code>Executors&lt;/code>: Provides convenient factory methods for these Executors.&lt;/p>
&lt;p>&lt;code>AbstractExecutorService&lt;/code>: Provides default implementations of ExecutorService execution methods. &lt;br>
&lt;code>ScheduledExecutorService&lt;/code>: An ExecutorService that can schedule commands to run after a given delay, or to execute periodically.&lt;/p>
&lt;h2 id="executorservice的生命周期">&lt;code>ExecutorService&lt;/code>的生命周期&lt;/h2>
&lt;ul>
&lt;li>Active&lt;/li>
&lt;li>Shutting Down&lt;/li>
&lt;li>Shutdown&lt;/li>
&lt;/ul>
&lt;h2 id="synchronizers-synchronization-aids">Synchronizers (synchronization aids)&lt;/h2>
&lt;ul>
&lt;li>CyclicBarrier循环屏障: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.&lt;/li>
&lt;li>Phaser&lt;/li>
&lt;li>CountDownLatch: 当counter为1时为被用作start signal，为N时为complete signal。&lt;/li>
&lt;li>Exchanger&lt;/li>
&lt;li>Semaphore&lt;/li>
&lt;li>SynchronousQueue&lt;/li>
&lt;/ul>
&lt;h2 id="potential-threading-problems">Potential threading problems&lt;/h2>
&lt;ul>
&lt;li>Deadlock&lt;/li>
&lt;li>Starvation&lt;/li>
&lt;li>Livelock&lt;/li>
&lt;li>Race conditions&lt;/li>
&lt;/ul>
&lt;h2 id="concurrent-collections">Concurrent Collections&lt;/h2></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-concurrency/</guid><pubDate>Mon, 16 Jul 2018 12:28:47 +0700</pubDate></item><item><title>缅甸旅游签证轻松办</title><link>https://danielsunyu.github.io/myblog-site/posts/apply-for-myammar-visa-the-easy-way/</link><description>&lt;p>从没想到缅甸签证原来那么好办，当然我指的是电子签证。&lt;/p>
&lt;p>&lt;a href="https://evisa.moip.gov.mm/index.aspx">网办缅甸签证的官网&lt;/a>&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/apply-for-myammar-visa-the-easy-way/</guid><pubDate>Fri, 29 Jun 2018 22:36:17 +0700</pubDate></item><item><title>Java中的assert断言</title><link>https://danielsunyu.github.io/myblog-site/posts/java-assertions/</link><description>&lt;p>使用Java已经有了10个年头，难以想象居然很少使用assert关键字。&lt;/p>
&lt;p>&lt;a href="https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html">Oracle官方指南&lt;/a>中详细介绍了assert的用法。&lt;/p>
&lt;!-- more -->
&lt;blockquote>
&lt;p>An assertion is a statement in the Java programming language that enables you to test your assumptions about your program. For example, if you write a method that calculates the speed of a particle, you might assert that the calculated speed is less than the speed of light.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Each assertion contains a boolean expression that you believe will be true when the assertion executes. If it is not true, the system will throw an error. By verifying that the boolean expression is indeed true, the assertion confirms your assumptions about the behavior of your program, increasing your confidence that the program is free of errors.&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>Experience has shown that writing assertions while programming is one of the quickest and most effective ways to detect and correct bugs. As an added benefit, assertions serve to document the inner workings of your program, enhancing maintainability.&lt;/p>&lt;/blockquote></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-assertions/</guid><pubDate>Fri, 29 Jun 2018 15:52:18 +0700</pubDate></item><item><title>David Pawson《箴言》第一部观感</title><link>https://danielsunyu.github.io/myblog-site/posts/david-pawson-provert-part1/</link><description>&lt;p>箴言这卷书一共有九百条箴言，涵盖人生各个层面，涵盖各种主题。&lt;/p>
&lt;p>圣经上没有世俗这个词，我们不应该使用。&lt;/p>
&lt;p>希腊思想才会把生活划分成神圣和世俗。&lt;/p>
&lt;p>圣经里的智慧和愚昧都不是指智力，而是道德。&lt;/p>
&lt;p>箴言这卷书是在讲如何善用人生，也在讲如何虚度人生，愚昧的人虚度人生。&lt;/p>
&lt;p>我们很容易虚度一生。&lt;/p>
&lt;p>人生很短，经不起你浪费一分一秒；但是人生的长度足够你活出上帝的旨意。&lt;/p>
&lt;p>箴言不是应许。在希伯来语中，箴言的意思是“就像这样”。箴言是对人生一般性的观察。至于应许是特殊的承诺，这两者要分得很清楚。&lt;/p>
&lt;p>智慧就是在某个情况下知道要应用什么箴言。箴言是一般性的常识，但是遇到不同情况的时候，需要有智慧才知道该应用哪一个箴言。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/david-pawson-provert-part1/</guid><pubDate>Sat, 23 Jun 2018 07:39:16 +0700</pubDate></item><item><title>Java Date and Time Problem</title><link>https://danielsunyu.github.io/myblog-site/posts/java-date-and-time-problem/</link><description>&lt;p>&lt;a href="https://www.hackerrank.com/challenges/java-date-and-time/problem">https://www.hackerrank.com/challenges/java-date-and-time/problem&lt;/a>&lt;/p>
&lt;!-- more -->
&lt;p>这道算法题使用Java 8的Date &amp;amp; Time API很容易解决了。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">Solution&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">private&lt;/span> &lt;span style="color:#00a8c8">static&lt;/span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#75af00">getDay&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">day&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">month&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">year&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">d&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">parseInt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">day&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">m&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">parseInt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">month&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">y&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">Integer&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">parseInt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">year&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">LocalDate&lt;/span> &lt;span style="color:#111">date&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">LocalDate&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">m&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">d&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">date&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">getDayOfWeek&lt;/span>&lt;span style="color:#111">().&lt;/span>&lt;span style="color:#75af00">toString&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">static&lt;/span> &lt;span style="color:#00a8c8">void&lt;/span> &lt;span style="color:#75af00">main&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">String&lt;/span>&lt;span style="color:#f92672">[]&lt;/span> &lt;span style="color:#111">args&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Scanner&lt;/span> &lt;span style="color:#111">in&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">new&lt;/span> &lt;span style="color:#111">Scanner&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">System&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">in&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">month&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">in&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">next&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">day&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">in&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">next&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">String&lt;/span> &lt;span style="color:#111">year&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">in&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">next&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">System&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">out&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">println&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">getDay&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">day&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">month&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">year&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-date-and-time-problem/</guid><pubDate>Fri, 22 Jun 2018 22:08:32 +0700</pubDate></item><item><title>Git Cookbook</title><link>https://danielsunyu.github.io/myblog-site/posts/git-cookbook/</link><description>&lt;p>这个博客包含了在日常开发中经常会使用，但是却不太容易记住的Git命令和用法。&lt;/p>
&lt;h3 id="如何重命名本地和远程分支">如何重命名本地和远程分支&lt;/h3>
&lt;h3 id="如何删除本地和远程分支">如何删除本地和远程分支&lt;/h3>
&lt;h3 id="如何撤销已被push到远程git仓库的最新的commit">如何撤销已被push到远程Git仓库的最新的commit&lt;/h3>
&lt;pre tabindex="0">&lt;code>git revert HEAD
git push
&lt;/code>&lt;/pre>&lt;h3 id="如何从某个分支cherry-pick一个commit并生成patch文件">如何从某个分支cherry-pick一个commit，并生成patch文件&lt;/h3>
&lt;h3 id="如何stash当前分支本地的修改">如何stash当前分支本地的修改&lt;/h3>
&lt;pre tabindex="0">&lt;code>git stash
&lt;/code>&lt;/pre>&lt;h3 id="如何unstash本地修改">如何unstash本地修改&lt;/h3>
&lt;pre tabindex="0">&lt;code>git stash pop
&lt;/code>&lt;/pre></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/git-cookbook/</guid><pubDate>Thu, 21 Jun 2018 12:07:45 +0700</pubDate></item><item><title>Java 8 Date &amp; Time API</title><link>https://danielsunyu.github.io/myblog-site/posts/java-8-date-and-time-api/</link><description>&lt;p>&lt;a href="https://developer.android.com/reference/java/time/package-summary">Android官方文档里&lt;/a>&lt;/p>
&lt;p>&lt;code>java.time.temporal&lt;/code>: lower level access to the fields. &lt;br>
&lt;code>java.time.format&lt;/code>: customization options.&lt;/p>
&lt;!-- more -->
&lt;blockquote>
&lt;p>The offset-based date-time types OffsetTime and OffsetDateTime, are intended primarily for use with network protocols and database access. For example, most databases cannot automatically store a time-zone like &amp;lsquo;Europe/Paris&amp;rsquo;, but they can store an offset like &amp;lsquo;+02:00&amp;rsquo;.&lt;/p>&lt;/blockquote>
&lt;h2 id="获取当前月份">获取当前月份&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">Month&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">from&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Instant&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">now&lt;/span>&lt;span style="color:#111">().&lt;/span>&lt;span style="color:#75af00">atZone&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ZoneId&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Asia/Bangkok&amp;#34;&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="instant">Instant&lt;/h2>
&lt;p>An Instant represents a specific moment in time using GMT.&lt;/p>
&lt;h2 id="daylight-saving-time">Daylight Saving Time&lt;/h2>
&lt;p>The United States observes daylight savings time on March 12, 2017, by moving the clocks forward an hour at 2 a.m.&lt;/p>
&lt;p>In the United States, daylight savings time ends on November 5th, 2017 at 02:00 a.m. and we repeat the previous hour.&lt;/p>
&lt;p>实验如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">LocalDate&lt;/span> &lt;span style="color:#111">localDate&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">LocalDate&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">2017&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Month&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">NOVEMBER&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">5&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">LocalTime&lt;/span> &lt;span style="color:#111">localTime&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">LocalTime&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">0&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ZoneId&lt;/span> &lt;span style="color:#111">zone&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">ZoneId&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;America/New_York&amp;#34;&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ZonedDateTime&lt;/span> &lt;span style="color:#111">z&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">ZonedDateTime&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">of&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">localDate&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">localTime&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">zone&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">0&lt;/span>&lt;span style="color:#111">;&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#111">6&lt;/span>&lt;span style="color:#111">;&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">++&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">System&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">out&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">println&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">z&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">plusHours&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>2017-11-05T01:00-04:00[America/New_York]
2017-11-05T01:00-05:00[America/New_York]
2017-11-05T02:00-05:00[America/New_York]
2017-11-05T03:00-05:00[America/New_York]
2017-11-05T04:00-05:00[America/New_York]
2017-11-05T05:00-05:00[America/New_York]
&lt;/code>&lt;/pre></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-8-date-and-time-api/</guid><pubDate>Sat, 16 Jun 2018 22:43:02 +0700</pubDate></item><item><title>谈谈赴泰工作的问题</title><link>https://danielsunyu.github.io/myblog-site/posts/applying-visa-to-work-in-thailand/</link><description>&lt;p>自从16年10月到泰国工作，迄今已经超过一年半了。我也想分享一下如何去泰国工作，其中最重要的就是签证问题。&lt;/p>
&lt;p>根据来泰国的目的，需要申请对应的签证。对于大多数人来说旅游签的门槛很低，但是持有旅游签是不能直接来泰国申请Work Permit的。事实上这种做法是非法的。&lt;/p>
&lt;p>事实上有两个法律凭证需要搞清楚，第一个是工作签证；第二个是工作证。&lt;/p>
&lt;h2 id="需要解答的问题">需要解答的问题&lt;/h2></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/applying-visa-to-work-in-thailand/</guid><pubDate>Thu, 14 Jun 2018 16:48:42 +0700</pubDate></item><item><title>Java泛型中一些难点解析</title><link>https://danielsunyu.github.io/myblog-site/posts/java-generics/</link><description>&lt;p>Joshua Bloch：&lt;/p>
&lt;!-- more -->
&lt;blockquote>
&lt;p>For maximum flexibility, use wildcard types on input parameters that represent producers or consumers. If an input parameter is both a producer and a consumer, then wildcard types will do you no good: you
need an exact type match, which is what you get without any wildcards. Here is a mnemonic to help you remember which wildcard type to use:
PECS stands for producer-extends, consumer-super.&lt;/p>&lt;/blockquote>
&lt;p>参考Stackoverflow上这个&lt;a href="https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java">问答&lt;/a>或是参考这个&lt;a href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103">Java Generics FAQs&lt;/a>&lt;/p>
&lt;h3 id="what-is-a-bounded-wildcard">What is a bounded wildcard?&lt;/h3>
&lt;p>A wildcard with either an upper or a lower bound.
A wildcard with an upper bound looks like &amp;quot; ? extends Type &amp;quot; and stands for the family of all types that are subtypes of Type , type Type being included. Type is called the upper bound .
A wildcard with a lower bound looks like &amp;quot; ? super Type &amp;quot; and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound .&lt;/p>
&lt;p>Bounded wildcards are used as arguments for instantiation of generic types. Bounded wildcards are useful in situations where only partial knowledge about the type argument of a parameterized type is needed, but where unbounded wildcards carry too little type information.&lt;/p>
&lt;p>Example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">Collections&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// bounded wildcard parameterized types&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">static&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#00a8c8">void&lt;/span> &lt;span style="color:#75af00">copy&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">List&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">dest&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">List&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">extends&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">src&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">int&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">0&lt;/span>&lt;span style="color:#111">;&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#111">src&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">size&lt;/span>&lt;span style="color:#111">();&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">++&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">dest&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">set&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">src&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The copy method copies elements from a source list into a destination list. The destination list must be capable of holding the elements from the source list. We express this by means of bounded wildcards: the output list is required to have an element type with a lower bound T and the input list must have an element type with an upper bound T .&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-generics/</guid><pubDate>Tue, 12 Jun 2018 11:44:52 +0700</pubDate></item><item><title>Java 8 Optional类的要点分析</title><link>https://danielsunyu.github.io/myblog-site/posts/java-8-optional/</link><description>&lt;p>首先仔细浏览&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html">Oracle&lt;/a>和&lt;a href="https://developer.android.com/reference/java/util/Optional">Android&lt;/a>官方API文档。&lt;/p>
&lt;!-- more -->
&lt;p>然后仔细浏览Urma所著的Oracle的Java官方&lt;a href="http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html">Tutorial&lt;/a>。&lt;/p>
&lt;p>Urma关于空指针的一段话：&lt;/p>
&lt;blockquote>
&lt;p>I will argue in this article that using null to represent the absence of a value is a wrong approach. What we need is a better way to model the absence and presence of a value.&lt;/p>&lt;/blockquote>
&lt;p>关于引入&lt;code>java.util.Optional&lt;/code>类的初衷：&lt;/p>
&lt;blockquote>
&lt;p>It is important to note that the intention of the Optional class is not to replace every single null reference. Instead, its purpose is to help design more-comprehensible APIs so that by just reading the signature of a method, you can tell whether you can expect an optional value. This forces you to actively unwrap an Optional to deal with the absence of a value.&lt;/p>&lt;/blockquote>
&lt;h2 id="optionalmap和optionalflatmap的区别">Optional.map和Optional.flatMap的区别&lt;/h2>
&lt;p>其实只要仔细读读Optional类的源码就明白两者的区别了：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * If a value is present, apply the provided mapping function to it,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * and if the result is non-null, return an {@code Optional} describing the
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * result. Otherwise return an empty {@code Optional}.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @apiNote This method supports post-processing on optional values, without
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * the need to explicitly check for a return status. For example, the
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * following code traverses a stream of file names, selects one that has
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * not yet been processed, and then opens that file, returning an
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * {@code Optional&amp;lt;FileInputStream&amp;gt;}:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * &amp;lt;pre&amp;gt;{@code
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Optional&amp;lt;FileInputStream&amp;gt; fis =
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * names.stream().filter(name -&amp;gt; !isProcessedYet(name))
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * .findFirst()
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * .map(name -&amp;gt; new FileInputStream(name));
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * }&amp;lt;/pre&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Here, {@code findFirst} returns an {@code Optional&amp;lt;String&amp;gt;}, and then
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * {@code map} returns an {@code Optional&amp;lt;FileInputStream&amp;gt;} for the desired
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * file if one exists.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param &amp;lt;U&amp;gt; The type of the result of the mapping function
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param mapper a mapping function to apply to the value, if present
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return an {@code Optional} describing the result of applying a mapping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * function to the value of this {@code Optional}, if a value is present,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * otherwise an empty {@code Optional}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @throws NullPointerException if the mapping function is null
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">Optional&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#75af00">map&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Function&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#f92672">?&lt;/span> &lt;span style="color:#00a8c8">extends&lt;/span> &lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Objects&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">requireNonNull&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#f92672">!&lt;/span>&lt;span style="color:#111">isPresent&lt;/span>&lt;span style="color:#111">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">empty&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">Optional&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">ofNullable&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">apply&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">value&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * If a value is present, apply the provided {@code Optional}-bearing
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * mapping function to it, return that result, otherwise return an empty
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * {@code Optional}. This method is similar to {@link #map(Function)},
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * but the provided mapper is one whose result is already an {@code Optional},
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * and if invoked, {@code flatMap} does not wrap it with an additional
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * {@code Optional}.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param &amp;lt;U&amp;gt; The type parameter to the {@code Optional} returned by
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param mapper a mapping function to apply to the value, if present
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * the mapping function
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return the result of applying an {@code Optional}-bearing mapping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * function to the value of this {@code Optional}, if a value is present,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * otherwise an empty {@code Optional}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @throws NullPointerException if the mapping function is null or returns
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * a null result
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">Optional&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#75af00">flatMap&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Function&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Optional&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">U&lt;/span>&lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">Objects&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">requireNonNull&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#f92672">!&lt;/span>&lt;span style="color:#111">isPresent&lt;/span>&lt;span style="color:#111">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">empty&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">Objects&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">requireNonNull&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">apply&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">value&lt;/span>&lt;span style="color:#111">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可见两者唯一的区别就是map方法在最后用 &lt;code>Optional.ofNullable&lt;/code> 包装了返回值，而flatMap没有。&lt;/p>
&lt;h2 id="optional类的primitive版本">Optional类的primitive版本&lt;/h2>
&lt;p>&lt;code>OptionalInt&lt;/code>、&lt;code>OptionalLong&lt;/code>、&lt;code>OptionalDouble&lt;/code>，它们的对应&lt;code>get&lt;/code>方法签名变成了&lt;code>getAsInt&lt;/code>、&lt;code>getAsLong&lt;/code>、&lt;code>getAsDouble&lt;/code>。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-8-optional/</guid><pubDate>Mon, 11 Jun 2018 21:15:02 +0700</pubDate></item><item><title>Introduction to Java 8</title><link>https://danielsunyu.github.io/myblog-site/posts/introduction-to-java-8/</link><description>&lt;p>关于&lt;a href="http://math.hws.edu/javanotes/glossary.html">Java的术语总结&lt;/a>。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/introduction-to-java-8/</guid><pubDate>Mon, 11 Jun 2018 11:59:30 +0700</pubDate></item><item><title>Java Stream API</title><link>https://danielsunyu.github.io/myblog-site/posts/java-stream-api/</link><description>&lt;p>Java 8引入了Stream的概念，掌握这个概念的最佳方式是阅读Java官方文档。&lt;/p>
&lt;!-- more -->
&lt;p>可以浏览一下Oracle Java文档或是&lt;a href="https://developer.android.com/reference/java/util/stream/package-summary">Android官方文档&lt;/a>。&lt;/p>
&lt;p>有些关键的概念需要掌握：stream、source、stream pipeline、stream operations、intermediate operations、terminal operation。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Returns a sequential {@code Stream} with this collection as its source.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * &amp;lt;p&amp;gt;This method should be overridden when the {@link #spliterator()}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * method cannot return a spliterator that is {@code IMMUTABLE},
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * {@code CONCURRENT}, or &amp;lt;em&amp;gt;late-binding&amp;lt;/em&amp;gt;. (See {@link #spliterator()}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * for details.)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @implSpec
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * The default implementation creates a sequential {@code Stream} from the
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * collection&amp;#39;s {@code Spliterator}.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return a sequential {@code Stream} over the elements in this collection
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @since 1.8
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">default&lt;/span> &lt;span style="color:#111">Stream&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">E&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#75af00">stream&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">StreamSupport&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">stream&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">spliterator&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#00a8c8">false&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Stream实例只能被使用一次，否则会抛出Runtime Exception：&lt;/p>
&lt;pre tabindex="0">&lt;code>java.lang.IllegalStateException: stream has already been operated upon or closed
&lt;/code>&lt;/pre>&lt;p>The right and most convenient way to use streams are by a stream pipeline, which is a chain of stream source, intermediate operations, and a terminal operation.&lt;/p>
&lt;h2 id="将stream转换为intlong或double流">将&lt;code>Stream&lt;/code>转换为&lt;code>int&lt;/code>、&lt;code>long&lt;/code>或&lt;code>double&lt;/code>流&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#111">DoubleStream&lt;/span> &lt;span style="color:#75af00">mapToDouble&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ToDoubleFunction&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#111">IntStream&lt;/span> &lt;span style="color:#75af00">mapToInt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ToIntFunction&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#111">LongStream&lt;/span> &lt;span style="color:#75af00">mapToLong&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ToLongFunction&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">mapper&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="allmatchanymatch和nonematch方法">allMatch，anyMatch和noneMatch方法&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#00a8c8">boolean&lt;/span> &lt;span style="color:#75af00">allMatch&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Predicate&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">predicate&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#00a8c8">boolean&lt;/span> &lt;span style="color:#75af00">anyMatch&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Predicate&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">predicate&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">abstract&lt;/span> &lt;span style="color:#00a8c8">boolean&lt;/span> &lt;span style="color:#75af00">noneMatch&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">Predicate&lt;/span>&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#00a8c8">super&lt;/span> &lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">predicate&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-stream-api/</guid><pubDate>Wed, 06 Jun 2018 18:02:25 +0700</pubDate></item><item><title>Java 8 Functional Interfaces笔记</title><link>https://danielsunyu.github.io/myblog-site/posts/java-8-functional-interfaces-notes/</link><description>&lt;p>最近在准备OCJP 8考试，需要熟悉一下Java 8引入的函数式编程的概念。具体包括了Functional Interfaces、Lambda表达式、Stream API等新知识。&lt;/p>
&lt;!-- more -->
&lt;p>最值得阅读的文档一般都是官方文档。&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">Oracle&lt;/a>和&lt;a href="https://developer.android.com/reference/java/util/function/package-summary">Android&lt;/a>都有文档的链接。&lt;/p>
&lt;h2 id="4个内建built-in的functional-interfaces">4个内建(Built-in)的Functional interfaces&lt;/h2>
&lt;p>Functional Interfaces，或称为函数式接口，主要是指列于&lt;code>java.util.function&lt;/code>包下的所有新的接口。它们被设计出来以满足通用的需求。乍看下共有43个接口，会觉得很吓人。其实它们都是从4个最典型的接口派生而来，为了某个specialization的、更具体化的场景而设计的，说白了就是为了让程序员能够根据需求选择出最具体化的接口。&lt;/p>
&lt;h3 id="1-function接口">1. Function接口&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">@FunctionalInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">interface&lt;/span> &lt;span style="color:#75af00">Function&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">R&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Applies this function to the given argument.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param t the function argument
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return the function result
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">R&lt;/span> &lt;span style="color:#75af00">apply&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">T&lt;/span> &lt;span style="color:#111">t&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-supplier接口">2. Supplier接口&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">@FunctionalInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">interface&lt;/span> &lt;span style="color:#75af00">Supplier&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Gets a result.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return a result
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">T&lt;/span> &lt;span style="color:#75af00">get&lt;/span>&lt;span style="color:#111">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-predicate接口">3. Predicate接口&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">@FunctionalInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">interface&lt;/span> &lt;span style="color:#75af00">Predicate&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Evaluates this predicate on the given argument.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param t the input argument
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @return {@code true} if the input argument matches the predicate,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * otherwise {@code false}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">boolean&lt;/span> &lt;span style="color:#75af00">test&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">T&lt;/span> &lt;span style="color:#111">t&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-consumer接口">4. Consumer接口&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">@FunctionalInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">public&lt;/span> &lt;span style="color:#00a8c8">interface&lt;/span> &lt;span style="color:#75af00">Consumer&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>&lt;span style="color:#111">T&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Performs this operation on the given argument.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param t the input argument
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">void&lt;/span> &lt;span style="color:#75af00">accept&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">T&lt;/span> &lt;span style="color:#111">t&lt;/span>&lt;span style="color:#111">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Lambda表达式和函数式接口并不是一一对应的关系，一个Lambda表达式可以与多个Functional Interfaces兼容（compatible）。&lt;/p>
&lt;h2 id="primitive-functional-interfaces">Primitive Functional Interfaces&lt;/h2>
&lt;p>Primitive Functional Interfaces只包含&lt;code>double&lt;/code>、&lt;code>int&lt;/code>和&lt;code>long&lt;/code>类型，而不包含&lt;code>char&lt;/code>、&lt;code>float&lt;/code>和&lt;code>short&lt;/code>类型，所以&lt;code>java.util.function&lt;/code>包下就不存在类似&lt;code>CharSupplier&lt;/code>的接口。&lt;/p>
&lt;h2 id="补充">补充&lt;/h2>
&lt;p>arity的解释是&amp;quot;元数&amp;quot;，就是参数数目的意思。&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/java-8-functional-interfaces-notes/</guid><pubDate>Wed, 06 Jun 2018 17:15:33 +0700</pubDate></item><item><title>在Mac系统上安装Java 7最佳实践</title><link>https://danielsunyu.github.io/myblog-site/posts/install-java7-on-mac/</link><description>&lt;p>截止今日，Oracle已经推出了JDK 8，对于这么新的版本，相信很多人和我一样不敢尝试。由于JDK 7已经在一些平台上（如最新的Android系统）得到支持，所以如果能在Mac上将JDK 6升级到7将会解决一些开发上的需求。&lt;/p>
&lt;p>Mac系统历代OS都内置了JDK版本，不过最新的Mavericks上却只内置了JRE 6。Mac系统省缺JDK但是可以通过其升级机制安装JDK，遗憾的是苹果官方支持/安装的是JDK 6。看来Mac在Java的支持上有些滞后。幸运的是，在Mac上升级JDK很简单，可以按照如下步骤：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>前往Oracle官网的Java SE Development Kit 7下载页下载Mac平台的dmg安装包。由于Mac系统的处理器都是64位的，所以只有唯一对应的安装包可以选择！&lt;/p>
&lt;/li>
&lt;li>
&lt;p>双击dmg安装包，会显示如下安装界面，双击pkg图标就会开始安装。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;figure>&lt;img src="https://danielsunyu.github.io/myblog-site/images/jdk7_installation_wizard.png" width="400px" height="560px">
&lt;/figure>
&lt;p>安装结束后在命令行输入：&lt;/p>
&lt;pre tabindex="0">&lt;code>java --version
&lt;/code>&lt;/pre>&lt;p>回显：&lt;/p>
&lt;pre tabindex="0">&lt;code>java version &amp;#34;1.7.0_67&amp;#34;
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
&lt;/code>&lt;/pre>&lt;p>Bingo，JDK 7已经安装完毕，不过先别急着离开，在实际的软件开发中，还会需要设置JAVA_HOME环境变量。&lt;/p>
&lt;p>附加任务：设置JAVA_HOME环境变量&lt;/p>
&lt;p>打开home目录下的.bash_profile文件，在最后加入如下代码：&lt;/p>
&lt;pre tabindex="0">&lt;code>export JAVA_HOME=$(/usr/libexec/java_home)
&lt;/code>&lt;/pre>&lt;p>关闭文件后，在命令行输入：&lt;/p>
&lt;pre tabindex="0">&lt;code>source .bash_profile
&lt;/code>&lt;/pre>&lt;p>这样，JAVA_HOME环境变量就设置完毕了，可以这样验证：&lt;/p>
&lt;pre tabindex="0">&lt;code>echo $JAVA_HOME
&lt;/code>&lt;/pre>&lt;p>回显如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>/Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home
&lt;/code>&lt;/pre>&lt;p>OK，大功告成！&lt;/p></description><author>Daniel Sun</author><guid>https://danielsunyu.github.io/myblog-site/posts/install-java7-on-mac/</guid><pubDate>Tue, 16 Sep 2014 14:02:10 +0800</pubDate></item></channel></rss>