{"version":"https://jsonfeed.org/version/1","title":"S先生の筆記📒","home_page_url":"https://danielsunyu.github.io/myblog-site/","feed_url":"https://danielsunyu.github.io/myblog-site/feed.json","description":"A minimal hugo theme focus on content","favicon":"https://danielsunyu.github.io/myblog-site//assets/favicon.ico","expired":false,"author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"},"items":[{"id":"d28bbfe7b103e72d63d82ab0529b981011cb1041","title":"Run xv6-x86-64 on macOS M","summary":"","content_text":"https://en.wikipedia.org/wiki/Xv6\nI used to believe it\u0026rsquo;s not possible to run xv6-x86-64 version on macOS with arm chip. It turns out that it is not that hard to do that with qemu.\nAll we need is to install qemu on your macOS.\nbrew install qemu Verify:\nwhich qemu-system-x86_64 $ /opt/homebrew/bin/qemu-system-x86_64 Install cross-compilation toolchain:\n$ brew install x86_64-elf-gcc $ which x86_64-elf-gcc $ /opt/homebrew/bin/x86_64-elf-gcc make qemu-nox ","content_html":"\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Xv6\"\u003ehttps://en.wikipedia.org/wiki/Xv6\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eI used to believe it\u0026rsquo;s not possible to run \u003ccode\u003exv6-x86-64\u003c/code\u003e version on macOS with arm chip. It turns out that it is not\nthat hard to do that with \u003ccode\u003eqemu\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eAll we need is to install \u003ccode\u003eqemu\u003c/code\u003e on your macOS.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew install qemu\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eVerify:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewhich qemu-system-x86_64\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ /opt/homebrew/bin/qemu-system-x86_64\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eInstall cross-compilation toolchain:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ brew install x86_64-elf-gcc\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ which x86_64-elf-gcc\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ /opt/homebrew/bin/x86_64-elf-gcc\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emake qemu-nox   \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/run-xv6-x86-64-on-mac-m/","date_published":"5036-05-09T341:55:00-07:00","date_modified":"5036-05-09T341:55:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"81a53cc4038c904dd3d7ff20c6153ce4a664b419","title":"Assembly Word","summary":"","content_text":"在 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\n这里的“double”不是“相对当前模式”， 而是相对最初的 16 位 word。\n","content_html":"\u003cp\u003e在 x86 体系里——不管 16 位、32 位、还是 64 位模式——\nWORD 永远是 16 位 = 2 字节。\n这是历史遗产。\n早期 8086 是 16 位 CPU。\n当时“word”就是机器的自然数据宽度——16 位。\n后来扩展到 32 位：\n原来的 word 仍然是 16 位\n新的 32 位被叫做 double word（DWORD）\n再到 64 位：\n64 位叫 quad word（QWORD）\n所以单位一直叠加：\nBYTE = 8 bit\nWORD = 16 bit\nDWORD = 32 bit\nQWORD = 64 bit\u003c/p\u003e\n\u003cp\u003e这里的“double”不是“相对当前模式”，\n而是相对最初的 16 位 word。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/assembly-word/","date_published":"3036-03-09T326:33:00-07:00","date_modified":"3036-03-09T326:33:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"c2db9c320ab2c96022b6c62fb1039a1cce1f930c","title":"Useful Uou Resources","summary":"","content_text":"Student Health Center https://studenthealth.utah.edu/\n","content_html":"\u003cp\u003eStudent Health Center\n\u003ca href=\"https://studenthealth.utah.edu/\"\u003ehttps://studenthealth.utah.edu/\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/useful-uou-resources/","date_published":"22026-22-09T26:2222:00-07:00","date_modified":"22026-22-09T26:2222:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"d9abf4b8911949bf01e85528c3030f984c84f676","title":"Run x86-64 Docker on Macos","summary":"","content_text":"","content_html":"","url":"https://danielsunyu.github.io/myblog-site/posts/run-x86-64-docker-on-macos/","date_published":"17026-17-09T225:1717:00-07:00","date_modified":"17026-17-09T225:1717:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"9607266c6ee35011528d55cd7e4b7e1f4b349d7c","title":"决定不玩SRS账户了","summary":"","content_text":"向SRS账户转入一笔钱的那刻，注定是给自己找麻烦。\n新加坡很多理专忽悠我开通SRS账户。基本上连新加坡人也很少玩SRS。\n钱转入后，看似可以避税，但是打理这个账户非常麻烦。\n首先，SRS需要挂靠在一家银行账户下。为了增值，还需要开通银行的证券账户，所以我还得安装银行的证券App。\n本来SRS就那么点钱，还要用专门的App去运作，真是麻烦的很。而且银行证券服务的交易手续费也比在线券商高很多。\n终于，三思后，打算把余额转出SRS，此生不碰SRS。\n","content_html":"\u003cp\u003e向SRS账户转入一笔钱的那刻，注定是给自己找麻烦。\u003c/p\u003e\n\u003cp\u003e新加坡很多理专忽悠我开通SRS账户。基本上连新加坡人也很少玩SRS。\u003c/p\u003e\n\u003cp\u003e钱转入后，看似可以避税，但是打理这个账户非常麻烦。\u003c/p\u003e\n\u003cp\u003e首先，SRS需要挂靠在一家银行账户下。为了增值，还需要开通银行的证券账户，所以我还得安装银行的证券App。\u003c/p\u003e\n\u003cp\u003e本来SRS就那么点钱，还要用专门的App去运作，真是麻烦的很。而且银行证券服务的交易手续费也比在线券商高很多。\u003c/p\u003e\n\u003cp\u003e终于，三思后，打算把余额转出SRS，此生不碰SRS。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/done-with-srs/","date_published":"14026-14-09T258:1414:00-07:00","date_modified":"14026-14-09T258:1414:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"7a4314129c66a402b13384a939b2f087edc79190","title":"Ampcode","summary":"","content_text":"Ampcode是我入门Vibe Coding，也几乎成为了日常开发工作的重要工具。\nprint(\u0026#34;hello world\u0026#34;); https://ampcode.com/news/amp-free\nhttps://ampcode.com/free\nhttps://ampcode.com/manual\nhttps://ampcode.com/news/liberating-code-review\n","content_html":"\u003cp\u003e\u003ccode\u003eAmpcode\u003c/code\u003e是我入门Vibe Coding，也几乎成为了日常开发工作的重要工具。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003eprint\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;hello world\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ca href=\"https://ampcode.com/news/amp-free\"\u003ehttps://ampcode.com/news/amp-free\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://ampcode.com/free\"\u003ehttps://ampcode.com/free\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://ampcode.com/manual\"\u003ehttps://ampcode.com/manual\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://ampcode.com/news/liberating-code-review\"\u003ehttps://ampcode.com/news/liberating-code-review\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/ampcode/","date_published":"11026-11-09T248:1111:00-07:00","date_modified":"11026-11-09T248:1111:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"e7cf694d6826ffad231f709917d0cc7b2cbe1454","title":"两种几何随机变量的定义","summary":"","content_text":"发现在一些主流教材中，几何型随机变量(Geometric Random Variable)的定义有细微的分歧。主流教材中给的定义是，重复多次的抛硬币试验 (单次试验是Bernoulli experiment)，\nNumber of flips (failures) until the first heads (success)\n但有有些教材会定义为：\nNumber of flips (failures) before the first heads (success)\n虽然中外主流教材都是采用第一种定义，但是遗憾的是R和Python中的概率计算库使用的是第二种定义。\n比如为要计算X ~ Geo(0.5)，X = 1的概率，需要传入0：\ndgeom(0, 0.5) 这种定义的不一致带来毫无必要的麻烦。\nhttps://en.wikipedia.org/wiki/Geometric_distribution\n","content_html":"\u003cp\u003e发现在一些主流教材中，几何型随机变量(Geometric Random Variable)的定义有细微的分歧。主流教材中给的定义是，重复多次的抛硬币试验\n(单次试验是Bernoulli experiment)，\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003eNumber of flips (failures) until the first heads (success)\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e但有有些教材会定义为：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003eNumber of flips (failures) before the first heads (success)\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e虽然中外主流教材都是采用第一种定义，但是遗憾的是\u003cstrong\u003eR\u003c/strong\u003e和\u003cstrong\u003ePython\u003c/strong\u003e中的概率计算库使用的是第二种定义。\u003c/p\u003e\n\u003cp\u003e比如为要计算X ~ Geo(0.5)，X = 1的概率，需要传入0：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-R\" data-lang=\"R\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003edgeom\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.5\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这种定义的不一致带来毫无必要的麻烦。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Geometric_distribution\"\u003ehttps://en.wikipedia.org/wiki/Geometric_distribution\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/geometric-random-variable-note/","date_published":"3116-03-09T1150:33:00-07:00","date_modified":"3116-03-09T1150:33:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"0a4d55a8d778e5022fab701977c5d840bbc486d0","title":"Hello World","summary":"","content_text":"","content_html":"","url":"https://danielsunyu.github.io/myblog-site/posts/hello-world/","date_published":"4106-04-09T1011:44:00-06:00","date_modified":"4106-04-09T1011:44:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"872478d1a1c24cd492d4e4c9e442e21e22763453","title":"有用的Google Colab命令","summary":"","content_text":"如何将Jupyter Notebook转成PDF !sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-plain-generic !sudo apt-get install pandoc !jupyter nbconvert --to pdf \u0026lt;path to jupyter notebook\u0026gt;.ipynb ","content_html":"\u003ch4 id=\"如何将jupyter-notebook转成pdf\"\u003e如何将Jupyter Notebook转成PDF\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e!sudo apt-get install texlive-xetex texlive-fonts-recommended texlive-plain-generic\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e!sudo apt-get install pandoc\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e!jupyter nbconvert --to pdf \u0026lt;path to jupyter notebook\u0026gt;.ipynb \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/useful-colab-commands/","date_published":"6096-06-09T952:66:00-06:00","date_modified":"6096-06-09T952:66:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"8f65fd76df6c5a0cf5ae68550efb7764e2894f90","title":"犹他大学CS6353：Deep Learning","summary":"","content_text":"https://d2l.ai/index.html\n","content_html":"\u003cp\u003e\u003ca href=\"https://d2l.ai/index.html\"\u003ehttps://d2l.ai/index.html\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/utah-cs-6353-deep-learning/","date_published":"22086-22-09T826:2222:00-06:00","date_modified":"22086-22-09T826:2222:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"4556f3569e016cc46018238f832cb94640bacaed","title":"犹他大学CS 6300：Artificial Intelligence","summary":"","content_text":"课程主页：https://dsbrown1331.github.io/intro-ai-class/\n基本不出所料，这本课程拷贝了Berkeley CS188。\nhttps://inst.eecs.berkeley.edu/~cs188/su25/\nOffice hours: https://docs.google.com/spreadsheets/d/1l8_Ao3nhnRuwWtWc2FHGDa45U35HzWy-PXrfO-VEAh4/edit?gid=0#gid=0\nPiazza: https://piazza.com/class/me9fkw623gc52m\n第一章：绪论\nAn agent is just something that acts. A rational agent is one that acts so as to achieve the best outcome or, when there is uncertainty, the best expected outcome.\nThe 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.\nIn 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.\n","content_html":"\u003cp\u003e课程主页：\u003ca href=\"https://dsbrown1331.github.io/intro-ai-class/\"\u003ehttps://dsbrown1331.github.io/intro-ai-class/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e基本不出所料，这本课程拷贝了Berkeley CS188。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://inst.eecs.berkeley.edu/~cs188/su25/\"\u003ehttps://inst.eecs.berkeley.edu/~cs188/su25/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eOffice hours: \u003ca href=\"https://docs.google.com/spreadsheets/d/1l8_Ao3nhnRuwWtWc2FHGDa45U35HzWy-PXrfO-VEAh4/edit?gid=0#gid=0\"\u003ehttps://docs.google.com/spreadsheets/d/1l8_Ao3nhnRuwWtWc2FHGDa45U35HzWy-PXrfO-VEAh4/edit?gid=0#gid=0\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003ePiazza: \u003ca href=\"https://piazza.com/class/me9fkw623gc52m\"\u003ehttps://piazza.com/class/me9fkw623gc52m\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e第一章：绪论\u003c/p\u003e\n\u003cp\u003eAn agent is just something that acts. \u003cbr\u003e\nA rational agent is one that acts so as to achieve the\nbest outcome or, when there is uncertainty, the best expected outcome.\u003c/p\u003e\n\u003cp\u003eThe rational-agent approach to AI has prevailed throughout most of the field’s history. In the early decades, rational\nagents were built on logical foundations and formed definite plans to achieve specific goals. Later, methods based on\nprobability\ntheory and machine learning allowed the creation of agents that could make decisions under\nuncertainty to attain the best expected outcome.\u003c/p\u003e\n\u003cp\u003eIn a nutshell, AI has focused on the study\nand construction of agents that do the right thing. What counts as the right thing is defined\nby the objective that we provide to the agent. This general paradigm is so pervasive that we\nmight call it the standard model.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/utah-cs6300-ai/","date_published":"22086-22-09T817:2222:00-06:00","date_modified":"22086-22-09T817:2222:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"da4dc43fb5ef853bfec1cab2f32038aeb42a549a","title":"Big Nerd Ranch React Programming笔记","summary":"","content_text":"第十三章\nSyntheticBaseEvent 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 nativeEvent property. (However, it is unlikely that you will ever need it.)\n","content_html":"\u003cp\u003e第十三章\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eSyntheticBaseEvent\u003c/code\u003e is a wrapper that React puts around native events to ensure that events work the same across all\nbrowsers. You can access the underlying native event through the \u003ccode\u003enativeEvent\u003c/code\u003e property. (However, it is unlikely\nthat you will ever need it.)\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/react-programming-notes/","date_published":"20076-20-09T743:2020:00+08:00","date_modified":"20076-20-09T743:2020:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"6a19733ebcd70f13e9194d8a83633b1749db26db","title":"Bootstrap Microservices Ch4","summary":"","content_text":"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.\n","content_html":"\u003cp\u003eTesting an internal microservice from the outside is normally\nonly possible in development. Once we move this microservice to production, its\nREST 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.\nThis is a security feature of microservices! We can control which microservices are\nexposed to the outside world, and we can use that to restrict access to parts of the\napplication that should not be directly accessible by outsiders.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/bootstrap-microservices-ch4/","date_published":"9076-09-09T721:99:00+07:00","date_modified":"9076-09-09T721:99:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"78a8673d2b9c2a913f5568b38a976eb396d0ceec","title":"Spring Boot的环境变量","summary":"","content_text":"在Spring Boot中，环境变量的定义，可以诸如在application.properties中：\nserver.port=${PORT} 这里的$PORT是一个自定义的环境变量，它将绑定系统预设的server.port，就是服务的端口号。\n但是如果要自定义一个环境变量，而没有系统的某个key对应，那就不要在application.properties中绑定？\n","content_html":"\u003cp\u003e在Spring Boot中，环境变量的定义，可以诸如在application.properties中：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eserver.port=${PORT}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这里的$PORT是一个自定义的环境变量，它将绑定系统预设的server.port，就是服务的端口号。\u003c/p\u003e\n\u003cp\u003e但是如果要自定义一个环境变量，而没有系统的某个key对应，那就不要在application.properties中绑定？\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/spring-boots-env-vars/","date_published":"8076-08-09T728:88:00+07:00","date_modified":"8076-08-09T728:88:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"24e810b458f30eb9e440f6c9c0c178c30b1d25a9","title":"Bootstrapping Microservices第三章笔记","summary":"","content_text":"A microservices application, however, isn’t a microservices application if it only consists of a single microservice!\nWe’d like to add a database, that’s one container, but it’s not something we consider as a microservice.\nWe 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.\nFor 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.\nWhy 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.\nDocker 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.\nThe Docker Compose file is a script that specifies how to compose an application from multiple Docker containers.\nThe Docker Compose file is like a script for building and launching a microservices\nRecall 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\nWe’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.\nOur Docker Compose file, which is called docker-compose.yaml. Because it doesn’t belong to any single microservice, it lives in the root directory of our microservices application.\nservices: video-streaming: image: video-streaming build: context: ./video-streaming dockerfile: Dockerfile container_name: video-streaming ports: - \u0026#34;4000:8080\u0026#34; environment: - PORT=8080 restart: \u0026#34;no\u0026#34; You might be wondering why we set the restart 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.\nThe output of Docker commands such as docker ps can be different from the output of docker compose ps. 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.\nIn 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.\nPut another way, docker compose ps shows us only the containers that are listed in our Docker Compose file, whereas, docker ps shows us all containers on our development computer.\n","content_html":"\u003cp\u003eA microservices application, however, isn’t a microservices application if it only consists of a single microservice!\u003c/p\u003e\n\u003cp\u003eWe’d like to add a database, that’s one container, but it’s not something we consider as a microservice.\u003c/p\u003e\n\u003cp\u003eWe could use the local version of Kubernetes that is included with Docker Desktop, but it’s kind of resource hungry\n(try running it on a laptop if you want to see poor performance) and just not that convenient to use when we’re working\non multiple projects.\u003c/p\u003e\n\u003cp\u003eFor now, we can “simulate” Kubernetes on our development computer using Docker Compose, which is much easier and more\nstraightforward than trying to dive straight into Kubernetes.\u003c/p\u003e\n\u003cp\u003eWhy Docker Compose? In the same way that Docker allows us to build, run, and manage a single microservice, Docker\nCompose gives us a convenient way to build, run, and manage multiple microservices in development. During development\nand testing, we must frequently boot and reboot our entire application, which will eventually contain many\nmicroservices. After each small increment of development, we also must test the changes to our code.\u003c/p\u003e\n\u003cp\u003eDocker Compose revolves around the Docker Compose file. I like to think of this as a script file that builds a local\ninstance of a microservices application.\u003c/p\u003e\n\u003cp\u003eThe Docker Compose file is a script that specifies how to compose an application from multiple Docker containers.\u003c/p\u003e\n\u003cp\u003eThe Docker Compose file is like a script for building and launching a microservices\u003c/p\u003e\n\u003cp\u003eRecall the Dockerfile we created, which was a script for building a single image. The Docker Compose file scales this up\nand allows us to orchestrate the creation of a whole application from a collection of Dockerfiles. Docker Compose reads\nthe Docker Compose file and produces a running application\u003c/p\u003e\n\u003cp\u003eWe’re now building an application that will soon have more than one microservice. We must therefore put each\nmicroservice into its own separate subdirectory. Our convention is that each subdirectory will be named after its\nmicroservice.\u003c/p\u003e\n\u003cp\u003eOur Docker Compose file, which is called \u003ccode\u003edocker-compose.yaml\u003c/code\u003e. Because it doesn’t belong to any single microservice, it\nlives in the root directory of our microservices application.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-docker\" data-lang=\"docker\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eservices:\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e  video-streaming:\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    image: video-streaming\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    build: \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e      context: ./video-streaming\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e      dockerfile: Dockerfile\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    container_name: video-streaming\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    ports:\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e     - \u003cspan style=\"color:#d88200\"\u003e\u0026#34;4000:8080\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    environment:\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e      - \u003cspan style=\"color:#111\"\u003ePORT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e8080\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u003c/span\u003e    restart: \u003cspan style=\"color:#d88200\"\u003e\u0026#34;no\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eYou might be wondering why we set the \u003ccode\u003erestart\u003c/code\u003e option to no. When working in development, we don’t want our\nmicroservices to automatically restart when they crash. If they did that, we could easily miss problems! Instead, if\nthese crash, we want them to stay that way so that we’ll notice the problem. This is the opposite of how we’d usually\nlike our microservices to work in production. We’ll see later in chapter 11 how we can have Kubernetes automatically\nrestart our production microservices that crash.\u003c/p\u003e\n\u003cp\u003eThe output of Docker commands such as \u003ccode\u003edocker ps\u003c/code\u003e can be different from the output of \u003ccode\u003edocker compose ps\u003c/code\u003e. That’s\nbecause Docker commands relate to all images and containers on our development computer, whereas Docker Compose commands\nonly relate to the images and containers specified in our Docker Compose file.\u003c/p\u003e\n\u003cp\u003eIn this sense, we’re using Docker Compose like a scoping mechanism. It constrains the commands to apply only to images\nand containers in our current project. Essentially, it restricts the scope of these commands to the current working\ndirectory, which is another useful aspect of Docker Compose.\u003c/p\u003e\n\u003cp\u003ePut another way, \u003ccode\u003edocker compose ps\u003c/code\u003e shows us only the containers that are listed in our Docker Compose file, whereas,\n\u003ccode\u003edocker ps\u003c/code\u003e shows us all containers on our development computer.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/bm-ch3-notes/","date_published":"4076-04-09T721:44:00+07:00","date_modified":"4076-04-09T721:44:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"09eacfe0c968a3be980f862612496dc2d53c4e62","title":"Bootstrapping Microservices V2","summary":"","content_text":"Chapter 2 Express is the de facto standard for building HTTP servers on Node.js.\nOf 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\u0026rsquo;d otherwise need using the low-level Node.js API.\nnpm install --save express The \u0026ndash;save argument causes the dependency to be added to and tracked in the package.json file. Note that \u0026ndash;save isn\u0026rsquo;t necessary anymore. In older versions of Node.js, this was required; these days, it\u0026rsquo;s the default.\nThe command npm install by itself (not specifying any particular package) installs all the dependencies listed in package.json.\nThe file index.js is one of the standard names for the main entry point (main file) of a Node.js application. We could just as easily have called it something else, such as main.js or server.js.\nWe 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\u0026rsquo;t have to be called src —— you can call it anything you like —— but src is a common name for it. Don\u0026rsquo;t forget to update your package.json file to include the location of index.js within the src directory.\nIt\u0026rsquo;s customary during development to set your Node.js application to listen on port 3000.\nEnvironment variables can be thought of as an input or parameter to our microservice.\nConfiguring a microservice\nWe 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 environment variables.\nTo run multiple different microservices at the same time, we’ll have to start them on separate port numbers.\nexport PORT=3000 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.\nWell, to get our microservice ready to run in production, we’ll use a slightly different version of this command:\nnpm install --omit=dev We added the argument --omit=dev 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.\nnpm script\nUp until now, we’ve run our HTTP server on our dev computer like this:\nnode src/index.js That’s OK, but now we’ll start running our microservice using the following standard convention for Node.js:\nnpm start 注：npm start是启用生产环境的惯例。\nInvoking the command npm start is the conventional way to start a Node.js application. This is a special case of a npm script.\nThe nice thing about this convention is that for almost any Node.js project (at least those that follow this convention) , we can run npm start without actually knowing if the main file is called index.js 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.\nThis 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.\nSo 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.\nLive reloading for fast iteration\nTo 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.\nWe can install nodemon in our Node.js project as follows:\nnpm install --save-dev nodemon Note that now we’re using the --save-dev argument. This installs the package as a dev dependency rather than a production dependency.\nnpx command Now that we’re going to be using nodemon instead, we’ll replace node with nodemon and run it like this:\nnpx nodemon src/index.js 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. Now we can run tools like this directly from the current project’s dependencies. 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.\nDebugging the container 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:\ndocker exec -it \u0026lt;container-id\u0026gt; bash From here, you can use common Linux commands such as cd, ls, and ps 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.\n","content_html":"\u003ch1 id=\"chapter-2\"\u003eChapter 2\u003c/h1\u003e\n\u003cp\u003eExpress is the de facto standard for building HTTP servers on Node.js.\u003c/p\u003e\n\u003cp\u003eOf course, we could build an HTTP server directly on Node.js without Express,\nbut Express allows us to do this at a higher level of abstraction, with less code,\nand without the nuts-and-bolts code we\u0026rsquo;d otherwise need using the low-level Node.js API.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install --save express\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u0026ndash;save argument causes the dependency to be added to and tracked in the package.json file. Note that \u0026ndash;save isn\u0026rsquo;t\nnecessary anymore. In older versions of Node.js, this was required; these days, it\u0026rsquo;s the default.\u003c/p\u003e\n\u003cp\u003eThe command npm install by itself (not specifying any particular package) installs all the dependencies listed in\npackage.json.\u003c/p\u003e\n\u003cp\u003eThe \u003ccode\u003efile index.js\u003c/code\u003e is one of the standard names for the main entry point (\u003cem\u003emain\u003c/em\u003e file) of a Node.js application. We\ncould just as\neasily have called it something else, such as main.js or server.js.\u003c/p\u003e\n\u003cp\u003eWe placed the file index.js under the src directory as a convenient way to keep our source code files separated and\neasily distinguished from our configuration and other files. The directory doesn\u0026rsquo;t have to be called src —— you can\ncall it anything you like —— but src is a common name for it. Don\u0026rsquo;t forget to update your package.json file to include\nthe location of index.js within the src directory.\u003c/p\u003e\n\u003cp\u003eIt\u0026rsquo;s customary during development to set your Node.js application to listen on port 3000.\u003c/p\u003e\n\u003cp\u003eEnvironment variables can be thought of as an input or parameter to our microservice.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eConfiguring a microservice\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eWe need a way to configure our microservice so it knows the port number to use when starting the HTTP server. There are\nseveral techniques we might use to configure our microservice, such as configuration files or command-line arguments.\nThese techniques work, but another has emerged as the standard way to configure a microservice, and it’s well supported\nby all the tools we’ll be using. We’ll configure our microservices using \u003cstrong\u003eenvironment variables\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eTo run multiple different microservices at the same time, we’ll have to start them on separate \u003cstrong\u003eport\u003c/strong\u003e numbers.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eexport\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePORT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e3000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWe can also use environment variables to pass secret and sensitive data into a microservice (e.g., the password for our\ndatabase). We need to treat this information carefully, and we shouldn’t store it in the code where everyone in the\ncompany can see it.\u003c/p\u003e\n\u003cp\u003eWell, to get our microservice ready to run in production, we’ll use a slightly different version of this command:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install --omit\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edev\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWe added the argument \u003ccode\u003e--omit=dev\u003c/code\u003e to omit development dependencies and only install those dependencies that are\nrequired\nin production. This is important because when creating a Node.js project, we’ll usually have a bunch of these so-called\ndev dependencies that we only need to support our development efforts—we don’t want to install these into our production\nenvironment.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003enpm script\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eUp until now, we’ve run our HTTP server on our dev computer like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enode src/index.js\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThat’s OK, but now we’ll start running our microservice using the following standard convention for Node.js:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm start\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注：npm start是启用生产环境的惯例。\u003c/p\u003e\n\u003cp\u003eInvoking the command npm start is the conventional way to start a Node.js application. This is a special case of a npm\nscript.\u003c/p\u003e\n\u003cp\u003eThe nice thing about this convention is that for almost any Node.js project (at least those that follow this convention)\n, we can run \u003ccode\u003enpm start\u003c/code\u003e without actually knowing if the main file is called \u003ccode\u003eindex.js\u003c/code\u003e or if it has some other name. We\nalso don’t need to know if the application takes any special command-line arguments or configuration because those\ndetails can be recorded here as well.\u003c/p\u003e\n\u003cp\u003eThis gives us a single command to remember regardless of whatever project we’re looking at and however the particular\napplication is started. This makes understanding how to use any Node.js project much easier, even those created by other\npeople.\u003c/p\u003e\n\u003cp\u003eSo far, we set up our microservice to run on our development computer. That’s all well\nand good—we need that for ongoing development and testing—but before we get to\nthe fun stuff (Docker, Kubernetes, Terraform, etc.), we need to know how to set up\nour microservice to run in the production environment.\nWhen I say production environment, what I mean is our customer-facing environment.\nThat’s where our application is hosted so it can be accessed by our customers. For this\nbook, our production environment is Kubernetes, and we’re gearing up to run our\napplication in a Kubernetes cluster to make it publicly accessible.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLive reloading for fast iteration\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eTo create our live reload pipeline, we’ll install a package called nodemon. We use nodemon to run our microservice, and\nit automatically watches for code changes in our project. When a code change is detected, nodemon automatically restarts\nour microservice for us, saving us the effort of doing so manually. This might not sound like it does much at all, but\nI’ve found that it makes for a fast and fluid development cycle. Once you’ve tried it, you might wonder how you ever did\nwithout it.\u003c/p\u003e\n\u003cp\u003eWe can install nodemon in our Node.js project as follows:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpm install --save-dev nodemon\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNote that now we’re using the \u003ccode\u003e--save-dev\u003c/code\u003e argument. This installs the package as a dev dependency rather than a\nproduction dependency.\u003c/p\u003e\n\u003ch3 id=\"npx-command\"\u003enpx command\u003c/h3\u003e\n\u003cp\u003eNow that we’re going to be using nodemon instead, we’ll replace node with nodemon and run it like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enpx nodemon src/index.js\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe npx command that’s suddenly appeared is a useful command that comes with\nNode.js and allows us to run locally installed packages directly from the command\nline. Before npx was added to Node.js, we used to install modules such as nodemon\nglobally. \u003ca href=\"#\"\u003eNow we can run tools like this directly from the current project’s dependencies.\u003c/a\u003e This really helps us use\nthe right versions of modules for each project and prevents our computer from being cluttered up with globally installed\nmodules.\u003c/p\u003e\n\u003ch3 id=\"debugging-the-container\"\u003eDebugging the container\u003c/h3\u003e\n\u003cp\u003eWhen we’re running a container locally, especially one that is having problems, it can be useful to shell into it and\ninspect it from the inside. This can help us understand what’s happening inside our container. We can open a shell into\nour container like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edocker \u003cspan style=\"color:#111\"\u003eexec\u003c/span\u003e -it \u0026lt;container-id\u0026gt; bash\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eFrom here, you can use common Linux commands such as \u003ccode\u003ecd\u003c/code\u003e, \u003ccode\u003els\u003c/code\u003e, and \u003ccode\u003eps\u003c/code\u003e to inspect the filesystem and process inside\nthe container. This is a valuable technique for debugging and understanding what is going on in your container, so\nplease spend some time exploring inside your container.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/bootstrapping-microservices-v2/","date_published":"29066-29-09T652:2929:00+07:00","date_modified":"29066-29-09T652:2929:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"e0c37459734a0dc4250c8f0c2d65b6d91b31776e","title":"创新思维与创业管理","summary":"","content_text":"创新思维方式：敢于挑战常规和传统模式，用与众不同的思考方式提出全新的想法或者寻找更好解决方案的思维方式；Think different。\n要做到它需要：\n拆毁心理之墙 多问为什么 第一性原理 多角度看问题 ","content_html":"\u003cp\u003e创新思维方式：敢于挑战常规和传统模式，用与众不同的思考方式提出全新的想法或者寻找更好解决方案的思维方式；Think different。\u003c/p\u003e\n\u003cp\u003e要做到它需要：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e拆毁心理之墙\u003c/li\u003e\n\u003cli\u003e多问为什么\u003c/li\u003e\n\u003cli\u003e第一性原理\u003c/li\u003e\n\u003cli\u003e多角度看问题\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/entrepreneurship/","date_published":"27066-27-09T644:2727:00+07:00","date_modified":"27066-27-09T644:2727:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"2a03dbca8bbae2f3864d9e2d7fde69a5304ba94c","title":"Node Trick 1","summary":"","content_text":"在Node项目中，要运行npm install，必须要存在package.json。\n如果是手动从零新建一个项目，新建package.json后，加入个空的对象。\n// package.json {} 否则，运行npm install foo会报错。\n或是用npm init -y来创建，参数-y避免在创建创木时需要回答的一些交互问题。\n","content_html":"\u003cp\u003e在Node项目中，要运行npm install，必须要存在package.json。\u003c/p\u003e\n\u003cp\u003e如果是手动从零新建一个项目，新建package.json后，加入个空的对象。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// package.json\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e{}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e否则，运行npm install foo会报错。\u003c/p\u003e\n\u003cp\u003e或是用npm init -y来创建，参数-y避免在创建创木时需要回答的一些交互问题。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/node-trick-1/","date_published":"26066-26-09T632:2626:00+07:00","date_modified":"26066-26-09T632:2626:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"7d43d65df7295981cbce3c94faf2c1d16042a5c7","title":"ETF并不一定是指数ETF","summary":"","content_text":"ETF (Exchange-Traded Funds)被翻译为“交易所挂牌基金”或是“交易所交易基金”。\n不要误认为ETF就是挂钩某个指数(index)的ETF，甚至是宽基指数(broadband index)。\n比如KWEB挂钩某个小众指数 — 中证海外中国互联网指数(CSI Overseas China Internet Index)。\n","content_html":"\u003cp\u003eETF (Exchange-Traded Funds)被翻译为“交易所挂牌基金”或是“交易所交易基金”。\u003c/p\u003e\n\u003cp\u003e不要误认为ETF就是挂钩某个指数(index)的ETF，甚至是宽基指数(broadband index)。\u003c/p\u003e\n\u003cp\u003e比如\u003ca href=\"https://kraneshares.com/kweb/\"\u003eKWEB\u003c/a\u003e挂钩某个小众指数 — 中证海外中国互联网指数(CSI Overseas China Internet Index)。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/etf-might-not--be-index-etf/","date_published":"25066-25-09T659:2525:00+07:00","date_modified":"25066-25-09T659:2525:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"4fff9e86d6fb1fbe268bc1b8b8dfa921e954502e","title":"CMU: Intro to Ml Notes","summary":"","content_text":"第一课 Artificial Intelligence (AI): Getting Computers to Behave Intelligently\nDo things that people do well (better than computers) A moving target! But usually involves:\nPerceptron Control Planning Human language (recognize, understand, respond to, generate) Example Tasks: Identify objects in an image Translate from one huamn language to another Recognoize speech Assess risk (e.g. in loan application) \u0026hellip; 1st Attempt: \u0026ldquo;Knowledge-Based AI\u0026rdquo; (1960s — 1980s) = Write programs that simulate how people do it. Problems:\nWill never get better than a person Requires deep introspection Sometimes requires experts (\u0026ldquo;expert systems\u0026rdquo;, \u0026ldquo;knowledge elicitation\u0026rdquo;) Often we don\u0026rsquo;t know how we do things (e.g. ride bicycle) Difference between knowing and knowing-how-we-know Sometimes we think we know, but we\u0026rsquo;re wrong Didn\u0026rsquo;t work as well as hoped.\nAlternative: \u0026ldquo;Data-Based AI\u0026rdquo; (a.k.a Machine Learning) (1980s — today) = Write programs that learn the task from examples.\nYou don\u0026rsquo;t need to know how to do it yourself Performance (should) improve with more examples But:\nNeed lots of examples! (millions and billions) When it finally works, you may not understand how Lecture 2 ML: Learn a task from experience (examples)\nGet better at the task with experience Medical Diagnosis: f: Patient Info -\u0026gt; {Categories}, Classification\nPredict Tomorrow\u0026rsquo;s Temperature f: (Input) -\u0026gt; R, Regular Regression\nML = Learning a function.\n","content_html":"\u003ch1 id=\"第一课\"\u003e第一课\u003c/h1\u003e\n\u003cp\u003eArtificial Intelligence (AI): Getting Computers to Behave Intelligently\u003c/p\u003e\n\u003cp\u003eDo things that people do well (better than computers)\nA moving target! But usually involves:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePerceptron\u003c/li\u003e\n\u003cli\u003eControl\u003c/li\u003e\n\u003cli\u003ePlanning\u003c/li\u003e\n\u003cli\u003eHuman language (recognize, understand, respond to, generate)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"example-tasks\"\u003eExample Tasks:\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eIdentify objects in an image\u003c/li\u003e\n\u003cli\u003eTranslate from one huamn language to another\u003c/li\u003e\n\u003cli\u003eRecognoize speech\u003c/li\u003e\n\u003cli\u003eAssess risk (e.g. in loan application)\u003c/li\u003e\n\u003cli\u003e\u0026hellip;\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"1st-attempt-knowledge-based-ai-1960s--1980s\"\u003e1st Attempt: \u0026ldquo;Knowledge-Based AI\u0026rdquo; (1960s — 1980s)\u003c/h3\u003e\n\u003cp\u003e= Write programs that simulate how people do it.\nProblems:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWill never get better than a person\u003c/li\u003e\n\u003cli\u003eRequires deep introspection\u003c/li\u003e\n\u003cli\u003eSometimes requires experts (\u0026ldquo;expert systems\u0026rdquo;, \u0026ldquo;knowledge elicitation\u0026rdquo;)\u003c/li\u003e\n\u003cli\u003eOften we don\u0026rsquo;t know how we do things (e.g. ride bicycle)\n\u003cul\u003e\n\u003cli\u003eDifference between knowing and knowing-how-we-know\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eSometimes we \u003cem\u003ethink\u003c/em\u003e we know, but we\u0026rsquo;re wrong\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDidn\u0026rsquo;t work as well as hoped.\u003c/p\u003e\n\u003ch3 id=\"alternative-data-based-ai-aka-machine-learning-1980s--today\"\u003eAlternative: \u0026ldquo;Data-Based AI\u0026rdquo; (a.k.a Machine Learning) (1980s — today)\u003c/h3\u003e\n\u003cp\u003e= Write programs that learn the task from examples.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eYou don\u0026rsquo;t need to know how to do it yourself\u003c/li\u003e\n\u003cli\u003ePerformance (should) improve with more examples\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eBut:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eNeed lots of examples! (millions and billions)\u003c/li\u003e\n\u003cli\u003eWhen it finally works, you may not understand how\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"lecture-2\"\u003eLecture 2\u003c/h1\u003e\n\u003cp\u003eML: Learn a task from experience (examples)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eGet better at the task with experience\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eMedical Diagnosis:\nf: Patient Info -\u0026gt; {Categories}, Classification\u003c/p\u003e\n\u003cp\u003ePredict Tomorrow\u0026rsquo;s Temperature\nf: (Input) -\u0026gt; R, Regular Regression\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eML = Learning a function.\u003c/strong\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/cmu-intro-to-ml/","date_published":"26046-26-09T424:2626:00-06:00","date_modified":"26046-26-09T424:2626:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"85f9ec0f8f1d93198a475982c2f4d27b5e181e4a","title":"Spring Security in Action 2 Notes","summary":"","content_text":"Chapter 2 For the apps that you develop with the Spring Framework, Spring Security is an excellent choice for application-level security.\nTo customize the handling of authentication and authorization, we’ll need to define a bean of type SecurityFilterChain.\nAn object that implements a UserDetailsService interface with Spring Security manages the details about users.\nIt is good practice to separate the responsibilities even for the configuration classes.\n","content_html":"\u003ch1 id=\"chapter-2\"\u003eChapter 2\u003c/h1\u003e\n\u003cp\u003eFor the apps that you develop with the Spring Framework, Spring Security is an excellent choice for application-level\nsecurity.\u003c/p\u003e\n\u003cp\u003eTo customize the handling of authentication and authorization, we’ll need to define a bean of type SecurityFilterChain.\u003c/p\u003e\n\u003cp\u003eAn object that implements a \u003ccode\u003eUserDetailsService\u003c/code\u003e interface with Spring Security manages the details about users.\u003c/p\u003e\n\u003cp\u003eIt is good practice to separate the responsibilities even for the configuration classes.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/spring-security-in-action-2-notes/","date_published":"24036-24-09T349:2424:00-06:00","date_modified":"24036-24-09T349:2424:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"e2833a8e4392e3e0ffabef775b37e524a70b59dd","title":"MongoDB in Action 2笔记","summary":"","content_text":"Chapter 1 Perhaps the biggest reason developers use MongoDB isn\u0026rsquo;t because of its scaling strategy, but because of its intuitive data model. MongoDB stores its information in documents rather than rows.\nA document-based data model can represent rich, hierarchical data structures. It\u0026rsquo;s often possible to do without the multitable joins common to relational databases.\n\u0026hellip; the distinction between a tabular and object representation of data \u0026hellip;\nThe umbrella term NoSQL 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.\nThe 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.\nInternally, MongoDB stores documents in a format called Binary JSON, or BSON.\nBSON has a similar structure (of JSON) but is intended for storing many documents.\nWhere relational databases have tables, MongoDB has collections.\nThe data in a collection is stored to disk, and most queries require you to specify which collection you\u0026rsquo;d like to target.\nThe technique of separating an object\u0026rsquo;s data into multiple tables is known as normalization. A normalized data set, among other things, ensures that each unit of data is represented in one place only.\nBut strict normalization isn\u0026rsquo;t without its costs. Notably, some assembly is required.\nA document-oriented data model naturally represents data in an aggregate form, allowing you to work with an object holistically.\nMongoDB 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.\nYour application code, and not the database, enforces the data\u0026rsquo;s structure.\nTo say that a system supports ad hoc queries (即席查询) 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.\nOne of MongoDB’s design goals is to preserve most of the query power that’s been so fundamental to the relational database world.\nWith MongoDB, you can create up to 64 indexes per collection.\nMongoDB provides database replication via a topology known as a replica set.\nReplica sets distribute data across two or more machines for redundancy and automate fail-over in the event of server and network outages.\nSince MongoDB v2.0, journaling 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.\nMongoDB was designed to make horizontal scaling manageable. It does so via a range-based partitioning mechanism, known as sharding, 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.\nThe core database server runs via an executable called mongod. The mongod server process receives commands over a network socket using a custom binary protocol.\nThe MongoDB command shell is a JavaScript-based tool for administering the database and manipulating data. The mongosh executable loads the shell and connects to a specified mongod process, or one running locally by default.\nChapter 2 MongoDB divides collections into separate databases. Unlike the usual overhead that databases produce in the SQL world, databases in MongoDB are just namespaces to distinguish between collections.\nDatabases and collections are created only when documents are first inserted.\nEvery MongoDB document requires an _id, and if one isn\u0026rsquo;t present when the document is created, a special MongoDB ObjectID will be generated and added to the document at that time.\nYou can set your own _id by setting it in the document you insert, the ObjectID is just MongoDB\u0026rsquo;s default.\nA query selector is a document that\u0026rsquo;s used to match against all documents in the collection.\nNote that calling the find method without any argument is equivalent to passing in an empty predicate; db.user.find() is the same as db.users.find({}).\nRather, 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\u0026rsquo;re used to relational databases.\n","content_html":"\u003ch3 id=\"chapter-1\"\u003eChapter 1\u003c/h3\u003e\n\u003cp\u003ePerhaps the biggest reason developers use MongoDB isn\u0026rsquo;t because of its scaling strategy, but because of its intuitive\ndata model. MongoDB stores its information in \u003cstrong\u003edocuments\u003c/strong\u003e rather than rows.\u003c/p\u003e\n\u003cp\u003eA document-based data model can represent rich, hierarchical data structures. It\u0026rsquo;s often possible to do without the\nmultitable joins common to relational databases.\u003c/p\u003e\n\u003cp\u003e\u0026hellip; the distinction between a \u003cstrong\u003etabular\u003c/strong\u003e and \u003cstrong\u003eobject\u003c/strong\u003e representation of data \u0026hellip;\u003c/p\u003e\n\u003cp\u003eThe umbrella term \u003cstrong\u003eNoSQL\u003c/strong\u003e was coined in 2009 to lump together the many relational database gaining in popularity at the\ntime, one of their commonalities being that they use a query language other than SQL.\u003c/p\u003e\n\u003cp\u003eThe most important thing to remember from its history is that MongoDB was intended to be an extremely simple, yet\nflexible, part of a web-application stack.\u003c/p\u003e\n\u003cp\u003eInternally, MongoDB stores documents in a format called Binary JSON, or \u003cstrong\u003eBSON\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eBSON has a similar structure (of JSON) but is intended for storing many documents.\u003c/p\u003e\n\u003cp\u003eWhere relational databases have tables, MongoDB has \u003cstrong\u003ecollections\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThe data in a collection is stored to disk, and most queries require you to specify which collection you\u0026rsquo;d like to\ntarget.\u003c/p\u003e\n\u003cp\u003eThe technique of separating an object\u0026rsquo;s data into multiple tables is known as \u003cstrong\u003enormalization\u003c/strong\u003e. A normalized data set,\namong other things, ensures that each unit of data is represented in one place only.\u003c/p\u003e\n\u003cp\u003eBut strict normalization isn\u0026rsquo;t without its costs. Notably, some \u003cem\u003eassembly\u003c/em\u003e is required.\u003c/p\u003e\n\u003cp\u003eA document-oriented data model naturally represents data in an aggregate form, allowing you to work with an object\nholistically.\u003c/p\u003e\n\u003cp\u003eMongoDB groups documents into collections, containers that don’t impose any sort of schema. In theory, each document in\na collection can have a completely different structure; in practice, a collection’s document will be relatively uniform.\u003c/p\u003e\n\u003cp\u003eYour application code, and not the database, enforces the data\u0026rsquo;s structure.\u003c/p\u003e\n\u003cp\u003eTo say that a system supports \u003cstrong\u003ead hoc queries\u003c/strong\u003e (即席查询) is to say that it isn’t necessary to define in advance what sorts of\nqueries the system will accept. Relational databases have this property; they’ll faithfully execute any well-formed SQL\nquery with any number of conditions.\u003c/p\u003e\n\u003cp\u003eOne of MongoDB’s design goals is to \u003cstrong\u003e\u003cem\u003epreserve\u003c/em\u003e\u003c/strong\u003e most of the query power that’s been so fundamental to the relational\ndatabase world.\u003c/p\u003e\n\u003cp\u003eWith MongoDB, you can create up to 64 indexes per collection.\u003c/p\u003e\n\u003cp\u003eMongoDB provides database replication via a topology known as a \u003cstrong\u003ereplica set\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eReplica sets distribute data across two or more machines for redundancy and automate fail-over in the event of server\nand network outages.\u003c/p\u003e\n\u003cp\u003eSince MongoDB v2.0, \u003cstrong\u003ejournaling\u003c/strong\u003e is enabled by default. With journaling, every write is flushed to the journal file every\n100ms. If the server is ever shut down uncleanly (say, in a power outage), the journal will be used to ensure that\nMongoDB’s data files are restored to a consistent state when you restart the server. This is the safest way to run\nMongoDB.\u003c/p\u003e\n\u003cp\u003eMongoDB was designed to make horizontal scaling manageable. It does so via a range-based partitioning mechanism, known\nas \u003cstrong\u003esharding\u003c/strong\u003e, which automatically manages the distribution of data across nodes. There’s also a hash- and tag-based\nsharding mechanism, but it’s just another form of the range-based sharding mechanism.\u003c/p\u003e\n\u003cp\u003eThe core database server runs via an executable called \u003ccode\u003emongod\u003c/code\u003e. The \u003ccode\u003emongod\u003c/code\u003e server process receives commands over a\nnetwork socket using a custom binary protocol.\u003c/p\u003e\n\u003cp\u003eThe MongoDB command shell is a JavaScript-based tool for administering the database and manipulating data. The \u003ccode\u003emongosh\u003c/code\u003e\nexecutable loads the shell and connects to a specified mongod process, or one running locally by default.\u003c/p\u003e\n\u003ch3 id=\"chapter-2\"\u003eChapter 2\u003c/h3\u003e\n\u003cp\u003eMongoDB divides collections into separate databases. Unlike the usual overhead that databases produce in the SQL world,\ndatabases in MongoDB are just \u003cem\u003enamespaces\u003c/em\u003e to distinguish between collections.\u003c/p\u003e\n\u003cp\u003eDatabases and collections are \u003cem\u003ecreated only\u003c/em\u003e when documents are first inserted.\u003c/p\u003e\n\u003cp\u003eEvery MongoDB document requires an \u003ccode\u003e_id\u003c/code\u003e, and if one isn\u0026rsquo;t present when the document is created, a special MongoDB\n\u003ccode\u003eObjectID\u003c/code\u003e will be generated and added to the document at that time.\u003c/p\u003e\n\u003cp\u003eYou can set your own \u003ccode\u003e_id\u003c/code\u003e by setting it in the document you insert, the \u003ccode\u003eObjectID\u003c/code\u003e is just MongoDB\u0026rsquo;s default.\u003c/p\u003e\n\u003cp\u003eA \u003cstrong\u003equery selector\u003c/strong\u003e is a document that\u0026rsquo;s used to match against all documents in the collection.\u003c/p\u003e\n\u003cp\u003eNote that calling the \u003ccode\u003efind\u003c/code\u003e method without any argument is equivalent to passing in an empty predicate; \u003ccode\u003edb.user.find()\u003c/code\u003e\nis the same as \u003ccode\u003edb.users.find({})\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eRather, the query itself is a document. The idea of representing commands as documents is used often in MongoDB and may\ncome as a surprise if you\u0026rsquo;re used to relational databases.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/notes-on-mongodb-in-action-2/","date_published":"21036-21-09T347:2121:00-06:00","date_modified":"21036-21-09T347:2121:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"2fcdb2e6ab3409b627d13dc20197b52cb074cc2b","title":"Programming in Python","summary":"","content_text":"Lists are an extension of an earlier, more primitive concept called arrays.\nAn older programming concept called a record, which is any data structure that combines several distinct values into an integrated whole.\nThe individual components of a record are generally called fields.\nThe simplest way to represent a record in Python is to use a built-in data structure called tuple, which is used in both computer science and mathematics to refer to an ordered, immutable collection of elements.\nAs 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 destructuring assignment for splitting a tuple into its component elements.\nEncode the information for each record as an object containing the necessary fields, which are more often called attributes in the context of a Python object.\nIn Python, having a reference to an object makes it possible to create new attributes within it.\n","content_html":"\u003cp\u003eLists are an extension of an earlier, more primitive concept called \u003cstrong\u003earrays\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eAn older programming concept called a \u003cstrong\u003erecord\u003c/strong\u003e, which is any data structure that combines several distinct values into\nan integrated whole.\u003c/p\u003e\n\u003cp\u003eThe individual components of a record are generally called \u003cstrong\u003efields\u003c/strong\u003e.\u003c/p\u003e\n\u003cp\u003eThe simplest way to represent a record in Python is to use a built-in data structure called \u003cstrong\u003etuple\u003c/strong\u003e, which is used in both computer science and mathematics to refer to an\nordered, immutable collection of elements.\u003c/p\u003e\n\u003cp\u003eAs it happens, Python programmers rarely refer to the elements of a tuple by their\nindex number because the language offers a convenient syntactic form called\n\u003cstrong\u003edestructuring assignment\u003c/strong\u003e for splitting a tuple into its component elements.\u003c/p\u003e\n\u003cp\u003eEncode the information for each record as an object containing the\nnecessary fields, which are more often called \u003cstrong\u003eattributes\u003c/strong\u003e in the context of a Python\nobject.\u003c/p\u003e\n\u003cp\u003eIn Python, having a reference to an object makes it possible to create new attributes within it.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/programming-in-python/","date_published":"18036-18-09T350:1818:00-06:00","date_modified":"18036-18-09T350:1818:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"a894658bb480282c2340dcecab5301f9454c27b1","title":"Data Serialization Formats Useability","summary":"","content_text":"JSON JSONC JSON5 HJSON YAML TOML XML CSV\n","content_html":"\u003cp\u003eJSON\nJSONC\nJSON5\nHJSON\nYAML\nTOML\nXML\nCSV\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/data-serialization-formats/","date_published":"14036-14-09T311:1414:00-06:00","date_modified":"14036-14-09T311:1414:00-06:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"9ebad8e4ef8f0fdbac58b33619f5f7984cfb72f7","title":"Tableau With Postgres","summary":"","content_text":"","content_html":"","url":"https://danielsunyu.github.io/myblog-site/posts/tableau-with-postgres/","date_published":"8036-08-09T321:88:00-07:00","date_modified":"8036-08-09T321:88:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"6a33a3789d8c4040f8cbc0d3cea8d68c3daf55db","title":"本地安装MongoDB 8.0+","summary":"","content_text":"https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#std-label-install-mdb-community-macos\nmongosh The MongoDB Shell, mongosh, is a JavaScript and Node.js REPL environment for interacting with MongoDB deployments.\nMongoDB Compass 用命令行启动MongoDB服务器 MongoDB needs a folder/directory to store the database.\n启动mongod，需要带上存储路径\n% mongod --dbpath /opt/homebrew/var/mongodb --dbpath参数：Directory for datafiles - defaults to /data/db\n% mongod --config /opt/homebrew/etc/mongod.conf /opt/homebrew/etc/mongod.conf是MongoDB的配置文件\nsystemLog: 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 如果是用homebrew安装的MongoDB，可以这样启动和关闭：\n% brew services start mongodb-community % brew services stop mongodb-community you should be able to directly interact with the MongoDB database by running the command:\n% mongosh 参考 https://web.stanford.edu/class/cs142/install.html\n","content_html":"\u003cp\u003e\u003ca href=\"https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#std-label-install-mdb-community-macos\"\u003ehttps://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/#std-label-install-mdb-community-macos\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"mongosh\"\u003emongosh\u003c/h3\u003e\n\u003cp\u003eThe MongoDB Shell, mongosh, is a JavaScript and Node.js REPL environment for interacting with MongoDB deployments.\u003c/p\u003e\n\u003ch3 id=\"mongodb-compass\"\u003eMongoDB Compass\u003c/h3\u003e\n\u003ch3 id=\"用命令行启动mongodb服务器\"\u003e用命令行启动MongoDB服务器\u003c/h3\u003e\n\u003cp\u003eMongoDB needs a folder/directory to store the database.\u003c/p\u003e\n\u003cp\u003e启动mongod，需要带上存储路径\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e% mongod --dbpath /opt/homebrew/var/mongodb\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e--dbpath\u003c/code\u003e参数：Directory for datafiles - defaults to \u003ccode\u003e/data/db\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e% mongod --config /opt/homebrew/etc/mongod.conf\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e/opt/homebrew/etc/mongod.conf\u003c/code\u003e是MongoDB的配置文件\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-textmate\" data-lang=\"textmate\"\u003esystemLog:\ndestination: file\npath: /opt/homebrew/var/log/mongodb/mongo.log\nlogAppend: true\nstorage:\ndbPath: /opt/homebrew/var/mongodb\nnet:\nbindIp: 127.0.0.1, ::1\nipv6: true\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果是用homebrew安装的MongoDB，可以这样启动和关闭：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e% brew services start mongodb-community\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e% brew services stop mongodb-community\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eyou should be able to directly interact with the MongoDB database by running the command:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e% mongosh\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"参考\"\u003e参考\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://web.stanford.edu/class/cs142/install.html\"\u003ehttps://web.stanford.edu/class/cs142/install.html\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/install-mongodb/","date_published":"5036-05-09T313:55:00-07:00","date_modified":"5036-05-09T313:55:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"3e9fc471be28c53fa7cd1f2ee52e4ee47a439109","title":"安装PostgreSQL","summary":"","content_text":" Postgres似乎是比PostgreSQL更cool的称呼。\n上一份工作一直在和Postgres打交道。本地Mac开发环境里，Postgres跑在了Docker容器中，非侵入式地安装。然后使用DataGrip提供的可视化界面进行数据查询。\n而侵入式地安装Postgres，会把本地文件系统搞得乱糟糟。安装容易卸载难啊。\n如果想geek一些的，推荐在Docker中运行Postgres。\n本地安装 然而在大学课堂里，大部分教授都不懂Docker，所以课堂上要求侵入式地安装Postgres —— 我也老老实实地照做了。\n一种简单的安装方式是直接从Postgres官网下载，在下载页面可找到各平台的Installer安装包。目前最新的版本是17。\n初始安装后，界面只会显示默认的postgres数据库。\n注意，这里是指在Postgres中的一个叫postgres的数据库。\n直接安装Postgres也是有好处的，有一个操作Postgres的极简用户界面。界面上会列出了一个个本地创建的数据库。此外，可以用界面启动、暂停Postgres服务器。\n设置PATH环境变量 此外，安装目录带了许多原生的命令行工具，其中有重要的psql命令。它的所在位置如下：\n/Applications/Postgres.app/Contents/Versions/17/bin/psql 为了在Terminal运行这条命令，要把Postgres的bin目录放入PATH环境变量中。\nexport PATH=$PATH:/Applications/Postgres.app/Contents/Versions/17/bin 这样就能运行psql命令了：\n% psql --version psql (PostgreSQL) 17.4 (Postgres.app) 安装完毕后，与Postgres交互可以从psql命令行开始。需要掌握psql的常用命令。\n请我喝杯咖啡吧！\n完毕\n","content_html":"\u003cblockquote\u003e\n\u003cp\u003ePostgres似乎是比PostgreSQL更cool的称呼。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e上一份工作一直在和Postgres打交道。本地Mac开发环境里，Postgres跑在了Docker容器中，非侵入式地安装。然后使用DataGrip提供的可视化界面进行数据查询。\u003c/p\u003e\n\u003cp\u003e而侵入式地安装Postgres，会把本地文件系统搞得乱糟糟。安装容易卸载难啊。\u003c/p\u003e\n\u003cp\u003e如果想geek一些的，推荐\u003ca href=\"/posts/run-postgres-on-docker/\"\u003e在Docker中运行Postgres\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"本地安装\"\u003e本地安装\u003c/h3\u003e\n\u003cp\u003e然而在大学课堂里，大部分教授都不懂Docker，所以课堂上要求侵入式地安装Postgres —— 我也老老实实地照做了。\u003c/p\u003e\n\u003cp\u003e一种简单的安装方式是直接从Postgres官网下载，在\u003ca href=\"https://www.postgresql.org/download/\"\u003e下载页面\u003c/a\u003e可找到各平台的Installer安装包。目前最新的版本是17。\u003c/p\u003e\n\u003cp\u003e初始安装后，界面只会显示默认的postgres数据库。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意，这里是指在Postgres中的一个叫postgres的数据库。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cfigure\u003e\u003cimg src=\"/images/postgres-ui.png\" width=\"480px\" height=\"360px\"\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e直接安装Postgres也是有好处的，有一个操作Postgres的极简用户界面。界面上会列出了一个个本地创建的数据库。此外，可以用界面启动、暂停Postgres服务器。\u003c/p\u003e\n\u003ch3 id=\"设置path环境变量\"\u003e设置PATH环境变量\u003c/h3\u003e\n\u003cp\u003e此外，安装目录带了许多原生的命令行工具，其中有重要的\u003cstrong\u003epsql\u003c/strong\u003e命令。它的所在位置如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e/Applications/Postgres.app/Contents/Versions/17/bin/psql\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e为了在Terminal运行这条命令，要把Postgres的bin目录放入PATH环境变量中。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eexport\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePATH\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e$PATH\u003c/span\u003e:/Applications/Postgres.app/Contents/Versions/17/bin\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样就能运行psql命令了：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-zsh\" data-lang=\"zsh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e% psql --version\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epsql \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003ePostgreSQL\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e 17.4 \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003ePostgres.app\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装完毕后，与Postgres交互可以从psql命令行开始。需要掌握\u003ca href=\"/posts/essential-psql-commands\"\u003epsql的常用命令\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e请我喝杯咖啡吧！\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.buymeacoffee.com/danielsun\"\u003e\u003cimg src=\"https://tinyurl.com/57dkxa4f\" width=\"120\"/\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e完毕\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/install-postgres/","date_published":"3036-03-09T354:33:00-07:00","date_modified":"3036-03-09T354:33:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"26737983c170c4463d151b7b96095a14b731a624","title":"Learning Numpy","summary":"","content_text":"这是找到的一个NumPy Tutorial https://cs231n.github.io/python-numpy-tutorial/\n","content_html":"\u003cp\u003e这是找到的一个NumPy Tutorial\n\u003ca href=\"https://cs231n.github.io/python-numpy-tutorial/\"\u003ehttps://cs231n.github.io/python-numpy-tutorial/\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/learning-numpy/","date_published":"25026-25-09T239:2525:00-07:00","date_modified":"25026-25-09T239:2525:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"d60444047827a6eb93ab5bbc0805baa3669f0b02","title":"Data Wrangling","summary":"","content_text":"Data Analysis (Wikipedia\u0026rsquo;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.\nData Wrangling (author\u0026rsquo;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.\nData Analysis (Wikipedia): the process of working with and inspecting data to support decision-making.\nData Analysis (author): I view data analysis a subset of the data-wrangling process.\n","content_html":"\u003cp\u003eData Analysis (Wikipedia\u0026rsquo;s definition): the process of converting data, with the help of tools, from one form to another to allow convenient\nconsumption of the data. This includes transformation, aggregation, visualization, and statistics.\u003c/p\u003e\n\u003cp\u003eData Wrangling (author\u0026rsquo;s definition): the whole process of working with data to get it into and through your pipeline, whatever that may be,\nfrom data acquisition to your target audience, whoever they might be.\u003c/p\u003e\n\u003cp\u003eData Analysis (Wikipedia): the process of working with and inspecting data to support decision-making.\u003c/p\u003e\n\u003cp\u003eData Analysis (author): I view data analysis a subset of the data-wrangling process.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/data-wrangling/","date_published":"17016-17-09T119:1717:00-07:00","date_modified":"17016-17-09T119:1717:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"027e17e44740733218086f12c232d2b0b52fbbdc","title":"Monorepo和Microservices","summary":"","content_text":"https://monorepo.tools/\nhttps://www.atlassian.com/git/tutorials/monorepos\nhttps://danluu.com/monorepo/\nhttps://news.ycombinator.com/item?id=33587622\n","content_html":"\u003cp\u003e\u003ca href=\"https://monorepo.tools/\"\u003ehttps://monorepo.tools/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.atlassian.com/git/tutorials/monorepos\"\u003ehttps://www.atlassian.com/git/tutorials/monorepos\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://danluu.com/monorepo/\"\u003ehttps://danluu.com/monorepo/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://news.ycombinator.com/item?id=33587622\"\u003ehttps://news.ycombinator.com/item?id=33587622\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/monorepo-and-microservices/","date_published":"15016-15-09T120:1515:00-07:00","date_modified":"15016-15-09T120:1515:00-07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"a78e0fde06c17ff6fb4dcc45041e5c72fb636fa4","title":"Book Troubleshooting Java","summary":"","content_text":"最近在读一本Larentiu Spilca写的关于Java的调试和性能刨析的书。\n第六章：Identifying resource consumption problems using profiling techniques 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.\n作者推荐VisualVM，一款免费的profiler。此外还可以选：\nJava Mission Control JProfiler A memory leak is when an app stores and keeps references to unused objects.\nLeakCanary\n","content_html":"\u003cp\u003e最近在读一本Larentiu Spilca写的关于Java的调试和性能刨析的书。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://m.media-amazon.com/images/I/61BaCofsSyL._SL1500_.jpg\" width=\"400px\" height=\"720px\"\u003e\n\u003c/figure\u003e\n\n\u003ch1 id=\"第六章identifying-resource-consumption-problems-using-profiling-techniques\"\u003e第六章：Identifying resource consumption problems using profiling techniques\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI 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\nseemingly hopeless problem.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e作者推荐\u003ca href=\"https://visualvm.github.io/index.html\"\u003eVisualVM\u003c/a\u003e，一款免费的profiler。此外还可以选：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://jdk.java.net/jmc/8/\"\u003eJava Mission Control\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.ej-technologies.com/jprofiler\"\u003eJProfiler\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eA memory leak is when an app stores and keeps references to unused objects.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://square.github.io/leakcanary/\"\u003eLeakCanary\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/book-troubleshooting-java/","date_published":"16086-16-09T835:1616:00+08:00","date_modified":"16086-16-09T835:1616:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"db305cbe73e25fdc22f8372663b4b2fae4598ada","title":"MapStruct介绍","summary":"","content_text":" 所谓的成为一位后端工程师，无非就是要掌握一系列的后端技术。学习了一门小的技术，并会拆解它，这样，就朝着后端工程师迈入坚实的一步。\n我司的Spring Boot项目中，有引用一个第三方依赖 — MapStruct，属于工具类的库。\n引用官网的介绍：\nMapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach.\n","content_html":"\u003cblockquote\u003e\n\u003cp\u003e所谓的成为一位后端工程师，无非就是要掌握一系列的后端技术。学习了一门小的技术，并会拆解它，这样，就朝着后端工程师迈入坚实的一步。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e我司的Spring Boot项目中，有引用一个第三方依赖 — \u003ca href=\"https://mapstruct.org/\"\u003eMapStruct\u003c/a\u003e，属于工具类的库。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://mapstruct.org/images/mapstruct.png\" width=\"360px\" height=\"200px\"\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e引用官网的介绍：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based\non a convention over configuration approach.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/mapstruct-introduction/","date_published":"10086-10-09T855:1010:00+08:00","date_modified":"10086-10-09T855:1010:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"401e981033577de7f6b7a1e27ebc24c7fbbadc54","title":"Git笔记","summary":"","content_text":"安装Git\n首次配置Git\nGit从2.28.0版本（2020年7月）开始将默认的初始分支名称从\u0026quot;master\u0026quot;改为\u0026quot;main\u0026quot;。\n","content_html":"\u003cp\u003e\u003ca href=\"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git\"\u003e安装Git\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://git-scm.com/book/en/v2/Getting-Started-Installing-Git\"\u003e首次配置Git\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eGit从2.28.0版本（2020年7月）开始将默认的初始分支名称从\u0026quot;master\u0026quot;改为\u0026quot;main\u0026quot;。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/git-notes/","date_published":"6066-06-09T634:66:00+08:00","date_modified":"6066-06-09T634:66:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"3f5a83f04c473ade0024e3a15849e50cf2b1b798","title":"Leanring Kotlin Coroutines","summary":"","content_text":" Suspending functions, like withContext, can only be called from other suspending functions or inside a coroutine builder.\n对于Kotlin的Coroutines，不应该参考维基百科的协程定义。\nKotlin\u0026rsquo;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.\n","content_html":"\u003cblockquote\u003e\n\u003cp\u003eSuspending functions, like \u003ccode\u003ewithContext\u003c/code\u003e, can only be called from other suspending functions or inside a coroutine builder.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e对于Kotlin的Coroutines，不应该参考维基百科的协程定义。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eKotlin\u0026rsquo;s coroutines are a language-level feature designed for structured concurrency, while operating system coroutines\nare a low-level mechanism for cooperative multitasking provided by the operating system or user-level libraries.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/leanring-kotlin-coroutines/","date_published":"25056-25-09T516:2525:00+08:00","date_modified":"25056-25-09T516:2525:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"8a87b27ea8b14e4e4f05e6d7443bf43fe146434a","title":"学习Kotlin","summary":"","content_text":"Kotlin的杀手锏是与Java的互操作性。\nKotlinx — a set of optional, first-party libraries provided by JetBrains that extend on the base functionality in the Kotlin language and standard library. The Coroutines library is also part of Kotlinx.\nCIO — coroutine-based I/O.\nStructured Concurrency — A paradigm for managing batches of coroutines and handling them collectively as resources.\nasync — 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:\nCoroutines 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.\nKotlin 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.\nCoroutines are based on the idea of functions being able to suspend, meaning that a function can be paused until a long-running operation completes.\nCoroutines 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.\nKotlin does not ship with support for coroutines.\n","content_html":"\u003cp\u003eKotlin的杀手锏是与Java的互操作性。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eKotlinx\u003c/strong\u003e — a set of optional, first-party libraries provided by JetBrains that extend on the base functionality in the\nKotlin language and standard library. The \u003cstrong\u003eCoroutines\u003c/strong\u003e library is also part of Kotlinx.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCIO\u003c/strong\u003e — coroutine-based I/O.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eStructured Concurrency\u003c/strong\u003e — A paradigm for managing batches of coroutines and handling them collectively as resources.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003easync\u003c/strong\u003e — A coroutine builder that can be used as an alternative to launch. Much like launch, async accepts a lambda\nexpression as an argument, which is where you can call other code that suspends. The big difference between these two\nfunctions is their return types:\u003c/p\u003e\n\u003ch1 id=\"coroutines\"\u003eCoroutines\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eUnlike threads, coroutines can execute and wait for the completion of other work without blocking the thread they are\nlaunched on – thanks to the magic of suspending functions.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eKotlin 1.3 introduced stable support for coroutines, but coroutines are not new or exclusive to Kotlin. The concept of\na coroutine dates back to the 1950s, and they have been implemented in many programming languages.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eCoroutines are based on the idea of functions being able to suspend, meaning that a function can be paused until a\nlong-running operation completes.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eCoroutines provide a high-level and safer set of tools to help you build asynchronous code. Under the hood, Kotlin’s\ncoroutines use threads to perform work in parallel, but you often do not have to worry about this detail.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eKotlin does not ship with support for coroutines.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/learning-kotlin/","date_published":"24056-24-09T55:2424:00+08:00","date_modified":"24056-24-09T55:2424:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"f0c4b27012af8e1b055df4c94ffd284469729ac1","title":"F公司的Backend Tech Stack","summary":"","content_text":"很感恩，差不多三月底拿到F公司的的offer，并于4月15日入职。那天是周三，一个值得纪念的日子。\n算来刚满了一月。我想聊聊技术栈。公司主要使用Kotlin和TypeScript\n基础技能： Git：the popular version control system\nDocker\nREST API\nPostman/cURL\nSQL\nIntelliJ IDEA\nGradle\nLinux basics\nTypeScript\nNode.js\nKotlin\n进阶技能 Unit Testing Kotest：Kotest is a flexible and elegant multi-platform test framework for Kotlin with extensive assertions and integrated property testing JUnit 5 Spring Boot\nPostgreSQL\nKafka\\\nGraphQL Expedia™️ GraphQL Kotlin GraphQL Tools：A set of utilities for faster GraphQL development. The Guild/Conductor：A Fully-Featured, Open-Source GraphQL Gateway for Your Project The Guild/GraphQL Codegen：Generate code from your GraphQL schema and operations with a simple CLI Exposed Exposed is a Kotlin SQL database library with two flavors: a lightweight ORM (using DAO) and type-safe SQL (using DSL).\nAWS\nCamunda\n高阶技能 TimescaleDB\nnginx\nFlyway\nTerraform\nKeycloak：一个开源的身份和访问管理系统,提供了完整的认证、授权、用户管理等功能。它是一个独立的认证服务器,可以与多种应用程序集成。\nKubernetes\nTBC\u0026hellip;\n","content_html":"\u003cp\u003e很感恩，差不多三月底拿到F公司的的offer，并于4月15日入职。那天是周三，一个值得纪念的日子。\u003c/p\u003e\n\u003cp\u003e算来刚满了一月。我想聊聊技术栈。公司主要使用Kotlin和TypeScript\u003c/p\u003e\n\u003ch1 id=\"基础技能\"\u003e基础技能：\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"/posts/git-notes\"\u003eGit\u003c/a\u003e：the popular version control system\u003cbr\u003e\nDocker\u003cbr\u003e\nREST API\u003cbr\u003e\nPostman/cURL\u003cbr\u003e\nSQL\u003cbr\u003e\nIntelliJ IDEA\u003cbr\u003e\n\u003ca href=\"https://docs.gradle.org/current/userguide/userguide.html\"\u003eGradle\u003c/a\u003e\u003cbr\u003e\nLinux basics\u003cbr\u003e\nTypeScript\u003cbr\u003e\nNode.js\u003cbr\u003e\n\u003ca href=\"https://kotlinlang.org/\"\u003eKotlin\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"进阶技能\"\u003e进阶技能\u003c/h1\u003e\n\u003ch2 id=\"unit-testing\"\u003eUnit Testing\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://kotest.io/\"\u003eKotest\u003c/a\u003e：Kotest is a flexible and elegant multi-platform test framework for Kotlin with extensive\nassertions and integrated property testing\u003c/li\u003e\n\u003cli\u003eJUnit 5\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSpring Boot\u003cbr\u003e\nPostgreSQL\u003cbr\u003e\nKafka\\\u003c/p\u003e\n\u003ch2 id=\"graphql\"\u003e\u003ca href=\"https://graphql.org/\"\u003eGraphQL\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://opensource.expediagroup.com/graphql-kotlin/docs\"\u003eExpedia™️ GraphQL Kotlin\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://the-guild.dev/graphql/tools\"\u003eGraphQL Tools\u003c/a\u003e：A set of utilities for faster GraphQL development.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://the-guild.dev/graphql/gateway\"\u003eThe Guild/Conductor\u003c/a\u003e：A Fully-Featured, Open-Source\nGraphQL Gateway for Your Project\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://the-guild.dev/graphql/codegen\"\u003eThe Guild/GraphQL Codegen\u003c/a\u003e：Generate code from your GraphQL schema and operations with a simple CLI\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"exposed\"\u003e\u003ca href=\"https://jetbrains.github.io/Exposed/home.html\"\u003eExposed\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eExposed is a Kotlin SQL database library with two flavors: a lightweight ORM (using DAO) and type-safe SQL (using DSL).\u003cbr\u003e\nAWS\u003cbr\u003e\nCamunda\u003c/p\u003e\n\u003ch2 id=\"高阶技能\"\u003e高阶技能\u003c/h2\u003e\n\u003cp\u003eTimescaleDB\u003cbr\u003e\nnginx\u003cbr\u003e\nFlyway\u003cbr\u003e\nTerraform\u003cbr\u003e\n\u003ca href=\"https://www.keycloak.org/\"\u003eKeycloak\u003c/a\u003e：一个开源的身份和访问管理系统,提供了完整的认证、授权、用户管理等功能。它是一个独立的认证服务器,可以与多种应用程序集成。\u003cbr\u003e\n\u003ca href=\"https://kubernetes.io/\"\u003eKubernetes\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eTBC\u0026hellip;\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/company-f-backend-tech-stack/","date_published":"22056-22-09T551:2222:00+08:00","date_modified":"22056-22-09T551:2222:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"7a0b7485bea21cb72bb82ed7e64cf31959347493","title":"新加坡是福利国家吗？","summary":"","content_text":"很多人会认为新加坡不是一个福利国家。它独特的公积金制度，是一个以受雇者薪水作为福利来源的方式。 确实，和西方发达国家在福利上支出相比，新加坡政府每年在福利项目上的支出，仅占总支出的2.15%和GDP的0.49%。 与此相比，美国政府在医疗福利上每年的支出竟高达GDP的17.3%。 这样福利制度的顶层设计，背后的指导思想是极小化福利支出在财政上的负担，让新加坡藉以保持竞争力。 反观很多欧美国家，受雇者一旦失业，可以向政府每月领取失业金，即使不用上班也可以过着体面的生活。当然这样从宏观上看，是降低了社会的竞争力。\n既然新加坡人在医疗和养老上是以自助为基础的，我为何认为它是个福利国家呢？\n原因就在于新加坡独特的公屋制度。按照住建局的公屋制度，每一对新加坡夫妇（有一方得是公民）有生之年，有一次申请新屋(BTO)的机会。 新屋的价格非常低廉，以至于低收入家庭也能够负担得起。 申请新屋大致流程是向住建局提出申请。住建局提供一些候选的地点和户型。其中户型大小和家庭大小有一定关联，人口多的家庭有资格申请较大的户型。 选定后，住建局下单开始兴建新屋。\n经过几十年的密集建设，现在新加坡的23个城镇共有100多万套组屋。1960年，只有9%的新加坡人住在公共住房，如今接近80%，超过90%的组屋居民买下了房子。\n有订单才会建新房，售价均低于市场价格，但要等上至少3、4年才能入住，不过低收入家庭也可以获得大量租房补贴。最新数据显示，组屋数量占新加坡住房总量的73%。\n摘自BBC：https://www.bbc.com/ukchina/simp/vert-cap-46773103\n由于新加坡的600百万人口里，有40%是外国人。这些人通常会租房。 这样公屋屋主就很容易将空余的房间出租给外国人，赚取一定的租金。 现在按照市价，一间单间的房间，租金均价在1000新币。如果能把一套三室户整体出租，租金甚至可以高达4000新币。这实在是一笔可观的收入。\n假若退休之后，这对夫妇选择出国定居，比如赴临近的马来西亚或是泰国养老。他们将整套公屋出租。 租金的收入基本上可以让他们在泰国租到一套房，并能覆盖日常的开销。\n既然按照公屋制度，新加坡人可以以相对低廉的价格获得公寓，那必然可以把赚来的工资分配在别的事项上，比如旅游、医疗、教育\u0026hellip;，这样即使新加坡不是 传统意义上的福利国家，仍然可以过着一定有保障的生活。\n当然，新加坡中产阶级普遍生活质量比不上欧美国家，这个话题将在日后撰文讨论。\n","content_html":"\u003cp\u003e很多人会认为新加坡不是一个福利国家。它独特的公积金制度，是一个以受雇者薪水作为福利来源的方式。\n确实，和西方发达国家在福利上支出相比，新加坡政府每年在福利项目上的支出，仅占总支出的2.15%和GDP的0.49%。\n与此相比，美国政府在医疗福利上每年的支出竟高达GDP的17.3%。\n这样福利制度的顶层设计，背后的指导思想是极小化福利支出在财政上的负担，让新加坡藉以保持竞争力。\n反观很多欧美国家，受雇者一旦失业，可以向政府每月领取失业金，即使不用上班也可以过着体面的生活。当然这样从宏观上看，是降低了社会的竞争力。\u003c/p\u003e\n\u003cp\u003e既然新加坡人在医疗和养老上是以自助为基础的，我为何认为它是个福利国家呢？\u003c/p\u003e\n\u003cp\u003e原因就在于新加坡独特的公屋制度。按照住建局的公屋制度，每一对新加坡夫妇（有一方得是公民）有生之年，有一次申请新屋(BTO)的机会。\n新屋的价格非常低廉，以至于低收入家庭也能够负担得起。\n申请新屋大致流程是向住建局提出申请。住建局提供一些候选的地点和户型。其中户型大小和家庭大小有一定关联，人口多的家庭有资格申请较大的户型。\n选定后，住建局下单开始兴建新屋。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e经过几十年的密集建设，现在新加坡的23个城镇共有100多万套组屋。1960年，只有9%的新加坡人住在公共住房，如今接近80%，超过90%的组屋居民买下了房子。\u003cbr\u003e\n有订单才会建新房，售价均低于市场价格，但要等上至少3、4年才能入住，不过低收入家庭也可以获得大量租房补贴。最新数据显示，组屋数量占新加坡住房总量的73%。\u003cbr\u003e\n\u003cem\u003e摘自BBC：https://www.bbc.com/ukchina/simp/vert-cap-46773103\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e由于新加坡的600百万人口里，有40%是外国人。这些人通常会租房。\n这样公屋屋主就很容易将空余的房间出租给外国人，赚取一定的租金。\n现在按照市价，一间单间的房间，租金均价在1000新币。如果能把一套三室户整体出租，租金甚至可以高达4000新币。这实在是一笔可观的收入。\u003c/p\u003e\n\u003cp\u003e假若退休之后，这对夫妇选择出国定居，比如赴临近的马来西亚或是泰国养老。他们将整套公屋出租。\n租金的收入基本上可以让他们在泰国租到一套房，并能覆盖日常的开销。\u003c/p\u003e\n\u003cp\u003e既然按照公屋制度，新加坡人可以以相对低廉的价格获得公寓，那必然可以把赚来的工资分配在别的事项上，比如旅游、医疗、教育\u0026hellip;，这样即使新加坡不是\n传统意义上的福利国家，仍然可以过着一定有保障的生活。\u003c/p\u003e\n\u003cp\u003e当然，新加坡中产阶级普遍生活质量比不上欧美国家，这个话题将在日后撰文讨论。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/is-singapore-a-welfare-state/","date_published":"19056-19-09T532:1919:00+08:00","date_modified":"19056-19-09T532:1919:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"7b32de59b595d0eb612d1e7af879adfec1a7900e","title":"学习GraphQL","summary":"","content_text":"GraphQL官方文档：https://graphql.org/\nGraphQL over HTTP: https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md\nThe GraphQL-First Philosophy 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.\n","content_html":"\u003cp\u003eGraphQL官方文档：https://graphql.org/\u003c/p\u003e\n\u003cp\u003eGraphQL over HTTP: \u003ca href=\"https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md\"\u003ehttps://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"the-graphql-first-philosophy\"\u003e\u003ca href=\"https://the-guild.dev/graphql/tools/docs/introduction#the-graphql-first-philosophy\"\u003eThe GraphQL-First Philosophy\u003c/a\u003e\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eA specific workflow for developing a GraphQL server, where the GraphQL schema is the first thing you design, and acts\nas the contract between your frontend and backend. It’s not necessarily for everyone, but it can be a great way to get\na server up and running with a very clear separation of concerns.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/learning-graphql/","date_published":"11056-11-09T523:1111:00+08:00","date_modified":"11056-11-09T523:1111:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"186fd54d66d0a1c3be7bd13fb3607cbcaadd0dc5","title":"UBS/TCS的最终轮面试","summary":"","content_text":" What\u0026rsquo;s the Java version used in your project?\nHave you used any recent version of Java?\nWhat frontend framework do you use?\nDo you use Redux to manage state?\nDo you use BDD or TDD for your development?\nHow do you configure your project to enable test coverage?\nWhich directory of your project stores the test configuration?\nElaborate how you carried out your project development?\nDoes your team use Agile/Scrum?\nSolve 215. Kth Largest Element in an Array.\n","content_html":"\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eWhat\u0026rsquo;s the Java version used in your project?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHave you used any recent version of Java?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWhat frontend framework do you use?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDo you use Redux to manage state?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDo you use BDD or TDD for your development?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHow do you configure your project to enable test coverage?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWhich directory of your project stores the test configuration?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eElaborate how you carried out your project development?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDoes your team use Agile/Scrum?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSolve \u003ca href=\"https://leetcode.com/problems/kth-largest-element-in-an-array/description/\"\u003e215. Kth Largest Element in an Array\u003c/a\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/tech/3rd-round-interview-with-ubs/","date_published":"4046-04-09T443:44:00+08:00","date_modified":"4046-04-09T443:44:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"051426e9af1f066539b7db8da12885ab6bff9054","title":"TATA咨询/瑞银的第二轮面试","summary":"","content_text":" 最近的Java版本中引入了哪些变化？\nJava中的record是什么？\n什么是Immutable，它有什么好处？\n如何设计一个Immutable类？\nJava 8带来了哪些变化？\n谈一下ConcurrentHashMap的实现。\nSpring Boot是什么？\n过去用过哪些Spring Boot Starter Dependencies？\n什么是Dependency Injection？\nSpring Boot中有哪几种Depedency Injection？\nSOLID Principles中的L是指哪个原则？\nWrite a function that checks if all elements in an array are odd numbers.\n手写Leetcode 121. Best Time to Buy and Sell Stock\n","content_html":"\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e最近的Java版本中引入了哪些变化？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eJava中的record是什么？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么是Immutable，它有什么好处？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如何设计一个Immutable类？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eJava 8带来了哪些变化？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e谈一下ConcurrentHashMap的实现。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Boot是什么？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e过去用过哪些Spring Boot Starter Dependencies？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么是Dependency Injection？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Boot中有哪几种Depedency Injection？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSOLID Principles中的\u003cstrong\u003eL\u003c/strong\u003e是指哪个原则？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWrite a function that checks if all elements in an array are odd numbers.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e手写\u003ca href=\"https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/\"\u003eLeetcode 121. Best Time to Buy and Sell Stock\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/tcs-interview-round2/","date_published":"28036-28-09T38:2828:00+08:00","date_modified":"28036-28-09T38:2828:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"3f6a0f41cd7a1dbbe1f41e009b9a0f5392a56113","title":"聊聊Spring WebFlux","summary":"","content_text":"先来梳理一下关系。\nReactive Streams Reactive Streams是一个规范，定义了处理异步数据流的标准，包括了发布者(Publisher)、订阅者(Subscriber)、订阅(Subscription)、处理 器(Processor)等核心接口和规则。 它为异步编程提供了一个统一的基础，解决了背压(Back Pressure)等问题。\n详细见：https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.4/README.md\nJava 9 Flow API 此外，Java 9引入的java.util.concurrent.Flow与Reactive Streams在语义上是1：1等价的。\nJDK9 java.util.concurrent.Flow\nThe interfaces available in JDK \u0026gt;= 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 \u0026lt;-\u0026gt; Flow adapter library as well as a TCK compatible directly with the JDK Flow types.\nProject Reactor 而Project Reactor则是这个规范的一种具体实现。它提供了Reactive Streams规范接口的不同实现，以及一组符合 规范的操作符，从而让开发者能够方便地进行响应式编程。\n有关Project Reactor的书很少，分享一本免费的在线电子书。 Unraveling Project Reactor RxJava RxJava 3是一个基于观察者模式的Java编程库，用于实现异步、基于事件的程序。作为Reactive Streams规范的实现之一，RxJava 3遵循了 Reactive Streams的接口和协议。\nSpring WebFlux ","content_html":"\u003cp\u003e先来梳理一下关系。\u003c/p\u003e\n\u003ch1 id=\"reactive-streams\"\u003eReactive Streams\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"http://www.reactive-streams.org/\"\u003eReactive Streams\u003c/a\u003e是一个规范，定义了处理异步数据流的标准，包括了发布者(Publisher)、订阅者(Subscriber)、订阅(Subscription)、处理\n器(Processor)等核心接口和规则。\n它为异步编程提供了一个统一的基础，解决了背压(Back Pressure)等问题。\u003c/p\u003e\n\u003cp\u003e详细见：https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.4/README.md\u003c/p\u003e\n\u003ch1 id=\"java-9-flow-api\"\u003eJava 9 Flow API\u003c/h1\u003e\n\u003cp\u003e此外，Java 9引入的java.util.concurrent.Flow与Reactive Streams在语义上是1：1等价的。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eJDK9 java.util.concurrent.Flow\u003c/em\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe interfaces available in JDK \u0026gt;= 9 java.util.concurrent.Flow, are 1:1 semantically equivalent to their respective\nReactive Streams counterparts. This means that there will be a migratory period, while libraries move to adopt the new\ntypes in the JDK, however this period is expected to be short - due to the full semantic equivalence of the libraries,\nas well as the Reactive Streams \u0026lt;-\u0026gt; Flow adapter library as well as a TCK compatible directly with the JDK Flow types.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"project-reactor\"\u003eProject Reactor\u003c/h1\u003e\n\u003cp\u003e而\u003ca href=\"https://projectreactor.io/\"\u003eProject Reactor\u003c/a\u003e则是这个规范的一种具体实现。它提供了Reactive Streams规范接口的不同实现，以及一组符合\n规范的操作符，从而让开发者能够方便地进行响应式编程。\u003c/p\u003e\n\u003cp\u003e有关Project Reactor的书很少，分享一本免费的\u003ca href=\"https://eherrera.net/project-reactor-course/\"\u003e在线电子书\u003c/a\u003e。\n\u003cfigure\u003e\u003cimg src=\"https://d2sofvawe08yqg.cloudfront.net/unraveling-project-reactor/s_hero2x?1682559252\" width=\"200px\" height=\"360px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eUnraveling Project Reactor\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\u003c/p\u003e\n\u003ch1 id=\"rxjava\"\u003eRxJava\u003c/h1\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/ReactiveX/RxJava\"\u003eRxJava 3\u003c/a\u003e是一个基于观察者模式的Java编程库，用于实现异步、基于事件的程序。作为Reactive Streams规范的实现之一，RxJava 3遵循了\nReactive Streams的接口和协议。\u003c/p\u003e\n\u003ch1 id=\"spring-webflux\"\u003eSpring WebFlux\u003c/h1\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/spring-webflux/","date_published":"28036-28-09T317:2828:00+08:00","date_modified":"28036-28-09T317:2828:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"917b3e03563eff1ddebe7395d052e4a88fd54c82","title":"Beyond Java8","summary":"","content_text":"在入职Grab后就开始专注Kotlin，我就没碰过Java了，所以Java 8之后语言的新变化知之甚少。但有点是肯定的，这门语言变得越来越复杂。\n当时我甚至觉得Kotlin这样新的JVM语言优于Java。Java已经不再是一门值得关注的语言。甚至我觉得我以后不太可能用Java了。\nCompiler 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.\nThere 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.\nNow 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.\n","content_html":"\u003cp\u003e在入职Grab后就开始专注Kotlin，我就没碰过Java了，所以Java 8之后语言的新变化知之甚少。但有点是肯定的，这门语言变得越来越复杂。\u003c/p\u003e\n\u003cp\u003e当时我甚至觉得Kotlin这样新的JVM语言优于Java。Java已经不再是一门值得关注的语言。甚至我觉得我以后不太可能用Java了。\u003c/p\u003e\n\u003cp\u003eCompiler bugs\nAll 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.\u003c/p\u003e\n\u003cp\u003eThere 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.\u003c/p\u003e\n\u003cp\u003eNow 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.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/beyond-java8/","date_published":"25036-25-09T343:2525:00+08:00","date_modified":"25036-25-09T343:2525:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"b21ab3f7a12a3c455eeaef77d5fbefcdfdf37053","title":"Kotlin书单","summary":"","content_text":"从2018年开始使用Kotlin至今，Kotlin已经伴随我在大型Android应用和后端的项目中，成为我主要使用的编程语言。\n除了透过Kotlin官网来学习Kotlin外，以下是我整理的优秀的Kotlin书单。\n第一本入门书 这是一本极佳的入门书。我正是读了它的第一版入门Kotlin的。Kotlin Programming The Big Nerd Ranch Guide, 2nd Edition\n本书出版于2021年底，覆盖了Kotlin 1.5。由于已经有三年，并且Kotlin 2.0也已经发布，我认为大约在2025年会出版该书的第三版。\n读了它的第20章Coroutine，觉得信息量很大。不重复读几遍很难读懂。\n","content_html":"\u003cp\u003e从2018年开始使用Kotlin至今，Kotlin已经伴随我在大型Android应用和后端的项目中，成为我主要使用的编程语言。\u003c/p\u003e\n\u003cp\u003e除了透过Kotlin官网来学习Kotlin外，以下是我整理的优秀的Kotlin书单。\u003c/p\u003e\n\u003ch1 id=\"第一本入门书\"\u003e第一本入门书\u003c/h1\u003e\n\u003cp\u003e这是一本极佳的入门书。我正是读了它的第一版入门Kotlin的。\u003ca href=\"https://bignerdranch.com/books/kotlin-programming-the-big-nerd-ranch-guide-2nd/\"\u003eKotlin Programming The Big Nerd Ranch Guide, 2nd Edition\u003c/a\u003e\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://bignerdranch.com/wp-content/uploads/2021/09/BNR_Kotlin_2E_mech-110241024_1.jpg\" width=\"300px\" height=\"480px\"\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e本书出版于2021年底，覆盖了Kotlin 1.5。由于已经有三年，并且Kotlin 2.0也已经发布，我认为大约在2025年会出版该书的第三版。\u003c/p\u003e\n\u003cp\u003e读了它的第20章Coroutine，觉得信息量很大。不重复读几遍很难读懂。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/kotlin-books/","date_published":"22036-22-09T354:2222:00+08:00","date_modified":"22036-22-09T354:2222:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"6788f5252a09d2b59aef90817aadcbe012ee8e91","title":"阅读「Web 3大趋势」","summary":"","content_text":" 本书的副标题是——日本网路教父教你一次看懂元宇宙、区块链、NFT。本书的作者是伊藤穰一。\n本书以Web 3、元宇宙和NFT作为最重要的三个关键字。\n伊藤给出了他认为最适合的元宇宙的定义——以网路即时沟通为前提，进行某种价值交换的空间。\n","content_html":"\u003cfigure\u003e\u003cimg src=\"/images/web3_book.jpg\" width=\"200px\" height=\"360px\"\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e\u003ca href=\"https://readmoo.com/book/210284743000101\" target=\"_blank\"\u003e本书\u003c/a\u003e的副标题是——日本网路教父教你一次看懂元宇宙、区块链、NFT。本书的作者是伊藤穰一。\u003c/p\u003e\n\u003cp\u003e本书以\u003cstrong\u003eWeb 3\u003c/strong\u003e、\u003cstrong\u003e元宇宙\u003c/strong\u003e和\u003cstrong\u003eNFT\u003c/strong\u003e作为最重要的三个关键字。\u003c/p\u003e\n\u003cp\u003e伊藤给出了他认为最适合的\u003cstrong\u003e元宇宙\u003c/strong\u003e的定义——以网路即时沟通为前提，进行某种价值交换的空间。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/reading-web3-big-trend/","date_published":"21036-21-09T313:2121:00+08:00","date_modified":"21036-21-09T313:2121:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"8ad47a8441e03e3d17fb6db03d25e11473d52ba9","title":"零成本开DBS账户 - My Account","summary":"","content_text":"我一直以为，开通DBS账户需要维持3000新币的最低存款要求，否则会被收取每月5新币的账户管理费。\n这也是为何我去年关闭了我的Multiplier Account。我认为为了拥有DBS账户而维持3000新币划不来。毕竟在高利率时代，3000新币一年能带来100新币的利息。相当于为了持有账户会让我每月损失8新币。\n因为我的Moomoo和Tiger证券账户有美元和港币想要出金，只有DBS是对外币免手续费。主要的原因是Moomoo和Tiger的银行账户是在DBS托管的。\n我本来是打算重新开DBS账户，并存入3000新币。在与DBS的工作人员交涉时，他解释了为何Multiplier Account要维持最低3000元的活期存款。因为只要credit your salaries，这个账户的活期存款有可观的利息收入的。他推荐我（重新）开通这个账户。\n此外，他也提到有一种活期账户（current account）类型叫My Account，且支持多种货币。我欣喜地发现，这个账户没有最低存款要求。他解释道：\nThis account caters to people who can\u0026rsquo;t manage to deposit even hundreds of dollars.\n于是，我开了My Account账户，只存入了50新币，并成功把Tiger上的港币出金到这个账户上，没有收取手续费。\n虽然不知道其他新加坡银行的情况，但我相信也是有这种没有最低存款要求的账户的。\n我会持续更新我的博文，让大家能够以最低成本持有银行账户。\n请我喝杯咖啡吧！\n","content_html":"\u003cp\u003e我一直以为，开通DBS账户需要维持3000新币的最低存款要求，否则会被收取每月5新币的账户管理费。\u003c/p\u003e\n\u003cp\u003e这也是为何我去年关闭了我的Multiplier Account。我认为为了拥有DBS账户而维持3000新币划不来。毕竟在高利率时代，3000新币一年能带来100新币的利息。相当于为了持有账户会让我每月损失8新币。\u003c/p\u003e\n\u003cp\u003e因为我的Moomoo和Tiger证券账户有美元和港币想要出金，只有DBS是对外币免手续费。主要的原因是Moomoo和Tiger的银行账户是在DBS托管的。\u003c/p\u003e\n\u003cp\u003e我本来是打算重新开DBS账户，并存入3000新币。在与DBS的工作人员交涉时，他解释了为何Multiplier Account要维持最低3000元的活期存款。因为只要credit your salaries，这个账户的活期存款有可观的利息收入的。他推荐我（重新）开通这个账户。\u003c/p\u003e\n\u003cp\u003e此外，他也提到有一种活期账户（current account）类型叫\u003cstrong\u003eMy Account\u003c/strong\u003e，且支持\u003cstrong\u003e多种货币\u003c/strong\u003e。我欣喜地发现，这个账户没有最低存款要求。他解释道：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003eThis account caters to people who can\u0026rsquo;t manage to deposit even hundreds of dollars.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e于是，我开了My Account账户，只存入了50新币，并成功把Tiger上的港币出金到这个账户上，没有收取手续费。\u003c/p\u003e\n\u003cp\u003e虽然不知道其他新加坡银行的情况，但我相信也是有这种没有最低存款要求的账户的。\u003c/p\u003e\n\u003cp\u003e我会持续更新我的博文，让大家能够以最低成本持有银行账户。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e请我喝杯咖啡吧！\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.buymeacoffee.com/danielsun\"\u003e\u003cimg src=\"https://tinyurl.com/57dkxa4f\" width=\"120\"/\u003e\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/open-my-account-in-dbs/","date_published":"21036-21-09T315:2121:00+08:00","date_modified":"21036-21-09T315:2121:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"cc1954da4993c1eff0fbefb3f914fe81db6d91c1","title":"新加坡交易所上值得买入的ETFs","summary":"","content_text":"第一个是追踪新加坡海峡时报指数的一款SPDR® Straits Times Index ETF；\n证券代号：ES3\n管理费：0.26%（年）\n交易货币：SGD\n挂牌日： 2002年4月17日\n规模：15亿新币\n派息率：4.60%\n派息日：每年的2月和8月\n","content_html":"\u003cp\u003e第一个是追踪\u003ca href=\"https://en.wikipedia.org/wiki/Straits_Times_Index\"\u003e新加坡海峡时报指数\u003c/a\u003e的一款\u003ca href=\"https://www.ssga.com/sg/en/institutional/etfs/funds/spdr-straits-times-index-etf-es3\"\u003eSPDR® Straits Times Index ETF\u003c/a\u003e；\u003c/p\u003e\n\u003cp\u003e证券代号：ES3\u003c/p\u003e\n\u003cp\u003e管理费：0.26%（年）\u003c/p\u003e\n\u003cp\u003e交易货币：SGD\u003c/p\u003e\n\u003cp\u003e挂牌日： 2002年4月17日\u003c/p\u003e\n\u003cp\u003e规模：15亿新币\u003c/p\u003e\n\u003cp\u003e派息率：4.60%\u003c/p\u003e\n\u003cp\u003e派息日：每年的2月和8月\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/etfs-listed-on-sg-stock-exchange/","date_published":"18036-18-09T340:1818:00+08:00","date_modified":"18036-18-09T340:1818:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"44a48f1bbecd205504a10a8d9882db34fffc8304","title":"塔塔咨询服务的Java后端面试记录","summary":"","content_text":"最近面了一家叫Tata Consultancy Services的咨询公司，面试的岗位是Java后端工程师。\n这家国际(印度)咨询公司有许多的客户。我猜这个岗位的客户是UBS。\n面试进行了35分钟左右。这里记录一下面试题。\n面试题围绕着Java、Spring Boot和Microservices展开。\nJava 8（2014年3月发布的）带来了哪些新功能？\nJava接口的default methods有啥作用；Java 8为何要加入这个特性？\n什么是Functional Interfaces？\nJava 8中的HashMap有啥改变？\n解释下Immutability/Immutable？\n如何设计一个Immutable类？比如一个Employee类。\n有一组Employee，每个Employee属于某个Department的集合，如何用Java Stream API找出属于IT Department的所有Employee？\nSpring Boot为Spring framework带来了哪些新特性？\n解释一下@SpringBootApplication的作用。\n解释一下@RestController的作用。\n谈一下Spring Data JPA。\nSpring Boot应用如何做Health Check？\n微服务中的Circuit Breaker是做什么的？\n微服务彼此之间是如何通信的？\n如何设计一个OpenFeign的类？\n什么是Solid Principles？\n什么是Twelve-Factor App？\n","content_html":"\u003cp\u003e最近面了一家叫\u003ca href=\"https://www.tcs.com/\"\u003eTata Consultancy Services\u003c/a\u003e的咨询公司，面试的岗位是Java后端工程师。\u003c/p\u003e\n\u003cp\u003e这家国际(印度)咨询公司有许多的客户。我猜这个岗位的客户是UBS。\u003c/p\u003e\n\u003cp\u003e面试进行了35分钟左右。这里记录一下面试题。\u003c/p\u003e\n\u003cp\u003e面试题围绕着Java、Spring Boot和Microservices展开。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eJava 8（2014年3月发布的）带来了哪些新功能？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eJava接口的default methods有啥作用；Java 8为何要加入这个特性？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么是Functional Interfaces？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eJava 8中的HashMap有啥改变？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解释下Immutability/Immutable？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如何设计一个Immutable类？比如一个Employee类。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e有一组Employee，每个Employee属于某个Department的集合，如何用Java Stream API找出属于IT Department的所有Employee？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Boot为Spring framework带来了哪些新特性？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解释一下@SpringBootApplication的作用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解释一下@RestController的作用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e谈一下Spring Data JPA。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSpring Boot应用如何做Health Check？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e微服务中的\u003ca href=\"https://microservices.io/patterns/reliability/circuit-breaker.html\"\u003eCircuit Breaker\u003c/a\u003e是做什么的？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e微服务彼此之间是如何通信的？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如何设计一个OpenFeign的类？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么是\u003ca href=\"https://simple.wikipedia.org/wiki/SOLID_(object-oriented_design)\"\u003eSolid Principles\u003c/a\u003e？\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么是\u003ca href=\"https://12factor.net/\"\u003eTwelve-Factor App\u003c/a\u003e？\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/an-interview-with-tcs/","date_published":"15036-15-09T335:1515:00+08:00","date_modified":"15036-15-09T335:1515:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"7e7572ceafff08ea0eba164fd12b0c44c6dc55ee","title":"「Spring Security in Action」读书笔记","summary":"","content_text":"Java专家Laurentiu Spilca于2020年出版了「Spring Security in Action」一书。\n这本书以Spring Boot v2.3.0和Java 11版本为基础。\n根据Manning Publications官方和Amazon上的讯息，他将于2024年4月出版本书第二版。\nSpring Security in Action 虽然我没有第二版的书，但是读一下2020年版的应该不会太过时。\n这篇博文记录书中的摘录、我的笔记和感想。\nSpring Security is a framework that belongs to application-level security.\nApplication-level security 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!\nThrough authentication, 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 authorization.\n","content_html":"\u003cp\u003eJava专家Laurentiu Spilca于2020年出版了「Spring Security in Action」一书。\u003c/p\u003e\n\u003cp\u003e这本书以Spring Boot v2.3.0和Java 11版本为基础。\u003c/p\u003e\n\u003cp\u003e根据Manning Publications官方和Amazon上的讯息，他将于2024年4月出版本书第二版。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://images.manning.com/360/480/resize/book/6/e751b54-0e51-4676-b05f-c0f023d152b9/Spilca-Spring-HI.png\" width=\"300px\" height=\"480px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eSpring Security in Action\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e虽然我没有第二版的书，但是读一下2020年版的应该不会太过时。\u003c/p\u003e\n\u003cp\u003e这篇博文记录书中的摘录、我的笔记和感想。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eSpring Security\u003c/strong\u003e is a framework that belongs to \u003cstrong\u003eapplication-level security\u003c/strong\u003e.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eApplication-level security\u003c/strong\u003e 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!\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003eThrough \u003cstrong\u003eauthentication\u003c/strong\u003e, 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 \u003cstrong\u003eauthorization\u003c/strong\u003e.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/reading-spring-security-in-action/","date_published":"14036-14-09T327:1414:00+08:00","date_modified":"14036-14-09T327:1414:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"9567498d2653f16c06ac6b35d1275be6b17e1b29","title":"「Spring Start Here」读书笔记📒","summary":"","content_text":"这本书是我见过质量最好的Spring入门书籍，真的是没有之一，我花了整整两周读完。但是价格要$49.99，真是不便宜啊。\n一直很稀奇，为何Spring这个流行的框架，社区中没有产出香Rails Tutorials那么高质量的入门实作读物。\n此外，作者有些书目的推荐。\n@RestController public class HelloController { @GetMapping(\u0026#34;/hello\u0026#34;) public String hello() { return \u0026#34;Hello!\u0026#34;; } } The @RestController annotation registers the bean in the context and tells Spring that the application uses this instance as a web controller.\n微服务 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.\nMicroservices in Action Microservices Patterns Spring Microservices in Action Microservices Security in Action Monolith to Microservices ","content_html":"\u003cp\u003e这本书是我见过质量最好的Spring入门书籍，真的是没有之一，我花了整整两周读完。但是价格要$49.99，真是不便宜啊。\u003c/p\u003e\n\u003cp\u003e一直很稀奇，为何Spring这个流行的框架，社区中没有产出香Rails Tutorials那么高质量的入门实作读物。\u003c/p\u003e\n\u003cp\u003e此外，作者有些书目的推荐。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003e@RestController\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eHelloController\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75af00\"\u003e@GetMapping\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;/hello\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003ehello\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#d88200\"\u003e\u0026#34;Hello!\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003e@RestController\u003c/code\u003e annotation registers the bean in the context and tells Spring that the application uses this instance as a web controller.\u003c/p\u003e\n\u003ch1 id=\"微服务\"\u003e微服务\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eSoftware 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003col\u003e\n\u003cli\u003eMicroservices in Action\u003c/li\u003e\n\u003cli\u003eMicroservices Patterns\u003c/li\u003e\n\u003cli\u003eSpring Microservices in Action\u003c/li\u003e\n\u003cli\u003eMicroservices Security in Action\u003c/li\u003e\n\u003cli\u003eMonolith to Microservices\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/reading-spring-start-here/","date_published":"12036-12-09T314:1212:00+08:00","date_modified":"12036-12-09T314:1212:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"c1b1af6dde82f195c85cba70f505c653e4f52bb6","title":"Hands on Learning Postgresql","summary":"","content_text":"这是记录我学习的Open Full Stack上的一门小课程Part 13 - Using relational databases。\n这本课程是用PostgreSQL。\n类似Mongoose，这门课程用到了Sequelize。官网的描述是：\nSequelize 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.\nSpring Security in Action 这里首先讲到之前课程用到的MongoDB。\nMongo 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.\nThe \\d command, which tells us what tables are in the database.\npostgres=# \\d List of relations Schema | Name | Type | Owner --------+--------------+----------+---------- public | notes | table | username public | notes_id_seq | sequence | username (2 rows) With the command \\d notes, we can see how the notes table is defined:\npostgres=# \\d notes Table \u0026#34;public.notes\u0026#34; Column | Type | Collation | Nullable | Default -----------+------------------------+-----------+----------+----------------------------------- id | integer | | not null | nextval(\u0026#39;notes_id_seq\u0026#39;::regclass) content | text | | not null | important | boolean | | | date | time without time zone | | | Indexes: \u0026#34;notes_pkey\u0026#34; PRIMARY KEY, btree (id) In practice, a migration 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.\n","content_html":"\u003cp\u003e这是记录我学习的Open Full Stack上的一门小课程\u003ca href=\"https://fullstackopen.com/en/part13\"\u003e\u003cstrong\u003ePart 13 - Using relational databases\u003c/strong\u003e\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e这本课程是用\u003ca href=\"https://www.postgresql.org/\"\u003e\u003cstrong\u003ePostgreSQL\u003c/strong\u003e\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e类似Mongoose，这门课程用到了\u003ca href=\"https://sequelize.org/\"\u003e\u003cstrong\u003eSequelize\u003c/strong\u003e\u003c/a\u003e。官网的描述是：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eSequelize\u003c/strong\u003e 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.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cfigure\u003e\u003cimg src=\"https://sequelize.org/img/logo.svg\" width=\"200px\" height=\"360px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eSpring Security in Action\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e这里首先讲到之前课程用到的MongoDB。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMongo 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eThe \u003ccode\u003e\\d\u003c/code\u003e command, which tells us what tables are in the database.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epostgres=# \\d\n            List of relations\n Schema |     Name     |   Type   |  Owner\n--------+--------------+----------+----------\n public | notes        | table    | username\n public | notes_id_seq | sequence | username\n(2 rows)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWith the command \u003ccode\u003e\\d\u003c/code\u003e notes, we can see how the notes table is defined:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epostgres=# \\d notes\n                                     Table \u0026#34;public.notes\u0026#34;\n  Column   |          Type          | Collation | Nullable |              Default\n-----------+------------------------+-----------+----------+-----------------------------------\n id        | integer                |           | not null | nextval(\u0026#39;notes_id_seq\u0026#39;::regclass)\n content   | text                   |           | not null |\n important | boolean                |           |          |\n date      | time without time zone |           |          |\nIndexes:\n    \u0026#34;notes_pkey\u0026#34; PRIMARY KEY, btree (id)\n\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003eIn practice, a \u003cem\u003emigration\u003c/em\u003e 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.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/hands-on-learning-postgresql/","date_published":"11036-11-09T322:1111:00+08:00","date_modified":"11036-11-09T322:1111:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"4319f1e429ecfbd4a4d77616508a89d5c590a45e","title":"「Redis for Dummies」第二版读书摘要","summary":"","content_text":"Redis is a popular multi-model database server.\nNoSQL数据库有四个主要的类型：key/value、column、document和graph。\n有两个易混淆的术语：\nData Store是专门的数据库系统，提供高效的数据组织和访问能力。\nData Storage是通用的数据存储介质和设备，为Data Store等上层系统提供存储容量。\nDurability is the ability to ensure that data is available in the event of a failure of a database component.\n第三章 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.\nThose 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.\n","content_html":"\u003cp\u003e\u003cstrong\u003eRedis\u003c/strong\u003e is a popular multi-model database server.\u003c/p\u003e\n\u003cp\u003eNoSQL数据库有四个主要的类型：key/value、column、document和graph。\u003c/p\u003e\n\u003cp\u003e有两个易混淆的术语：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eData Store\u003c/strong\u003e是专门的数据库系统，提供高效的数据组织和访问能力。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eData Storage\u003c/strong\u003e是通用的数据存储介质和设备，为Data Store等上层系统提供存储容量。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDurability\u003c/strong\u003e is the ability to ensure that data is available in the event of a failure of a database component.\u003c/p\u003e\n\u003ch1 id=\"第三章\"\u003e第三章\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThere 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThose 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.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/reading-redis-for-dummies-2nd/","date_published":"11036-11-09T330:1111:00+08:00","date_modified":"11036-11-09T330:1111:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"1ee7ba4c5006957cffade19edb43d6c33dea3ca0","title":"学习Redis","summary":"","content_text":"最近打算系统地学习Redis。想花最少的时间快速地入门Redis。尝试在网上搜些优质的资源，结果发现好的不多，整理如下：\n好书 第一本书是「Redis for Dummies」第二版，可以从redis.com官网免费下载。\nRedis for Dummies 我会把读书的笔记整理到一篇博文中。\n第二本叫「Redis in Action」,2013年出版的。这本书居然直到如今都没有更新，可能因为内容并没有过时。\nRedis in Action 配套的源码放在GitHub，并有多种语言的实现。\nRedis云服务提供商 介绍一个叫Redis Cloud的云产品。可以免费试用30天来创建一个数据库，用来学习是足够了。最基本的套餐也只要5美元/月。推荐使用这个云环境使用起来非常方便。我是懒得在本地安装、配置一个Redis实例了。\n工具 推荐从Redis官网下载一款叫RedisInsight的GUI工具。可以直接连接一个本地或是远程的多个Redis实例。\nRedisInsight 此外，黑马程序员的Redis课程也不错。\n认证考试 没想到Redis生态真是健全，还有认证考试，不知道含金量如何。\nClaude AI给我我如下的回复：\nRedis Certification考试的费用和考试方式情况如下: Redis认证考试分为两个级别:Redis Certified Developer（149美元）和Redis Certified Data Persistence Specialist（249美元）。\n","content_html":"\u003cp\u003e最近打算系统地学习Redis。想花最少的时间快速地入门Redis。尝试在网上搜些优质的资源，结果发现好的不多，整理如下：\u003c/p\u003e\n\u003ch1 id=\"好书\"\u003e好书\u003c/h1\u003e\n\u003cp\u003e第一本书是\u003ca href=\"https://redis.com/redis-for-dummies/\"\u003e「Redis for Dummies」\u003c/a\u003e第二版，可以从\u003ca href=\"https://redis.com/\"\u003eredis.com\u003c/a\u003e官网免费下载。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://m.media-amazon.com/images/I/419SUZus\u0026#43;4L.jpg\" width=\"300px\" height=\"480px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eRedis for Dummies\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e我会把读书的笔记整理到一篇博文中。\u003c/p\u003e\n\u003cp\u003e第二本叫\u003ca href=\"https://www.manning.com/books/redis-in-action\"\u003e「Redis in Action」\u003c/a\u003e,2013年出版的。这本书居然直到如今都没有更新，可能因为内容并没有过时。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://images.manning.com/360/480/resize/book/8/00f2522-76ce-4594-8564-541254e6d8f0/carlson.png\" width=\"300px\" height=\"480px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eRedis in Action\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e配套的源码放在\u003ca href=\"https://github.com/josiahcarlson/redis-in-action/\"\u003eGitHub\u003c/a\u003e，并有多种语言的实现。\u003c/p\u003e\n\u003ch1 id=\"redis云服务提供商\"\u003eRedis云服务提供商\u003c/h1\u003e\n\u003cp\u003e介绍一个叫\u003ca href=\"https://redis.com/cloud/overview/\"\u003eRedis Cloud\u003c/a\u003e的云产品。可以免费试用30天来创建一个数据库，用来学习是足够了。最基本的套餐也只要5美元/月。推荐使用这个云环境使用起来非常方便。我是懒得在本地安装、配置一个Redis实例了。\u003c/p\u003e\n\u003ch1 id=\"工具\"\u003e工具\u003c/h1\u003e\n\u003cp\u003e推荐从Redis官网下载一款叫\u003ca href=\"https://redis.com/redis-enterprise/redis-insight/\"\u003eRedisInsight\u003c/a\u003e的GUI工具。可以直接连接一个本地或是远程的多个Redis实例。\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://redis.com/wp-content/uploads/2022/11/redisinsight-dashboard-illustration-2.svg?\u0026amp;auto=webp\u0026amp;quality=85,75\u0026amp;width=600\" width=\"600px\"\u003e\u003cfigcaption\u003e\n      \u003ch4\u003eRedisInsight\u003c/h4\u003e\n    \u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e此外，黑马程序员的Redis课程也不错。\u003c/p\u003e\n\u003ch1 id=\"认证考试\"\u003e认证考试\u003c/h1\u003e\n\u003cp\u003e没想到Redis生态真是健全，还有\u003ca href=\"https://university.redis.com/certification/\"\u003e认证考试\u003c/a\u003e，不知道含金量如何。\u003c/p\u003e\n\u003cp\u003eClaude AI给我我如下的回复：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eRedis Certification考试的费用和考试方式情况如下:\nRedis认证考试分为两个级别:Redis Certified Developer（149美元）和Redis Certified Data\nPersistence Specialist（249美元）。\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/learning-redis/","date_published":"10036-10-09T352:1010:00+08:00","date_modified":"10036-10-09T352:1010:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"11887efdb87d69ebc81db0403172dd12ff3a4a9e","title":"Introduction to JDBC","summary":"","content_text":"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.\nThis document draws from the official Sun tutorial on JDBC Basics.\n","content_html":"\u003cp\u003eThis 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.\u003c/p\u003e\n\u003cp\u003eThis document draws from the official Sun tutorial on JDBC Basics.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/jdbc/","date_published":"22026-22-09T212:2222:00+08:00","date_modified":"22026-22-09T212:2222:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"04970a523d0a573d534bba25884a319b421413df","title":"Head First SQL的精要","summary":"","content_text":"这是一本很好的SQL入门书。\n很好的SQL练习题：https://leetcode.com/studyplan/top-sql-50/\n第一章\nSQL is case-insensitive. But it\u0026rsquo;s considered a good programming practice in SQL.\nCREATE DATABASE gregs_list; The semicolon is there to indicate that the command has ended.\nTIMESTAMP is usually used to capture the current time. DATETIME is best used to store a future event.\nDESC命令 To see how my_contacts table you created looks, you can use the DESC command to view it:\nDESC my_contacts; DESC is short for DESCRIBE.\nINSERT语句 INSERT INTO your_table (column_name1, column_name2,...) VALUES (\u0026#39;value1\u0026#39;, \u0026#39;value2\u0026#39;,...); IMPORTANT: the values need to be in the same order as the column names.\nAny value that goes into a VARCHAR, CHAR, DATE, or BLOB column has single quotes around it.\nNULL相当于undefined。\nYou can’t compare one NULL to another. A value can be NULL, but it never equals NULL because NULL is an undefined value!\n第四章 LIKE isn’t specific enough to target precise data.\n\u0026hellip; consider how much room on your hard drive it will take up when your database grows to an enormous size.\nCartesian join（亦称Cross join或Cartesian product） 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.\nAn outer joins returns all rows from one of the tables, along with matching information from another table.\n","content_html":"\u003cp\u003e这是一本很好的SQL入门书。\u003c/p\u003e\n\u003cp\u003e很好的SQL练习题：https://leetcode.com/studyplan/top-sql-50/\u003c/p\u003e\n\u003cp\u003e第一章\u003c/p\u003e\n\u003cp\u003eSQL is case-insensitive. But it\u0026rsquo;s considered a good programming practice in SQL.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eCREATE\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eDATABASE\u003c/span\u003e \u003cspan style=\"color:#111\"\u003egregs_list\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003cstrong\u003esemicolon\u003c/strong\u003e is there to indicate that the command has ended.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTIMESTAMP\u003c/strong\u003e is usually used to capture the current time. \u003cstrong\u003eDATETIME\u003c/strong\u003e is best used to store a future event.\u003c/p\u003e\n\u003ch1 id=\"desc命令\"\u003eDESC命令\u003c/h1\u003e\n\u003cp\u003eTo see how \u003cem\u003emy_contacts\u003c/em\u003e table you created looks, you can use the \u003cstrong\u003eDESC\u003c/strong\u003e command to view it:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eDESC\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emy_contacts\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eDESC\u003c/strong\u003e is short for \u003cem\u003eDESCRIBE\u003c/em\u003e.\u003c/p\u003e\n\u003ch1 id=\"insert语句\"\u003eINSERT语句\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eINSERT\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eINTO\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eyour_table\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ecolumn_name1\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ecolumn_name2\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,...)\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eVALUES\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#39;value1\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#d88200\"\u003e\u0026#39;value2\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,...);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIMPORTANT: the values need to be in the same order as the column names.\u003c/p\u003e\n\u003cp\u003eAny value that goes into a VARCHAR, CHAR, DATE, or BLOB column has single quotes around it.\u003c/p\u003e\n\u003cp\u003eNULL相当于undefined。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eYou can’t compare one NULL to another. A value can be NULL, but it never equals NULL because NULL is an undefined value!\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"第四章\"\u003e第四章\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003eLIKE\u003c/strong\u003e isn’t specific enough to target precise data.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u0026hellip; consider how much room on your hard drive it will take up when your database grows to an enormous size.\u003c/em\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"cartesian-join亦称cross-join或cartesian-product\"\u003eCartesian join（亦称Cross join或Cartesian product）\u003c/h1\u003e\n\u003cp\u003eA 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.\u003c/p\u003e\n\u003cp\u003eAn \u003cb\u003eouter joins\u003c/b\u003e returns all rows from one of the tables, along with matching information from another table.\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/head_first_sql_gist/","date_published":"17026-17-09T230:1717:00+08:00","date_modified":"17026-17-09T230:1717:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"67f5d3c7e1bc6eb39838c53d2a5718cec130146c","title":"Spring的容器中获取Bean","summary":"","content_text":"默认情况下，Spring项目启动时，会把Beans都创建好放在IOC容器中。如果想要主动获取这些Beans，可以通过如下方式：\n根据name获取Bean Object getBean(String name); 根据类型获取Bean \u0026lt;T\u0026gt; T getBean(Class\u0026lt;T\u0026gt; requiredType); 根据name获取Bean（带类型转换） \u0026lt;T\u0026gt; T getBean(String name, Class\u0026lt;T\u0026gt; requiredType); ","content_html":"\u003cp\u003e默认情况下，Spring项目启动时，会把Beans都创建好放在IOC容器中。如果想要主动获取这些Beans，可以通过如下方式：\u003c/p\u003e\n\u003ch2 id=\"根据name获取bean\"\u003e根据name获取Bean\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eObject\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003egetBean\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"根据类型获取bean\"\u003e根据类型获取Bean\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003egetBean\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eClass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003erequiredType\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"根据name获取bean带类型转换\"\u003e根据name获取Bean（带类型转换）\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003egetBean\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ename\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eClass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003erequiredType\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/spring-bean-management/","date_published":"14026-14-09T240:1414:00+08:00","date_modified":"14026-14-09T240:1414:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"63e2561f6200ac496cc71da65a054bf717401733","title":"在中国，使用npm需要替换registry","summary":"","content_text":"是在国外开始把玩Node.js，回国后发现npm install速度很慢\u0026hellip;\n这又是一个解决别的制度不存在的问题…\n总之，npm默认的registry是 https://registry.npmjs.org 。可是在中国，这个源似乎访问速度很慢。\nnpm config get registry 可以返回当前源设置\n设置淘宝源：\nnpm config set registry https://registry.npmmirror.com ","content_html":"\u003cp\u003e是在国外开始把玩Node.js，回国后发现npm install速度很慢\u0026hellip;\u003c/p\u003e\n\u003cp\u003e这又是一个解决别的制度不存在的问题…\u003c/p\u003e\n\u003cp\u003e总之，npm默认的registry是 \u003ca href=\"https://registry.npmjs.org\"\u003ehttps://registry.npmjs.org\u003c/a\u003e 。可是在中国，这个源似乎访问速度很慢。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003enpm config get registry\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e可以返回当前源设置\u003c/p\u003e\n\u003cp\u003e设置淘宝源：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003enpm config set registry https://registry.npmmirror.com\n\u003c/code\u003e\u003c/pre\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/switch-npm-registry-in-china/","date_published":"2016-02-09T110:22:00+08:00","date_modified":"2016-02-09T110:22:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"41bc3ae7e8ba9c213a3b9505d7b172d83c676194","title":"JavaScript怪癖","summary":"","content_text":"1. JavaScript里的空指针异常其实是一种TypeError null.toString(); 回显\n\u0026#34;TypeError: Cannot read property \u0026#39;toString\u0026#39; of null\u0026#34; ","content_html":"\u003ch3 id=\"1-javascript里的空指针异常其实是一种typeerror\"\u003e1. \u003ccode\u003eJavaScript\u003c/code\u003e里的空指针异常其实是一种\u003ccode\u003eTypeError\u003c/code\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003enull\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003etoString\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e回显\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-textmate\" data-lang=\"textmate\"\u003e\u0026#34;TypeError: Cannot read property \u0026#39;toString\u0026#39; of null\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/javascript-quirks/","date_published":"15046-15-09T452:1515:00+08:00","date_modified":"15046-15-09T452:1515:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"412d7867e7f9f45ed85d47f2ca202d6ef2af010b","title":"超有用的Flutter命令行","summary":"","content_text":"自动生成的代码 flutter packages pub run build_runner build --delete-conflicting-outputs 获取依赖 flutter pub get 静态分析 flutter analyze 格式化 flutter format -n --set-exit-if-changed path/to/project --line-length 140 ","content_html":"\u003ch2 id=\"自动生成的代码\"\u003e自动生成的代码\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eflutter packages pub run build_runner build --delete-conflicting-outputs\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"获取依赖\"\u003e获取依赖\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eflutter pub get\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"静态分析\"\u003e静态分析\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eflutter analyze\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"格式化\"\u003e格式化\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eflutter format -n --set-exit-if-changed path/to/project --line-length \u003cspan style=\"color:#ae81ff\"\u003e140\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/useful-flutter-commands/","date_published":"14046-14-09T451:1414:00+08:00","date_modified":"14046-14-09T451:1414:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"0baf5c49d71d33b61905095aa3b0194a01ebc036","title":"用命令行在iOS模拟器上打开Deeplink","summary":"","content_text":"比想象中简单，只需要打开Terminal输入如下咒语：\nxcrun simctl openurl booted \u0026#34;some url\u0026#34; ","content_html":"\u003cp\u003e比想象中简单，只需要打开Terminal输入如下咒语：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003excrun simctl openurl booted \u003cspan style=\"color:#d88200\"\u003e\u0026#34;some url\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/launch-deeplink-on-ios-simulator/","date_published":"4046-04-09T455:44:00+08:00","date_modified":"4046-04-09T455:44:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"dcb372713e62a7216daf7d34d60afde33b9d839d","title":"在Big Sur上安装Ruby的经历","summary":"","content_text":"TL;DR: macOS Big Sur貌似对安装Ruby不太友好。不推荐rvm；推荐rbenv\u0026hellip;\n我是在macOS Big Sur上安装Ruby的，从来没有那么折腾过，花费了大半天时间。最后虽然安装成功，但却有很多点值得记录。 这是是要安装2.7.5版本，LTS版本。输入ruby -v后会发现Mac是自带Ruby的，只是版本滞后，满足不了灵活需要。\n最好不要直接安装Ruby，而是通过Ruby版本管理工具。\n藉rvm安装Ruby 首先尝试安装rvm，用rvm管理不同的本地Ruby版本应该很简单，然而却不然。rvm很容易安装，但要手动设置环境变量。 具体步骤可以参考RVM官网。\nYouTube上有个很好的视频讲解\n安装某个Ruby版本只要rvm install 2.7.5；安装后设置成默认是用rvm --default use 2.7.5 ，但是却报错。\n藉rbenv安装Ruby rbenv似乎没有官方主页，只有Github项目地址\nbrew install rbenv 然后\nrbenv install 2.7.5 这条命令居然也失败了\u0026hellip;\n参考了这篇Github Gist，找到了解决方法。\nRUBY_CONFIGURE_OPTS=\u0026#34;--with-openssl-dir=$(brew --prefix openssl@1.1)\u0026#34; RUBY_CFLAGS=\u0026#34;-w\u0026#34; rbenv install 2.7.5 然后\nrbenv global 2.7.5 关闭Terminal后，ruby -v还是输出老版本，设置一下环境变量\nexport PATH=\u0026#34;$HOME/.rbenv/bin:$PATH\u0026#34; eval \u0026#34;$(rbenv init -)\u0026#34; ","content_html":"\u003cp\u003e\u003cstrong\u003eTL;DR\u003c/strong\u003e: macOS Big Sur貌似对安装Ruby不太友好。不推荐\u003ccode\u003ervm\u003c/code\u003e；推荐\u003ccode\u003erbenv\u003c/code\u003e\u0026hellip;\u003c/p\u003e\n\u003cp\u003e我是在macOS Big Sur上安装Ruby的，从来没有那么折腾过，花费了大半天时间。最后虽然安装成功，但却有很多点值得记录。\n这是是要安装\u003ccode\u003e2.7.5\u003c/code\u003e版本，LTS版本。输入\u003ccode\u003eruby -v\u003c/code\u003e后会发现Mac是自带Ruby的，只是版本滞后，满足不了灵活需要。\u003c/p\u003e\n\u003cp\u003e最好不要直接安装Ruby，而是通过Ruby版本管理工具。\u003c/p\u003e\n\u003ch2 id=\"藉rvm安装ruby\"\u003e藉rvm安装Ruby\u003c/h2\u003e\n\u003cp\u003e首先尝试安装\u003ca href=\"https://rvm.io/\"\u003ervm\u003c/a\u003e，用rvm管理不同的本地Ruby版本应该很简单，然而却不然。rvm很容易安装，但要手动设置环境变量。\n具体步骤可以参考RVM官网。\u003c/p\u003e\n\u003cp\u003eYouTube上有个很好的\u003ca href=\"https://www.youtube.com/watch?v=SL64tWlpwSE\"\u003e视频讲解\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e安装某个Ruby版本只要\u003ccode\u003ervm install 2.7.5\u003c/code\u003e；安装后设置成默认是用\u003ccode\u003ervm --default use 2.7.5 \u003c/code\u003e，但是却报错。\u003c/p\u003e\n\u003ch2 id=\"藉rbenv安装ruby\"\u003e藉rbenv安装Ruby\u003c/h2\u003e\n\u003cp\u003erbenv似乎没有官方主页，只有\u003ca href=\"https://github.com/rbenv/rbenv#installing-ruby-versions\"\u003eGithub项目地址\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ebrew install rbenv\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erbenv install 2.7.5\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这条命令居然也失败了\u0026hellip;\u003c/p\u003e\n\u003cp\u003e参考了\u003ca href=\"https://gist.github.com/Neutrollized/37841827940b28b27ec2e54abbbcc408\"\u003e这篇Github Gist\u003c/a\u003e，找到了解决方法。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eRUBY_CONFIGURE_OPTS\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;--with-openssl-dir=\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003e$(\u003c/span\u003ebrew --prefix openssl@1.1\u003cspan style=\"color:#00a8c8\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eRUBY_CFLAGS\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;-w\u0026#34;\u003c/span\u003e rbenv install 2.7.5\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erbenv global 2.7.5\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e关闭Terminal后，\u003ccode\u003eruby -v\u003c/code\u003e还是输出老版本，设置一下环境变量\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eexport\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePATH\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e$HOME\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e/.rbenv/bin:\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e$PATH\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eeval\u003c/span\u003e \u003cspan style=\"color:#d88200\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003e$(\u003c/span\u003erbenv init -\u003cspan style=\"color:#00a8c8\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/install-ruby-on-mac/","date_published":"1046-01-09T419:11:00+08:00","date_modified":"1046-01-09T419:11:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"63814b9b81152a2923c4943e2e55991548104b17","title":"Stack in Java","summary":"","content_text":"##前言 堆栈作为最基础的数据结构之一，在Java的最初版本就有了纯粹的标准实现：java.util.Stack。只可惜该实现存在性能缺陷，主要是由于主要的操作都加上了synchronized线程安全保护机制，导致无法被应用于对性能要求颇高的生产环境。\nA 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 stack = new ArrayDeque();\n在Java Collections类发布后就和java.util.Vector类被一起被废弃了，取代之的是java.util.Deque接口。之所以设计成接口，是不想与某一个Deque的实现绑定。Java提供了LinkedList和ArrayDeque即可按照使用场景不同，采纳基于数组或是链表的Deque实现，提供了灵活性。\nDeques 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.\n","content_html":"\u003cp\u003e##前言\n堆栈作为最基础的数据结构之一，在Java的最初版本就有了纯粹的标准实现：\u003ccode\u003ejava.util.Stack\u003c/code\u003e。只可惜该实现存在性能缺陷，主要是由于主要的操作都加上了synchronized线程安全保护机制，导致无法被应用于对性能要求颇高的生产环境。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eA 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\u003cInteger\u003e stack = new ArrayDeque\u003cInteger\u003e();\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在Java Collections类发布后就和\u003ccode\u003ejava.util.Vector\u003c/code\u003e类被一起被废弃了，取代之的是\u003ccode\u003ejava.util.Deque\u003c/code\u003e接口。之所以设计成接口，是不想与某一个\u003ccode\u003eDeque\u003c/code\u003e的实现绑定。Java提供了\u003ccode\u003eLinkedList\u003c/code\u003e和\u003ccode\u003eArrayDeque\u003c/code\u003e即可按照使用场景不同，采纳基于数组或是链表的\u003ccode\u003eDeque\u003c/code\u003e实现，提供了灵活性。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDeques 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.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/stack-in-java/","date_published":"2096-02-09T917:22:00+08:00","date_modified":"2096-02-09T917:22:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"b100fa99b0d35be661ae661d3da054eb67287c81","title":"how to maintain octopress","summary":"","content_text":"https://www.didiksetiawan.com/blog/2016/06/02/octopress-setup-and-deployment/\n","content_html":"\u003cp\u003e\u003ca href=\"https://www.didiksetiawan.com/blog/2016/06/02/octopress-setup-and-deployment/\"\u003ehttps://www.didiksetiawan.com/blog/2016/06/02/octopress-setup-and-deployment/\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/how-to-maintain-octopress/","date_published":"1096-01-09T919:11:00+08:00","date_modified":"1096-01-09T919:11:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"55aa155a4316200a90ade176846fbf51bc27f20c","title":"top k algorithms","summary":"","content_text":"##背景\n去年面试Facebook时，被问到了一道Top K的问题，这类的问题解法往往具有共通性。今天在LeetCode上又遇到了一道类似的问题，于是网上搜了一下解题思路，摘录留下备用。\nJDK里有一个强大的集合类 \u0026ndash; PriorityQueue，掌握了它的用法便能迎刃而解这类问题。\n值得注意的是PriorityQueue没有继承自List，不具有随机访问第i个元素的方法。\nE get(int index); Given a non-empty array of integers, return the k most frequent elements.\nclass Pair { int num; int count; Pair(int num, int count) { this.num=num; this.count=count; } } public class Solution { public List\u0026lt;Integer\u0026gt; topKFrequent(int[] nums, int k) { //count the frequency for each element HashMap\u0026lt;Integer, Integer\u0026gt; map = new HashMap\u0026lt;Integer, Integer\u0026gt;(); for(int num: nums){ if (map.containsKey(num)) { map.put(num, map.get(num)+1); } else { map.put(num, 1); } } // create a min heap PriorityQueue\u0026lt;Pair\u0026gt; queue = new PriorityQueue\u0026lt;\u0026gt;(new Comparator\u0026lt;Pair\u0026gt;() { public int compare(Pair a, Pair b) { return a.count - b.count; } }); //maintain a heap of size k. for (Map.Entry\u0026lt;Integer, Integer\u0026gt; entry: map.entrySet()) { Pair p = new Pair(entry.getKey(), entry.getValue()); queue.offer(p); if(queue.size() \u0026gt; k) { queue.poll(); } } //get all elements from the heap List\u0026lt;Integer\u0026gt; result = new ArrayList\u0026lt;Integer\u0026gt;(); while(queue.size() \u0026gt; 0) { result.add(queue.poll().num); } //reverse the order Collections.reverse(result); return result; } } ","content_html":"\u003cp\u003e##背景\u003c/p\u003e\n\u003cp\u003e去年面试Facebook时，被问到了一道Top K的问题，这类的问题解法往往具有共通性。今天在LeetCode上又遇到了一道\u003ca href=\"https://leetcode.com/problems/top-k-frequent-words/description/\"\u003e类似的问题\u003c/a\u003e，于是网上搜了一下\u003ca href=\"https://www.programcreek.com/2014/05/leetcode-top-k-frequent-elements-java/\"\u003e解题思路\u003c/a\u003e，摘录留下备用。\u003c/p\u003e\n\u003cp\u003eJDK里有一个强大的集合类 \u0026ndash; \u003cem\u003ePriorityQueue\u003c/em\u003e，掌握了它的用法便能迎刃而解这类问题。\u003c/p\u003e\n\u003cp\u003e值得注意的是\u003cem\u003ePriorityQueue\u003c/em\u003e没有继承自\u003cem\u003eList\u003c/em\u003e，不具有随机访问第i个元素的方法。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eE\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eget\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eindex\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003eGiven a non-empty array of integers, return the k most frequent elements.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003ePair\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ecount\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ecount\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ethis\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ethis\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003ecount\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ecount\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eSolution\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eList\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003etopKFrequent\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[]\u003c/span\u003e \u003cspan style=\"color:#111\"\u003enums\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ek\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e//count the frequency for each element\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eHashMap\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eHashMap\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003efor\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#111\"\u003enums\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#00a8c8\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003econtainsKey\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e))\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eput\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eget\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eput\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// create a min heap\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003ePriorityQueue\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePriorityQueue\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eComparator\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003ecompare\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ea\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ea\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003ecount\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eb\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003ecount\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e//maintain a heap of size k.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eMap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eEntry\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eentry\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eentrySet\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e())\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ep\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ePair\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eentry\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003egetKey\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(),\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eentry\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003egetValue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eoffer\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ep\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#00a8c8\"\u003eif\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003esize\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ek\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003epoll\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e//get all elements from the heap\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eList\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eresult\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eArrayList\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ewhile\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003esize\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#111\"\u003eresult\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eadd\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003equeue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003epoll\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e().\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enum\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e//reverse the order\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eCollections\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003ereverse\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eresult\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eresult\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/top-k-algorithms/","date_published":"1096-01-09T946:11:00+08:00","date_modified":"1096-01-09T946:11:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"b3d710cf2b3d4d9a89a6e14eee4effc0fef4ea2f","title":"Java Concurrency","summary":"","content_text":"为何要同步线程？ 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.\nExecutor: An object that executes submitted Runnable tasks. ExecutorService: A more extensive interface. ThreadPoolExecutor: Provides an extensible thread pool implementation. Executors: Provides convenient factory methods for these Executors.\nAbstractExecutorService: Provides default implementations of ExecutorService execution methods. ScheduledExecutorService: An ExecutorService that can schedule commands to run after a given delay, or to execute periodically.\nExecutorService的生命周期 Active Shutting Down Shutdown Synchronizers (synchronization aids) CyclicBarrier循环屏障: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. Phaser CountDownLatch: 当counter为1时为被用作start signal，为N时为complete signal。 Exchanger Semaphore SynchronousQueue Potential threading problems Deadlock Starvation Livelock Race conditions Concurrent Collections ","content_html":"\u003ch2 id=\"为何要同步线程\"\u003e为何要同步线程？\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eSince 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003eExecutor\u003c/code\u003e: An object that executes submitted \u003ccode\u003eRunnable\u003c/code\u003e tasks. \u003cbr\u003e\n\u003ccode\u003eExecutorService\u003c/code\u003e: A more extensive interface. \u003cbr\u003e\n\u003ccode\u003eThreadPoolExecutor\u003c/code\u003e: Provides an extensible thread pool implementation. \u003cbr\u003e\n\u003ccode\u003eExecutors\u003c/code\u003e: Provides convenient factory methods for these Executors.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eAbstractExecutorService\u003c/code\u003e: Provides default implementations of ExecutorService execution methods. \u003cbr\u003e\n\u003ccode\u003eScheduledExecutorService\u003c/code\u003e: An ExecutorService that can schedule commands to run after a given delay, or to execute periodically.\u003c/p\u003e\n\u003ch2 id=\"executorservice的生命周期\"\u003e\u003ccode\u003eExecutorService\u003c/code\u003e的生命周期\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eActive\u003c/li\u003e\n\u003cli\u003eShutting Down\u003c/li\u003e\n\u003cli\u003eShutdown\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"synchronizers-synchronization-aids\"\u003eSynchronizers (synchronization aids)\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eCyclicBarrier循环屏障: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.\u003c/li\u003e\n\u003cli\u003ePhaser\u003c/li\u003e\n\u003cli\u003eCountDownLatch: 当counter为1时为被用作start signal，为N时为complete signal。\u003c/li\u003e\n\u003cli\u003eExchanger\u003c/li\u003e\n\u003cli\u003eSemaphore\u003c/li\u003e\n\u003cli\u003eSynchronousQueue\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"potential-threading-problems\"\u003ePotential threading problems\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eDeadlock\u003c/li\u003e\n\u003cli\u003eStarvation\u003c/li\u003e\n\u003cli\u003eLivelock\u003c/li\u003e\n\u003cli\u003eRace conditions\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"concurrent-collections\"\u003eConcurrent Collections\u003c/h2\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/java-concurrency/","date_published":"16076-16-09T728:1616:00+07:00","date_modified":"16076-16-09T728:1616:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"be2b5761fe5b07a3e459515e087c3d56c4bffa43","title":"缅甸旅游签证轻松办","summary":"","content_text":"从没想到缅甸签证原来那么好办，当然我指的是电子签证。\n网办缅甸签证的官网\n","content_html":"\u003cp\u003e从没想到缅甸签证原来那么好办，当然我指的是电子签证。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://evisa.moip.gov.mm/index.aspx\"\u003e网办缅甸签证的官网\u003c/a\u003e\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/apply-for-myammar-visa-the-easy-way/","date_published":"29066-29-09T636:2929:00+07:00","date_modified":"29066-29-09T636:2929:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"3379a715b17ab6ed802a91dba14f651507c02e0a","title":"Java中的assert断言","summary":"","content_text":"使用Java已经有了10个年头，难以想象居然很少使用assert关键字。\nOracle官方指南中详细介绍了assert的用法。\nAn 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.\nEach 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.\nExperience 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.\n","content_html":"\u003cp\u003e使用Java已经有了10个年头，难以想象居然很少使用assert关键字。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html\"\u003eOracle官方指南\u003c/a\u003e中详细介绍了assert的用法。\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAn 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eEach 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eExperience 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.\u003c/p\u003e\u003c/blockquote\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/java-assertions/","date_published":"29066-29-09T652:2929:00+07:00","date_modified":"29066-29-09T652:2929:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"2e66495c8a9be205b987817477bc26fa58c3f712","title":"David Pawson《箴言》第一部观感","summary":"","content_text":"箴言这卷书一共有九百条箴言，涵盖人生各个层面，涵盖各种主题。\n圣经上没有世俗这个词，我们不应该使用。\n希腊思想才会把生活划分成神圣和世俗。\n圣经里的智慧和愚昧都不是指智力，而是道德。\n箴言这卷书是在讲如何善用人生，也在讲如何虚度人生，愚昧的人虚度人生。\n我们很容易虚度一生。\n人生很短，经不起你浪费一分一秒；但是人生的长度足够你活出上帝的旨意。\n箴言不是应许。在希伯来语中，箴言的意思是“就像这样”。箴言是对人生一般性的观察。至于应许是特殊的承诺，这两者要分得很清楚。\n智慧就是在某个情况下知道要应用什么箴言。箴言是一般性的常识，但是遇到不同情况的时候，需要有智慧才知道该应用哪一个箴言。\n","content_html":"\u003cp\u003e箴言这卷书一共有九百条箴言，涵盖人生各个层面，涵盖各种主题。\u003c/p\u003e\n\u003cp\u003e圣经上没有世俗这个词，我们不应该使用。\u003c/p\u003e\n\u003cp\u003e希腊思想才会把生活划分成神圣和世俗。\u003c/p\u003e\n\u003cp\u003e圣经里的智慧和愚昧都不是指智力，而是道德。\u003c/p\u003e\n\u003cp\u003e箴言这卷书是在讲如何善用人生，也在讲如何虚度人生，愚昧的人虚度人生。\u003c/p\u003e\n\u003cp\u003e我们很容易虚度一生。\u003c/p\u003e\n\u003cp\u003e人生很短，经不起你浪费一分一秒；但是人生的长度足够你活出上帝的旨意。\u003c/p\u003e\n\u003cp\u003e箴言不是应许。在希伯来语中，箴言的意思是“就像这样”。箴言是对人生一般性的观察。至于应许是特殊的承诺，这两者要分得很清楚。\u003c/p\u003e\n\u003cp\u003e智慧就是在某个情况下知道要应用什么箴言。箴言是一般性的常识，但是遇到不同情况的时候，需要有智慧才知道该应用哪一个箴言。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/david-pawson-provert-part1/","date_published":"23066-23-09T639:2323:00+07:00","date_modified":"23066-23-09T639:2323:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"ae1286ce45590287130d776348a745b04eeec433","title":"Java Date and Time Problem","summary":"","content_text":"https://www.hackerrank.com/challenges/java-date-and-time/problem\n这道算法题使用Java 8的Date \u0026amp; Time API很容易解决了。\npublic class Solution { private static String getDay(String day, String month, String year) { int d = Integer.parseInt(day); int m = Integer.parseInt(month); int y = Integer.parseInt(year); LocalDate date = LocalDate.of(y, m, d); return date.getDayOfWeek().toString(); } public static void main(String[] args) { Scanner in = new Scanner(System.in); String month = in.next(); String day = in.next(); String year = in.next(); System.out.println(getDay(day, month, year)); } } ","content_html":"\u003cp\u003e\u003ca href=\"https://www.hackerrank.com/challenges/java-date-and-time/problem\"\u003ehttps://www.hackerrank.com/challenges/java-date-and-time/problem\u003c/a\u003e\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cp\u003e这道算法题使用Java 8的Date \u0026amp; Time API很容易解决了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eSolution\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003egetDay\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eday\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emonth\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eyear\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ed\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eparseInt\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eday\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003em\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eparseInt\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emonth\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ey\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eInteger\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eparseInt\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eyear\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eLocalDate\u003c/span\u003e \u003cspan style=\"color:#111\"\u003edate\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eLocalDate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ey\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003em\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ed\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003edate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003egetDayOfWeek\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e().\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003etoString\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003emain\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e[]\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eargs\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eScanner\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ein\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003enew\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eScanner\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eSystem\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003ein\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emonth\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ein\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enext\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eday\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ein\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enext\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eString\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eyear\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ein\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enext\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003eSystem\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eout\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eprintln\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003egetDay\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eday\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emonth\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eyear\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/java-date-and-time-problem/","date_published":"22066-22-09T68:2222:00+07:00","date_modified":"22066-22-09T68:2222:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"3589f32b2cb96595eb272360a61e6869e6e30bbe","title":"Git Cookbook","summary":"","content_text":"这个博客包含了在日常开发中经常会使用，但是却不太容易记住的Git命令和用法。\n如何重命名本地和远程分支 如何删除本地和远程分支 如何撤销已被push到远程Git仓库的最新的commit git revert HEAD git push 如何从某个分支cherry-pick一个commit，并生成patch文件 如何stash当前分支本地的修改 git stash 如何unstash本地修改 git stash pop ","content_html":"\u003cp\u003e这个博客包含了在日常开发中经常会使用，但是却不太容易记住的Git命令和用法。\u003c/p\u003e\n\u003ch3 id=\"如何重命名本地和远程分支\"\u003e如何重命名本地和远程分支\u003c/h3\u003e\n\u003ch3 id=\"如何删除本地和远程分支\"\u003e如何删除本地和远程分支\u003c/h3\u003e\n\u003ch3 id=\"如何撤销已被push到远程git仓库的最新的commit\"\u003e如何撤销已被push到远程Git仓库的最新的commit\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit revert HEAD\ngit push\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"如何从某个分支cherry-pick一个commit并生成patch文件\"\u003e如何从某个分支cherry-pick一个commit，并生成patch文件\u003c/h3\u003e\n\u003ch3 id=\"如何stash当前分支本地的修改\"\u003e如何stash当前分支本地的修改\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit stash\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"如何unstash本地修改\"\u003e如何unstash本地修改\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit stash pop\n\u003c/code\u003e\u003c/pre\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/git-cookbook/","date_published":"21066-21-09T67:2121:00+07:00","date_modified":"21066-21-09T67:2121:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"9ca66eda818fd8b43c9ab03a2166561da686f184","title":"Java 8 Date \u0026 Time API","summary":"","content_text":"Android官方文档里\njava.time.temporal: lower level access to the fields. java.time.format: customization options.\nThe 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 \u0026lsquo;Europe/Paris\u0026rsquo;, but they can store an offset like \u0026lsquo;+02:00\u0026rsquo;.\n获取当前月份 Month.from(Instant.now().atZone(ZoneId.of(\u0026#34;Asia/Bangkok\u0026#34;)); Instant An Instant represents a specific moment in time using GMT.\nDaylight Saving Time The United States observes daylight savings time on March 12, 2017, by moving the clocks forward an hour at 2 a.m.\nIn the United States, daylight savings time ends on November 5th, 2017 at 02:00 a.m. and we repeat the previous hour.\n实验如下：\nLocalDate localDate = LocalDate.of(2017, Month.NOVEMBER, 5); LocalTime localTime = LocalTime.of(1, 0); ZoneId zone = ZoneId.of(\u0026#34;America/New_York\u0026#34;); ZonedDateTime z = ZonedDateTime.of(localDate, localTime, zone); for (int i = 0; i \u0026lt; 6; i++) { System.out.println(z.plusHours(i)); } 输出如下：\n2017-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] ","content_html":"\u003cp\u003e\u003ca href=\"https://developer.android.com/reference/java/time/package-summary\"\u003eAndroid官方文档里\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ejava.time.temporal\u003c/code\u003e: lower level access to the fields.     \u003cbr\u003e\n\u003ccode\u003ejava.time.format\u003c/code\u003e: customization options.\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe 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 \u0026lsquo;Europe/Paris\u0026rsquo;, but they can store an offset like \u0026lsquo;+02:00\u0026rsquo;.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"获取当前月份\"\u003e获取当前月份\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eMonth\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003efrom\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eInstant\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003enow\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e().\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eatZone\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eZoneId\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;Asia/Bangkok\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"instant\"\u003eInstant\u003c/h2\u003e\n\u003cp\u003eAn Instant represents a specific moment in time using GMT.\u003c/p\u003e\n\u003ch2 id=\"daylight-saving-time\"\u003eDaylight Saving Time\u003c/h2\u003e\n\u003cp\u003eThe United States observes daylight savings time on March 12, 2017, by moving the clocks forward an hour at 2 a.m.\u003c/p\u003e\n\u003cp\u003eIn the United States, daylight savings time ends on November 5th, 2017 at 02:00 a.m. and we repeat the previous hour.\u003c/p\u003e\n\u003cp\u003e实验如下：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eLocalDate\u003c/span\u003e \u003cspan style=\"color:#111\"\u003elocalDate\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eLocalDate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e2017\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eMonth\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eNOVEMBER\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e5\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eLocalTime\u003c/span\u003e \u003cspan style=\"color:#111\"\u003elocalTime\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eLocalTime\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eZoneId\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ezone\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eZoneId\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#d88200\"\u003e\u0026#34;America/New_York\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003eZonedDateTime\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ez\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eZonedDateTime\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eof\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003elocalDate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003elocalTime\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ezone\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e6\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003eSystem\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eout\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eprintln\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ez\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eplusHours\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输出如下：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e2017-11-05T01:00-04:00[America/New_York]\n2017-11-05T01:00-05:00[America/New_York]\n2017-11-05T02:00-05:00[America/New_York]\n2017-11-05T03:00-05:00[America/New_York]\n2017-11-05T04:00-05:00[America/New_York]\n2017-11-05T05:00-05:00[America/New_York]\n\u003c/code\u003e\u003c/pre\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/java-8-date-and-time-api/","date_published":"16066-16-09T643:1616:00+07:00","date_modified":"16066-16-09T643:1616:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"d8990abcc47e20ed02e3142d097bf711cf77aaa8","title":"谈谈赴泰工作的问题","summary":"","content_text":"自从16年10月到泰国工作，迄今已经超过一年半了。我也想分享一下如何去泰国工作，其中最重要的就是签证问题。\n根据来泰国的目的，需要申请对应的签证。对于大多数人来说旅游签的门槛很低，但是持有旅游签是不能直接来泰国申请Work Permit的。事实上这种做法是非法的。\n事实上有两个法律凭证需要搞清楚，第一个是工作签证；第二个是工作证。\n需要解答的问题 ","content_html":"\u003cp\u003e自从16年10月到泰国工作，迄今已经超过一年半了。我也想分享一下如何去泰国工作，其中最重要的就是签证问题。\u003c/p\u003e\n\u003cp\u003e根据来泰国的目的，需要申请对应的签证。对于大多数人来说旅游签的门槛很低，但是持有旅游签是不能直接来泰国申请Work Permit的。事实上这种做法是非法的。\u003c/p\u003e\n\u003cp\u003e事实上有两个法律凭证需要搞清楚，第一个是工作签证；第二个是工作证。\u003c/p\u003e\n\u003ch2 id=\"需要解答的问题\"\u003e需要解答的问题\u003c/h2\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/applying-visa-to-work-in-thailand/","date_published":"14066-14-09T648:1414:00+07:00","date_modified":"14066-14-09T648:1414:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"342d78a03919f555e2d465c12675651e552f8f98","title":"Java泛型中一些难点解析","summary":"","content_text":"Joshua Bloch：\nFor 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.\n参考Stackoverflow上这个问答或是参考这个Java Generics FAQs\nWhat is a bounded wildcard? A wildcard with either an upper or a lower bound. A wildcard with an upper bound looks like \u0026quot; ? extends Type \u0026quot; 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 \u0026quot; ? super Type \u0026quot; and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound .\nBounded 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.\nExample:\npublic class Collections { // bounded wildcard parameterized types public static \u0026lt;T\u0026gt; void copy(List\u0026lt;? super T\u0026gt; dest, List\u0026lt;? extends T\u0026gt; src) { for (int i = 0; i \u0026lt; src.size(); i++) dest.set(i, src.get(i)); } } 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 .\n","content_html":"\u003cp\u003eJoshua Bloch：\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFor 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\nneed 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:\nPECS stands for producer-extends, consumer-super.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e参考Stackoverflow上这个\u003ca href=\"https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java\"\u003e问答\u003c/a\u003e或是参考这个\u003ca href=\"http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103\"\u003eJava Generics FAQs\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"what-is-a-bounded-wildcard\"\u003eWhat is a bounded wildcard?\u003c/h3\u003e\n\u003cp\u003eA wildcard with either an upper or a lower bound.\nA wildcard with an upper bound looks like \u0026quot; ? extends Type \u0026quot; and stands for the family of all types that are subtypes of Type , type Type being included.  Type is called the upper bound .\nA wildcard with a lower bound looks like \u0026quot; ? super Type \u0026quot; and stands for the family of all types that are supertypes of Type , type Type being included. Type is called the lower bound .\u003c/p\u003e\n\u003cp\u003eBounded 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.\u003c/p\u003e\n\u003cp\u003eExample:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eCollections\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e// bounded wildcard parameterized types\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003ecopy\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eList\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003edest\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eList\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eextends\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003esrc\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#00a8c8\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#00a8c8\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003esrc\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003esize\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e \u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#111\"\u003edest\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eset\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003esrc\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eget\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe 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 .\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/java-generics/","date_published":"12066-12-09T644:1212:00+07:00","date_modified":"12066-12-09T644:1212:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"bb4ec72509f6ddcff845aaf4dcaf665a68b823d3","title":"Java 8 Optional类的要点分析","summary":"","content_text":"首先仔细浏览Oracle和Android官方API文档。\n然后仔细浏览Urma所著的Oracle的Java官方Tutorial。\nUrma关于空指针的一段话：\nI 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.\n关于引入java.util.Optional类的初衷：\nIt 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.\nOptional.map和Optional.flatMap的区别 其实只要仔细读读Optional类的源码就明白两者的区别了：\n/** * If a value is present, apply the provided mapping function to it, * and if the result is non-null, return an {@code Optional} describing the * result. Otherwise return an empty {@code Optional}. * * @apiNote This method supports post-processing on optional values, without * the need to explicitly check for a return status. For example, the * following code traverses a stream of file names, selects one that has * not yet been processed, and then opens that file, returning an * {@code Optional\u0026lt;FileInputStream\u0026gt;}: * * \u0026lt;pre\u0026gt;{@code * Optional\u0026lt;FileInputStream\u0026gt; fis = * names.stream().filter(name -\u0026gt; !isProcessedYet(name)) * .findFirst() * .map(name -\u0026gt; new FileInputStream(name)); * }\u0026lt;/pre\u0026gt; * * Here, {@code findFirst} returns an {@code Optional\u0026lt;String\u0026gt;}, and then * {@code map} returns an {@code Optional\u0026lt;FileInputStream\u0026gt;} for the desired * file if one exists. * * @param \u0026lt;U\u0026gt; The type of the result of the mapping function * @param mapper a mapping function to apply to the value, if present * @return an {@code Optional} describing the result of applying a mapping * function to the value of this {@code Optional}, if a value is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null */ public\u0026lt;U\u0026gt; Optional\u0026lt;U\u0026gt; map(Function\u0026lt;? super T, ? extends U\u0026gt; mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } /** * If a value is present, apply the provided {@code Optional}-bearing * mapping function to it, return that result, otherwise return an empty * {@code Optional}. This method is similar to {@link #map(Function)}, * but the provided mapper is one whose result is already an {@code Optional}, * and if invoked, {@code flatMap} does not wrap it with an additional * {@code Optional}. * * @param \u0026lt;U\u0026gt; The type parameter to the {@code Optional} returned by * @param mapper a mapping function to apply to the value, if present * the mapping function * @return the result of applying an {@code Optional}-bearing mapping * function to the value of this {@code Optional}, if a value is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null or returns * a null result */ public\u0026lt;U\u0026gt; Optional\u0026lt;U\u0026gt; flatMap(Function\u0026lt;? super T, Optional\u0026lt;U\u0026gt;\u0026gt; mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } } 可见两者唯一的区别就是map方法在最后用 Optional.ofNullable 包装了返回值，而flatMap没有。\nOptional类的primitive版本 OptionalInt、OptionalLong、OptionalDouble，它们的对应get方法签名变成了getAsInt、getAsLong、getAsDouble。\n","content_html":"\u003cp\u003e首先仔细浏览\u003ca href=\"https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html\"\u003eOracle\u003c/a\u003e和\u003ca href=\"https://developer.android.com/reference/java/util/Optional\"\u003eAndroid\u003c/a\u003e官方API文档。\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cp\u003e然后仔细浏览Urma所著的Oracle的Java官方\u003ca href=\"http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html\"\u003eTutorial\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eUrma关于空指针的一段话：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e关于引入\u003ccode\u003ejava.util.Optional\u003c/code\u003e类的初衷：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIt 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.\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"optionalmap和optionalflatmap的区别\"\u003eOptional.map和Optional.flatMap的区别\u003c/h2\u003e\n\u003cp\u003e其实只要仔细读读Optional类的源码就明白两者的区别了：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * If a value is present, apply the provided mapping function to it,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * and if the result is non-null, return an {@code Optional} describing the\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * result.  Otherwise return an empty {@code Optional}.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @apiNote This method supports post-processing on optional values, without\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * the need to explicitly check for a return status.  For example, the\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * following code traverses a stream of file names, selects one that has\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * not yet been processed, and then opens that file, returning an\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * {@code Optional\u0026lt;FileInputStream\u0026gt;}:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * \u0026lt;pre\u0026gt;{@code\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *     Optional\u0026lt;FileInputStream\u0026gt; fis =\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *         names.stream().filter(name -\u0026gt; !isProcessedYet(name))\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *                       .findFirst()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *                       .map(name -\u0026gt; new FileInputStream(name));\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * }\u0026lt;/pre\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * Here, {@code findFirst} returns an {@code Optional\u0026lt;String\u0026gt;}, and then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * {@code map} returns an {@code Optional\u0026lt;FileInputStream\u0026gt;} for the desired\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * file if one exists.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @param \u0026lt;U\u0026gt; The type of the result of the mapping function\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @param mapper a mapping function to apply to the value, if present\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @return an {@code Optional} describing the result of applying a mapping\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * function to the value of this {@code Optional}, if a value is present,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * otherwise an empty {@code Optional}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @throws NullPointerException if the mapping function is null\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eOptional\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003emap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eextends\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003eObjects\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003erequireNonNull\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eisPresent\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eempty\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eOptional\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eofNullable\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eapply\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003evalue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * If a value is present, apply the provided {@code Optional}-bearing\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * mapping function to it, return that result, otherwise return an empty\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * {@code Optional}.  This method is similar to {@link #map(Function)},\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * but the provided mapper is one whose result is already an {@code Optional},\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * and if invoked, {@code flatMap} does not wrap it with an additional\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * {@code Optional}.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @param \u0026lt;U\u0026gt; The type parameter to the {@code Optional} returned by\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @param mapper a mapping function to apply to the value, if present\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *           the mapping function\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @return the result of applying an {@code Optional}-bearing mapping\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * function to the value of this {@code Optional}, if a value is present,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * otherwise an empty {@code Optional}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @throws NullPointerException if the mapping function is null or returns\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * a null result\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eOptional\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eflatMap\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eOptional\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eU\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003eObjects\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003erequireNonNull\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eisPresent\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eempty\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eObjects\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003erequireNonNull\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003eapply\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003evalue\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e可见两者唯一的区别就是map方法在最后用 \u003ccode\u003eOptional.ofNullable\u003c/code\u003e 包装了返回值，而flatMap没有。\u003c/p\u003e\n\u003ch2 id=\"optional类的primitive版本\"\u003eOptional类的primitive版本\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eOptionalInt\u003c/code\u003e、\u003ccode\u003eOptionalLong\u003c/code\u003e、\u003ccode\u003eOptionalDouble\u003c/code\u003e，它们的对应\u003ccode\u003eget\u003c/code\u003e方法签名变成了\u003ccode\u003egetAsInt\u003c/code\u003e、\u003ccode\u003egetAsLong\u003c/code\u003e、\u003ccode\u003egetAsDouble\u003c/code\u003e。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/java-8-optional/","date_published":"11066-11-09T615:1111:00+07:00","date_modified":"11066-11-09T615:1111:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"340d8a9052a8ce7ff3d919794f682ba850e46732","title":"Introduction to Java 8","summary":"","content_text":"关于Java的术语总结。\n","content_html":"\u003cp\u003e关于\u003ca href=\"http://math.hws.edu/javanotes/glossary.html\"\u003eJava的术语总结\u003c/a\u003e。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/introduction-to-java-8/","date_published":"11066-11-09T659:1111:00+07:00","date_modified":"11066-11-09T659:1111:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"24838ff00ae23644c8e210a849ca9a7d0c9b376c","title":"Java Stream API","summary":"","content_text":"Java 8引入了Stream的概念，掌握这个概念的最佳方式是阅读Java官方文档。\n可以浏览一下Oracle Java文档或是Android官方文档。\n有些关键的概念需要掌握：stream、source、stream pipeline、stream operations、intermediate operations、terminal operation。\n/** * Returns a sequential {@code Stream} with this collection as its source. * * \u0026lt;p\u0026gt;This method should be overridden when the {@link #spliterator()} * method cannot return a spliterator that is {@code IMMUTABLE}, * {@code CONCURRENT}, or \u0026lt;em\u0026gt;late-binding\u0026lt;/em\u0026gt;. (See {@link #spliterator()} * for details.) * * @implSpec * The default implementation creates a sequential {@code Stream} from the * collection\u0026#39;s {@code Spliterator}. * * @return a sequential {@code Stream} over the elements in this collection * @since 1.8 */ default Stream\u0026lt;E\u0026gt; stream() { return StreamSupport.stream(spliterator(), false); } Stream实例只能被使用一次，否则会抛出Runtime Exception：\njava.lang.IllegalStateException: stream has already been operated upon or closed 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.\n将Stream转换为int、long或double流 abstract DoubleStream\tmapToDouble(ToDoubleFunction\u0026lt;? super T\u0026gt; mapper) abstract IntStream mapToInt(ToIntFunction\u0026lt;? super T\u0026gt; mapper) abstract LongStream mapToLong(ToLongFunction\u0026lt;? super T\u0026gt; mapper) allMatch，anyMatch和noneMatch方法 abstract boolean allMatch(Predicate\u0026lt;? super T\u0026gt; predicate) abstract boolean anyMatch(Predicate\u0026lt;? super T\u0026gt; predicate) abstract boolean noneMatch(Predicate\u0026lt;? super T\u0026gt; predicate) ","content_html":"\u003cp\u003eJava 8引入了Stream的概念，掌握这个概念的最佳方式是阅读Java官方文档。\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cp\u003e可以浏览一下Oracle Java文档或是\u003ca href=\"https://developer.android.com/reference/java/util/stream/package-summary\"\u003eAndroid官方文档\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e有些关键的概念需要掌握：stream、source、stream pipeline、stream operations、intermediate operations、terminal operation。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * Returns a sequential {@code Stream} with this collection as its source.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * \u0026lt;p\u0026gt;This method should be overridden when the {@link #spliterator()}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * method cannot return a spliterator that is {@code IMMUTABLE},\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * {@code CONCURRENT}, or \u0026lt;em\u0026gt;late-binding\u0026lt;/em\u0026gt;. (See {@link #spliterator()}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * for details.)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @implSpec\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * The default implementation creates a sequential {@code Stream} from the\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * collection\u0026#39;s {@code Spliterator}.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @return a sequential {@code Stream} over the elements in this collection\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e * @since 1.8\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003edefault\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eStream\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eE\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003estream\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e()\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eStreamSupport\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#75af00\"\u003estream\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003espliterator\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(),\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003efalse\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#111\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eStream实例只能被使用一次，否则会抛出Runtime Exception：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ejava.lang.IllegalStateException: stream has already been operated upon or closed\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe 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.\u003c/p\u003e\n\u003ch2 id=\"将stream转换为intlong或double流\"\u003e将\u003ccode\u003eStream\u003c/code\u003e转换为\u003ccode\u003eint\u003c/code\u003e、\u003ccode\u003elong\u003c/code\u003e或\u003ccode\u003edouble\u003c/code\u003e流\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eDoubleStream\u003c/span\u003e\t\u003cspan style=\"color:#75af00\"\u003emapToDouble\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eToDoubleFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eIntStream\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003emapToInt\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eToIntFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eLongStream\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003emapToLong\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eToLongFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003emapper\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"allmatchanymatch和nonematch方法\"\u003eallMatch，anyMatch和noneMatch方法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eallMatch\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePredicate\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003epredicate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eanyMatch\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePredicate\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003epredicate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003eabstract\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003enoneMatch\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003ePredicate\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;?\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003esuper\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003epredicate\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","url":"https://danielsunyu.github.io/myblog-site/posts/java-stream-api/","date_published":"6066-06-09T62:66:00+07:00","date_modified":"6066-06-09T62:66:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"b3715e7c399d391c8787d20d3b305bf937d88ac5","title":"Java 8 Functional Interfaces笔记","summary":"","content_text":"最近在准备OCJP 8考试，需要熟悉一下Java 8引入的函数式编程的概念。具体包括了Functional Interfaces、Lambda表达式、Stream API等新知识。\n最值得阅读的文档一般都是官方文档。Oracle和Android都有文档的链接。\n4个内建(Built-in)的Functional interfaces Functional Interfaces，或称为函数式接口，主要是指列于java.util.function包下的所有新的接口。它们被设计出来以满足通用的需求。乍看下共有43个接口，会觉得很吓人。其实它们都是从4个最典型的接口派生而来，为了某个specialization的、更具体化的场景而设计的，说白了就是为了让程序员能够根据需求选择出最具体化的接口。\n1. Function接口 @FunctionalInterface public interface Function\u0026lt;T, R\u0026gt; { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); 2. Supplier接口 @FunctionalInterface public interface Supplier\u0026lt;T\u0026gt; { /** * Gets a result. * * @return a result */ T get(); 3. Predicate接口 @FunctionalInterface public interface Predicate\u0026lt;T\u0026gt; { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); 4. Consumer接口 @FunctionalInterface public interface Consumer\u0026lt;T\u0026gt; { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); Lambda表达式和函数式接口并不是一一对应的关系，一个Lambda表达式可以与多个Functional Interfaces兼容（compatible）。\nPrimitive Functional Interfaces Primitive Functional Interfaces只包含double、int和long类型，而不包含char、float和short类型，所以java.util.function包下就不存在类似CharSupplier的接口。\n补充 arity的解释是\u0026quot;元数\u0026quot;，就是参数数目的意思。\n","content_html":"\u003cp\u003e最近在准备OCJP 8考试，需要熟悉一下Java 8引入的函数式编程的概念。具体包括了Functional Interfaces、Lambda表达式、Stream API等新知识。\u003c/p\u003e\n\u003c!-- more --\u003e\n\u003cp\u003e最值得阅读的文档一般都是官方文档。\u003ca href=\"https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html\"\u003eOracle\u003c/a\u003e和\u003ca href=\"https://developer.android.com/reference/java/util/function/package-summary\"\u003eAndroid\u003c/a\u003e都有文档的链接。\u003c/p\u003e\n\u003ch2 id=\"4个内建built-in的functional-interfaces\"\u003e4个内建(Built-in)的Functional interfaces\u003c/h2\u003e\n\u003cp\u003eFunctional Interfaces，或称为函数式接口，主要是指列于\u003ccode\u003ejava.util.function\u003c/code\u003e包下的所有新的接口。它们被设计出来以满足通用的需求。乍看下共有43个接口，会觉得很吓人。其实它们都是从4个最典型的接口派生而来，为了某个specialization的、更具体化的场景而设计的，说白了就是为了让程序员能够根据需求选择出最具体化的接口。\u003c/p\u003e\n\u003ch3 id=\"1-function接口\"\u003e1. Function接口\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003e@FunctionalInterface\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eFunction\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#111\"\u003eR\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * Applies this function to the given argument.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @param t the function argument\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @return the function result\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003eR\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eapply\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#111\"\u003et\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"2-supplier接口\"\u003e2. Supplier接口\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003e@FunctionalInterface\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eSupplier\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * Gets a result.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @return a result\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eget\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"3-predicate接口\"\u003e3. Predicate接口\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003e@FunctionalInterface\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003ePredicate\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * Evaluates this predicate on the given argument.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @param t the input argument\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @return {@code true} if the input argument matches the predicate,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * otherwise {@code false}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003etest\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#111\"\u003et\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"4-consumer接口\"\u003e4. Consumer接口\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75af00\"\u003e@FunctionalInterface\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#00a8c8\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#00a8c8\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eConsumer\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#111\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * Performs this operation on the given argument.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     * @param t the input argument\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e     */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#00a8c8\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#75af00\"\u003eaccept\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e(\u003c/span\u003e\u003cspan style=\"color:#111\"\u003eT\u003c/span\u003e \u003cspan style=\"color:#111\"\u003et\u003c/span\u003e\u003cspan style=\"color:#111\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eLambda表达式和函数式接口并不是一一对应的关系，一个Lambda表达式可以与多个Functional Interfaces兼容（compatible）。\u003c/p\u003e\n\u003ch2 id=\"primitive-functional-interfaces\"\u003ePrimitive Functional Interfaces\u003c/h2\u003e\n\u003cp\u003ePrimitive Functional Interfaces只包含\u003ccode\u003edouble\u003c/code\u003e、\u003ccode\u003eint\u003c/code\u003e和\u003ccode\u003elong\u003c/code\u003e类型，而不包含\u003ccode\u003echar\u003c/code\u003e、\u003ccode\u003efloat\u003c/code\u003e和\u003ccode\u003eshort\u003c/code\u003e类型，所以\u003ccode\u003ejava.util.function\u003c/code\u003e包下就不存在类似\u003ccode\u003eCharSupplier\u003c/code\u003e的接口。\u003c/p\u003e\n\u003ch2 id=\"补充\"\u003e补充\u003c/h2\u003e\n\u003cp\u003earity的解释是\u0026quot;元数\u0026quot;，就是参数数目的意思。\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/java-8-functional-interfaces-notes/","date_published":"6066-06-09T615:66:00+07:00","date_modified":"6066-06-09T615:66:00+07:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}},{"id":"71069bfd85a9406147fbd4cc2a70d9112a53948a","title":"在Mac系统上安装Java 7最佳实践","summary":"","content_text":"截止今日，Oracle已经推出了JDK 8，对于这么新的版本，相信很多人和我一样不敢尝试。由于JDK 7已经在一些平台上（如最新的Android系统）得到支持，所以如果能在Mac上将JDK 6升级到7将会解决一些开发上的需求。\nMac系统历代OS都内置了JDK版本，不过最新的Mavericks上却只内置了JRE 6。Mac系统省缺JDK但是可以通过其升级机制安装JDK，遗憾的是苹果官方支持/安装的是JDK 6。看来Mac在Java的支持上有些滞后。幸运的是，在Mac上升级JDK很简单，可以按照如下步骤：\n前往Oracle官网的Java SE Development Kit 7下载页下载Mac平台的dmg安装包。由于Mac系统的处理器都是64位的，所以只有唯一对应的安装包可以选择！\n双击dmg安装包，会显示如下安装界面，双击pkg图标就会开始安装。\n安装结束后在命令行输入：\njava --version 回显：\njava version \u0026#34;1.7.0_67\u0026#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) Bingo，JDK 7已经安装完毕，不过先别急着离开，在实际的软件开发中，还会需要设置JAVA_HOME环境变量。\n附加任务：设置JAVA_HOME环境变量\n打开home目录下的.bash_profile文件，在最后加入如下代码：\nexport JAVA_HOME=$(/usr/libexec/java_home) 关闭文件后，在命令行输入：\nsource .bash_profile 这样，JAVA_HOME环境变量就设置完毕了，可以这样验证：\necho $JAVA_HOME 回显如下：\n/Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home OK，大功告成！\n","content_html":"\u003cp\u003e截止今日，Oracle已经推出了JDK 8，对于这么新的版本，相信很多人和我一样不敢尝试。由于JDK 7已经在一些平台上（如最新的Android系统）得到支持，所以如果能在Mac上将JDK 6升级到7将会解决一些开发上的需求。\u003c/p\u003e\n\u003cp\u003eMac系统历代OS都内置了JDK版本，不过最新的Mavericks上却只内置了JRE 6。Mac系统省缺JDK但是可以通过其升级机制安装JDK，遗憾的是苹果官方支持/安装的是JDK 6。看来Mac在Java的支持上有些滞后。幸运的是，在Mac上升级JDK很简单，可以按照如下步骤：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e前往Oracle官网的Java SE Development Kit 7下载页下载Mac平台的dmg安装包。由于Mac系统的处理器都是64位的，所以只有唯一对应的安装包可以选择！\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e双击dmg安装包，会显示如下安装界面，双击pkg图标就会开始安装。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cfigure\u003e\u003cimg src=\"/images/jdk7_installation_wizard.png\" width=\"400px\" height=\"560px\"\u003e\n\u003c/figure\u003e\n\n\u003cp\u003e安装结束后在命令行输入：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ejava --version\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e回显：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ejava version \u0026#34;1.7.0_67\u0026#34;\nJava(TM) SE Runtime Environment (build 1.7.0_67-b01)\nJava HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBingo，JDK 7已经安装完毕，不过先别急着离开，在实际的软件开发中，还会需要设置JAVA_HOME环境变量。\u003c/p\u003e\n\u003cp\u003e附加任务：设置JAVA_HOME环境变量\u003c/p\u003e\n\u003cp\u003e打开home目录下的.bash_profile文件，在最后加入如下代码：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eexport JAVA_HOME=$(/usr/libexec/java_home)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e关闭文件后，在命令行输入：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esource .bash_profile\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样，JAVA_HOME环境变量就设置完毕了，可以这样验证：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eecho $JAVA_HOME\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e回显如下：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOK，大功告成！\u003c/p\u003e\n","url":"https://danielsunyu.github.io/myblog-site/posts/install-java7-on-mac/","date_published":"16096-16-09T92:1616:00+08:00","date_modified":"16096-16-09T92:1616:00+08:00","author":{"name":"Daniel Sun","url":"https://danielsunyu.github.io/myblog-site/"}}]}