面向对象编程的学习路线

面向对象设计与编程是目前最主流的编程范式。尽管函数式编程风头正劲,尽管有诸多贬低,可编程的世界或者说大部分商业软件的开发却依旧由OO占领着。从其他角度,譬如面试的考察频率也能看出,OO依旧是世界的主流。可OO的范围很庞大,从设计到编程,从各种概念到工具,如何才能学好呢?什么才是学习OO的正确路线呢?本文算是从中级继续进阶的建议,而非新手的学习指南。初学OO的新手可能会简单直接一些,《Code Complete》、《Clean Code》这几本经典著作,边读边在实战中体会。在各种项目中摸爬滚打几年,也就能看到自己的瓶颈,这时也许这篇文章能有所帮助。


1.哲学:知识的组织

面向对象跟普通的设计与编程有什么区别?上升到哲学的层面是不是有点太夸张了?还真没有。深入学习OO虽然谈不上对你人生观、世界观重塑,但读几本好书至少能对你的程序设计观、编码观会产生深远的影响。关于这一部分,极力推荐两本书,相信你读过后一定不会后悔:

  • 《Elegant Object》:基于“智能”对象之上的声明式编程,详见《优雅的对象》
  • 《Practical Object-Oriented Design in Ruby》:关注点由静态的Class转移到动态的Message将是你面向对象设计生涯的转折点!

还有一本《Object Thinking》,由于还没有开始看,所以先占个位子,不做大力推荐了。

当然,OO只是一种对计算,本质上对知识,有效的组织形式。你当然可以坚持认为世界是流动的、面向过程的,而非基于对象的,关键在于理解不同“哲学”背后的相同点


2.工具:思想的武器

2.1 原则

关于OO的设计原则不少,围绕着基本的高内聚和低耦合,耳熟能详的原则有SOLID、ACID…… 就说最有名的SOLID吧:S单一原则、O开闭原则、L里氏代换、I接口隔离、D依赖倒置。关于这些原则,依然推荐阅读《Practical Object-Oriented Design in Ruby》,分析的非常透彻!

2.2 模式

提设计模式当然不能不提GoF“四人帮”,23种模式整理了软件工程不长的历史中凝结的经验精华。但学习什么东西都要注重的就是:不要过分贬低,也不要神化。你看似酷炫的设计模式,却是我朴实无华的语言特性。而所谓的模式,可能只是你对其尝试抽象失败后的产物。从另外的角度看模式,也许你会得到非常震撼的结论,详见《设计模式沉思录》


3.实践:

3.1 重构

3.2 测试驱动


4.语言

Python:


5.方法论

领域驱动设计(DDD)

当我通勤时我该读什么

今年夏天房子到期后搬出了西雅图市区,从此开始了通勤上下班的生活。可能因为公交不太拥挤的缘故,在车上经常能看见捧着书读的人,有的还是厚厚的精装书。坐的每一趟车上平均都会有三到五个,甚至还有没有座位站着也要读书的。本以为亚马逊的Kindle会更为流行,结果好像很少见到,没想到实体书还如此顽强地生存着。于是信箱既然读书氛围这么好,我还一直有座位,那我也来读点什么吧。但以前晚上读的书有些比较费脑,感觉不是很合适在通勤的短时间里阅读。所以就想到这样一个问题:当我通勤时我该读什么?


1.轻松科普书

在车上读一些轻松的科普书再合适不过,不论是数学类的、科技史类的、人工智能类的,甚至非技术类的等等。既能开拓知识面,又能激发一些工作上的奇思妙想。从基础数学到离散数学,再到机器学习和人工智能,这条线索也是一直在脑海里规划着。机器学习很可能也与明年的工作内容相关,所以这一部分也是在有目标地读。只是因为水平和时间都有限,不能期望太多,每天进步一点点就行了。选书时,除了内容轻松一些,书整体不是太厚(300页最多),另外就是最好章节多一些,每一章都短一些。这样在每天通勤时能够至少读完一章,不至于读到中间就要下车被打断。


2.通俗技术书

技术书有很多种,感觉通勤时读一些比较好读、个人比较熟悉的题材比较好。比如自己熟悉的编程语言、框架等主题,这样读起来很顺、很快,不会被周围环境影响。目前一条主线是面向对象编程和设计,另外一条主线是逻辑与计算。前者是读完《Elegant Object》后的延续,面向对象的好书不少,可以继续学习。后者则是读完《Engines of Logic》意犹未尽,准备继续多读几本逻辑与计算相关的书。


3.我的书单

已经通勤了两个半月,这是目前读完的书:

  • 《The Joy of X》:与《费马大定理》一样轻松、有趣而令人着迷,详见博文《X的奇幻之旅》
  • 《Fermat’s Enigma》:大概十年前读过,当时就一发不可收拾,这次重读了英文版,依然十分精彩!整理的文章还没写完,之后会发出来。
  • 《Elegant Object》:颠覆面向对象观念的好书,详见博文《优雅的对象》
  • 《Engines of Logic》:梳理整个计算的理论发展史。正在整理中,文章很快会发出来。
  • 《Grow Object-Oriented Software Guided by Tests》:已经读完,比较不错,可以说是TDD的权威了。

前面提到了技术方面学习的两条主线,所以计划近期接下来要读的有:

  • 面向对象方面(由《Elegant Object》引出)
    • 《Practical Object-Oriented Design in Ruby》:评论很不错,已经读了一半,没想到这么好!如书中所说,这将是你面向对象设计生涯的转折点。
  • 逻辑与计算方面(由《Engines of Logic》引申出来)
    • 《Code: The Hidden Language of Computer Hardware and Software》
    • 《Annotated Turing》:通俗易懂地领大家过一遍图灵的论文,真正了解什么是图灵机。已经读了前面比较容易的三分之一,后面有些不适合通勤时间读了,还要再接再厉一口气读完。

4.阅读的收获

阅读的好处就不多说了,这里简单说说个人的体验。通勤时的狭小空间为忙碌的现代人提供了一个能够专注做一件事的机会。当你从书里的故事回到现实,走到办公室开始一天的工作时,你会觉得自己没有受限于自己日常的三点一线,平常的生活有了时间和空间上的广度。此外就是知识的日积月累,每天上下班一两个小时,坚持一年、三年甚至五年,累积起来的知识量将会是可怕的。

有一点要特别注意。比如个人而言,如果书的内容实在太精彩了,一般回到家后还会继续读,所以有时一本书一两周就能读完。但这样有利有弊。利就是能够思路连贯、一气呵成地读完,弊就是如果不及时总结那基本就跟没读差不多。所以读完之后要及时做笔记,做的同时翻看当时看书的旁注温习。如果最后写成的博文的还能成为一个系列中的一部分,形成了知识体系,那就再好不过了。

祝大家从阅读中找到快乐!

逻辑的引擎

最近利用通勤时间又读完了一本好书,《Engines of Logic——Mathematicians and the Origin of the Computer》。可能由于作者本身也是数学和计算方面的牛人,所以这本书并不那么容易读。一是字里行间可以立即感受到的不舒服,即句式有些太复杂,随便翻开一页就能发现很多可以用作GRE阅读理解的长难句。二是每一章都大概用了至少一半的篇幅,对年代和人物生平进行介绍。于是各种人名、国家、政治、战争相关的词参杂在GRE长难句中,令人云里雾里。三就是本人的问题了,对书中涉及的数学知识准备不足。

但本书的优点明显,系统地梳理了相关的人物和知识,可以作为后续学习的主线(参见本文最后一部分的后续学习计划)。再就是下面正文也会提到的,本书刷新了笔者对逻辑和计算两者关系的既有认知。回过头来想想,其实每天都在两者间往来,有点当局者迷了,本书正是醍醐灌顶的那一下。所以瑕不掩瑜,总体来说这是一本绝对值得推荐的好书。


1.莱布尼兹的梦

说到莱布尼兹,我们首先会想到的就是微积分了,与同样大名鼎鼎的牛顿各自独立研究出了微积分。但莱布尼兹有一项超凡的能力,他为微分和积分发明的符号记法沿用至今,使得复杂的微积分计算变成了几乎不用思考的“体力劳动”。莱布尼兹不止于此,他认为对人类的各种知识都可以用类似的方法来实现简化甚至自动化。于是,他梦想着将人类的全部知识进行百科全书式地编纂,用统一的数学语言将每一条知识点都精确地表达出来,同时用一套计算规则表示这些知识(proposition命题)之间的逻辑关系,最后也是最重要:一台能够承载这些计算的机器,自动证明、产生更多知识,解放人类去做创造性的思考

莱布尼兹着迷于亚里士多德的概念分类法,于是对这个他想到的绝妙构想,首先要做的就是用一套特殊的符号表去表示概念。同时他也在实践中向着这个方向努力,帕斯卡设计了能够加减的机器,而莱布尼兹则设计了第一台能够乘除的机器,在其中引入了被称作“莱布尼兹轮”的天才部件。尽管如此,他还是没能在有生之年实现这个美好的愿景。也许今天的我们想起来很简单,觉得计算机发展起来也就是最近几十年的事情。可是对于当时的人们,没有理论基础,没有合适的材料和工艺,要想靠一位数学家甚至是一代数学家们来完成都是不现实的。即便到了今天,尽管很多人都在研究,也有了Prolog专门的逻辑语言,可莱布尼兹的自动化愿景也还没完全实现。

莱布尼兹自己可能也清楚,这个宏伟的构想要靠接下来几代人共同努力了,而且他认为最终是可以实现的。脚踏实地,他给出了一系列可行的步骤:1)创建一套百科全书包揽人类的所有知识;2)选取关键的底层记号,为每一个都提供专门的符号来表达;3)逻辑推导变成了对这些符号的操纵。这也就是我们今天所说的“符号逻辑”,莱布尼兹为后人指明了前进的方向。


2.逻辑的计算

2.1 布尔:化逻辑为代数

在学习离散数学时相信大家肯定都学过布尔代数。当时眼里只有代数两个字,就觉得这只是另一种形式的代数。可如今想想,古老的逻辑与代数的运算结合到了一起,真是神奇!在莱布尼兹开创和指引的逻辑演算的大道上,布尔又更进了一步,经过更多人的贡献,最终发展成为一个分支——数理逻辑。想想每天编程时,每次声明一个布尔变量,其实都是在纪念着布尔。

简单来说,布尔用乘法表示交集,用加法表示并集,0表示空集,1表示全集(包含所有当前被考虑的对象)。通过一系列的研究和验证,比如最简单的x(1 - x) = 0,一个集合里的元素与不属于该集合的元素取交集,结果应该为0,即空集才对,否则就违反了最基本的Principle of Contradiction了。所谓的“矛盾原则”是由亚里士多德提出来的,所有哲学都应该遵守的基本公理。它的基本含义是:一个性质不可能既属于又不属于同一样东西。在布尔代数里,xx即集合与自己的交集当然仍旧等于自己。所以前面的等式就变成了x(1 - x) = x - xx = x - x = 0,于是布尔很高兴这个代数系统满足了基本的哲学原则。

布尔的逻辑系统可以说是对莱布尼兹构想第一步的“简单粗暴”的实现,但问题也很明显。布尔代数的乘法和加法表示交集和并集,也就是说布尔代数只能表示“并且”和“或者”的逻辑关系。但至少还要有“如果那么”吧,该怎样表示呢?答案就是x(1 - y) = 0,即x为真,并且y也为真。但莱布尼兹所说的人类全部知识所需的表达方式要远多于此,最基本的量词在布尔代数里就无法表达。尽管如此,布尔却在用代数和符号表达人类知识和逻辑推理的道路上迈出了坚实的一步。

最早在《程序员的数学修养》一文里对编程和数学家的日常工作做过类比,数学证明的构建与程序异曲同工。之后在读《The Joy of X》时又重新思考了这一问题,觉得数学证明是数学家的日常,即纯数学,而程序员更接近应用数学或计算数学,证明只是用来对算法(程序)本身正确性的验证。但这一次《Engines of Logic》刷新了我的认知,本书完全模糊了逻辑证明与计算的界限。其实这是我们程序员每天都在做的事,将写好的带有一堆条件语句的程序编译,然后运行在只有基本算术运算功能的CPU上。这一切都太过自然,以至于我们从来没有思考过为什么我们能够这样做?逻辑推导与计算的区别是什么?

2.2 弗雷格:命题逻辑

2.3 图灵:通用图灵机

2.4 冯诺依曼:第一台通用计算机

我们都知道第一台计算机埃尼阿克(ENIAC),1946年诞生于美国宾夕法尼亚大学。但其实埃尼阿克的下一代EDVAC才是通用图灵机的第一个物理实现。从实用角度出发,EDVAC具有“一步”就能实现加减乘除的基本运算功能,这在原版图灵机是需要通过configuration构建起来的(具体参见《Annotated Turing》)。同时它还能够把数据和指令从内存读到CPU中,这也就是著名的冯诺依曼架构。


3.计算的能力

3.1 康托:无限

3.2 希尔伯特:

这不是数学,这是神学!

3.3 哥德尔:

亚里士多德后最伟大的逻辑学家。


4.超越莱布尼兹的梦

4.1 逻辑与计算

阅读本书时的最大疑问就是:逻辑推理与计算是如何成了一件事的?其实它们就像硬币的两面,将逻辑推理化简成形式规则最早可以追溯到亚里士多德的时代。作者用了英文里“reckon”估算、估摸这个词,说这个词巧妙地说明了逻辑与计算间的关系。比如我们根据去年的庄家产量去估算今年的,当我们带着各种数字去reckon时逻辑推理与计算就交织在了一起。

4.2 计算机与人脑

图灵机横空出世后,关于计算机是否可以取代人、计算的智能是否可以达到甚至超过人类的争论,直到今天也没有停止过。图灵在他的论文里“添油加醋”,不断地在两者间打着比方,而之后图灵又提出了著名的图灵测试。然而,争论并没有因为图灵测试而停下来。如果一个人不会下棋,在做图灵测试时被关到一个小屋里,给了他一本在各种情况下应该如何落子应对的书。最后他成功欺骗了人类对手,甚至赢了比赛,在这种情况下我们可以说他是有下棋的智能吗?后来的故事我们都知道,深蓝赢了国际象棋大师卡斯帕罗夫。

问题的关键在于什么是“知道”、“会”(know)。很多人会说深蓝知道的只是指令,只是一堆没有意义的符号,与国际象棋无关。可如果你能在卡斯帕罗夫下棋时深入到他的头骨,你同样看不到棋子,你看到的是神经元在活动。关于人脑是如何工作的研究还处于初级,但计算机是由我们工程师和程序员共同构建起来的,它的构造我们了如指掌。然而不管是人脑还是计算机,我们可以把人脑分子层面的模式分析想象成计算机的符号操作。可这种解释也无法让所有人满意,有人会争辩深蓝是没有意识的。什么是意识?我们又陷入了更深的思考和争论。


5.后续补充学习

《Engines of Logic》这本书可以很好地充当符号逻辑、计算理论等方面的学习主线,可单单凭这一本书就想对这一庞大而历史悠久的分支有深刻理解是不现实的。如果读完就扔下那是对这本书以及阅读后产生的短时知识记忆的浪费,所以在本文做过总结后,还要读更多的书才能深入了解。以前是目前手头已有的不错资料的整理:

  • 远古的两座大神:亚里士多德的逻辑,欧几里德的公理系统。
  • 莱布尼兹的微积分记法
  • 哥德尔的证明
    • 《Gödel’s Proof》
    • 《Gödel, Escher, Bach: An Eternal Golden Braid》:旷世神书集异壁
  • 图灵机的深入研究
    • 《Annotated Turing》:目前在读,前面几章背景知识介绍就已足够惊艳,全书既有广度又有深度。
  • 香农的信息论
    • 《Code: The Hidden Language of Computer Hardware and Software》:跟《Annotated Turing》是一个作者,本书声望更高。
    • 《A Mind at Play: How Claude Shannon Invented the Information Age》

在github上轻松搭建博客

从2011年开始正式定期地写文章,最开始在Google AppEngine搭建了Wordpress,几个月后又将文章都转移到了CSDN。时间飞逝,一看自己的历史文章列表发现都快七年整了。CSDN也在进步,美观方面加了各种皮肤,功能方面支持了Markdown。用得时间长了也觉得有很不方便的地方,可能也是因为一直以来的需求比较低,本地写好后能发表就行。最近偶然间在知乎上看到一篇对CSDN博客系统的吐槽,包括身份验证、文章审核、页面广告等等。对这些吐槽倒并没有很在意,但是无意间看到了有人提到Jekyll在GitHub搭建博客系统。一直没有独立博客,就是有些嫌麻烦。这时一想自己需要的其实就是个渲染展示Markdown的地方,其他什么功能都不用。突然间豁然开朗!


1.Jekyll

1.1 超快速搭建

想要在GitHub上搭建自己的博客非常简单,按照Jekyll的说明,首先将其Fork到自己的代码库,然后将代码库的名字改成你的GitHub帐户名.github.io。过一会访问这个地址,你就能看到自己的博客了。如果还是不能访问的话,那就改一点_config.yml里的东西,强制GitHub编译生成你的博客。

1.2 本地运行

有时我们先定制自己的博客,那么就需要提交代码、再Push、再去GitHub上看效果。这样一来太麻烦,二来把博客系统改瘫痪了的话还得再回滚代码。这时就需要本地运行了,这样不用提交代码就能在本地看到效果,确定好使后再提交Push到GitHub就行。风险低,而且效率高。

首先如果没用过Ruby的gem,则需要先安装它。Ubuntu/Mint系的apt安装方法如下。如果是CentOS的yum或其他平台的话,请自行搜索如何安装。

$ sudo apt-get install rubygems ruby-dev

现在就可以安装GitHub的插件,并本地运行测试了。

$ sudo gem install github-pages
$ jekyll serve

现在访问http://127.0.0.1:4000应该就能看到你的博客了。

1.3 写作流程

以后的写作流程变得更为简单。有了想法后就在本地代码库的_posts文件夹里创建文字,格式为YYYY-MM-DD-title.md。前面是年月日,然后是标题,中英文皆可。打开自己喜欢的Markdown编辑器,Sublime配Vim,或者最近发现了一个Linux下非常漂亮的Markdown编辑器Typora。在这样的编辑器里写文章就是种享受啊!编辑完成或者完成了一部分后,就提交Push,这样别人也能看到你进展中的文章了。


2.Hype

博客的基本功能搭建好了,就要开始折腾样式了。搜索了不少主题,但都花里胡哨的,不太适合技术文章。最终找到了Hype,一个非常简洁漂亮的主题。但问题就是Hype本身已经包含了所有代码,没有提供如何安装到一个已有的Jekyll的方法。于是尝试着Fork了一份之后,把Hype代码覆盖到了Jekyll代码库,目前看来是可行的。

首先安装各种依赖:

$ sudo gem install jekyll-paginate
$ sudo gem install jekyll-gist
$ sudo gem install redcarpet
$ sudo gem install pygments.rb

之后_config.yml里主要修改两个地方,一是注释掉ralative_permalinks,二是paginate和gist加到plugins里。

# Dependencies
markdown:         redcarpet
highlighter:      pygments

# Permalinks
permalink:        pretty
#relative_permalinks: true

# Setup
title:            Chen's Blog
tagline:          'A Jekyll theme'
description:      'A brazen two-column <a href="http://jekyllrb.com" target="_blank">Jekyll</a> theme that pairs a prominent sidebar with uncomplicated content. Made by <a href="https://twitter.com/mdo" target="_blank">@mdo</a>.'
url:              http://cdai.github.io
baseurl:          /

author:
  name:           'Mark Otto'
  url:            https://twitter.com/mdo

paginate:         5

# Custom vars
version:          2.1.0

github:
  repo:           https://github.com/poole/hyde

plugins: [jekyll-paginate, jekyll-gist]

之后本地运行或者提交到GitHub,你就能看到你的博客变成了这种效果Chen’s Blog。再也不用等最后完成再提交到CSDN了,每天写好就提交,自己挖坑自己填…… 最后完成再提交到CSDN,Typora中Ctrl+Shift+C可以Copy as Markdown,然后直接拷贝到CSDN的编辑器就行了。现在开始享受写作的乐趣吧!

那些年我错过的java

最近在看面向对象设计的书,有了一些新的感悟。于是周末闲来无事,想写个小东西练练手。最近一直用Python,所以想回归一下更OO一些的Java。正研究怎么升级到Java 9尝尝鲜,结果发现再有80天Java 11都要发布了!真是山中方一日,世上已千年。才不关注Java没多久,已经快成版本帝了。索性直接上了Java 10,把最近落下的都补上。在这个夏天,补上那些年我错过的Java。

在开始之前要做的当然就是升级到最新版本,这是在Linux(Mint)上通过PPA的方式安装最新版本Java的命令:

$ sudo add-apt-repository ppa:linuxuprising/java
$ sudo apt update
$ sudo apt install oracle-java10-installer
$ sudo apt install oracle-java10-set-default

本文所有例子都可以加入测试类Test,并编译运行javac Test.java && java Test。当然,也可以玩一下Java 9提供的JShell,通过/set feedback verbose在每条命令后能够看到更多信息。

public class Test {
    public static final void main(String[] args) {
        //...
    }
}

1.语言特性增强

1.1 类型推断

Java很恼人的一点就是泛型,的确强制声明类型更加严谨和安全。然而在构建复杂数据类型时,代码会变得非常丑陋。Java 7试图改善这一问题,允许我们省略具体类型而让编译器自己去推断,还很形象地为其取名叫做Diamond Operator(钻石操作符)。

Map<String, List<String>> employeeGroupByAge = new HashMap<>();

Java 10中又进一步地让编译器变得更加聪明,引入了var关键字,让编译器自动推断本地变量的类型。

var employeeGroupByAge = new HashMap<>();
employeeGroupByAge.put(25, List.of("Allen", "Hank"));
employeeGroupByAge.put(30, List.of("Carter"));
System.out.println(employeeGroupByAge); //{25=[Allen, Hank], 30=[Carter]}

从下面JShell的输出可以看出,Java已经足够聪明了,能够推断出甚至比人为声明更为精细的类型。

jshell> var list = List.of(1, 2.0, "3");
list ==> [1, 2.0, 3]
|  modified variable list : List<Serializable&Comparable<? extends Serializable&Comparable<?>>>
|    update overwrote variable list : List<Serializable&Comparable<? extends Serializable&Comparable<?>>>

1.2 字符串

Java 7中很实用的一个特性就是Switch也支持字符串了,之前我们只能通过大段的if-then-else来实现。而且据说Switch更利于编译器做优化,具体为什么还要研究一下。

switch (type) {
    case "Hello": System.out.println("Hi!"); break;
    case "World": System.out.println("Wow!"); break;
    default: System.out.println("Bye!"); break;
}

此外一个小的改进就是String的Join,听起来好像Java太落后了…… 其实改进后依然与Python甚至Apache Lang中提供的工具方法有不小的差距。

System.out.println(new StringJoiner("+", "prefix+", "+suffix").add("a").add("b").add("c"));
System.out.println(String.join("+", "prefix", "a", "b", "c", "suffix"));
System.out.println(String.join("+", List.of("prefix", "a", "b", "c", "suffix")));

1.3 异常处理

Java 7中提供了几个非常实用的异常处理的语法特性,比如自动资源管理。第一次见到这个特性还是在大概十年前初学C#时,印象里好像是use关键字。Java沿用了try关键字,取名叫try-with-resources语句。但基本思想上是一样的,都是为了省去finally里无聊的资源关闭代码。适用于各种常见的资源,比如Connection、File、Stream等。

try (FileInputStream f = new FileInputStream("test.txt")) {
    //...
}

Socket s1 = ...;
File f1 = ...;
try (s1; f1) {
    //...
}

那其他资源或者我们自己的资源类呢?其实这些资源类都实现了java.lang.AutoCloseable接口,所以我们也可以实现它来获得自动关闭的能力。最近Java 9中又进一步简化,可以在try中传入多个final变量,甚至可以是不同的资源类型,只要它们实现了AutoCloseable接口即可。

在一个Catch中可以捕获多种异常,提供统一的处理和恢复逻辑,从而减少重复代码。

try {
    //...
} catch (FileNotFoundException | IOException ex) {
    ex.printStackTrace();
}

1.4 面向对象

interface

optional


2.新库函数引入

2.1 NIO 2

2.2 JodaTime

JSON

货币

HTTP/2 Client


3.多语言风格融合

3.1 REPL

REPL (Read-Evaluate-Print-Loop)

2.1 动态

2.2 Nashorn JS引擎

2.2 Lambda

2.1 Fork-Join框架(Java 7)

2.2


4.JVM

3.1 InvokeDynamic指令(Java 7)

4.2 永久代的移除(Java 8)

3.1 G1成为默认GC(Java 9)

在Java 7首次引入的垃圾回收器G1,在经历了几代的谨慎实验后,在Java 9中终于成为默认的GC。


附录:Release

引自Quora问答回帖:https://www.quora.com/What-are-the-differences-between-Java-6-Java-7-Java-8-and-Java-9

**JDK 1.7 Code Name : Dolphin Year : 2011**
  1. Automated Resource Management
  2. Timsort is used to sort collections and arrays of objects instead of merge sort
  3. Multiple exceptions handling in single catch block
  4. String in switch
  5. JDBC 4.1 support
  6. JVM Enhancements(invokedynamic instructions)
  7. Automatic Type Inference during the Generic Instance Creation(using diamond operator)
  8. Numeric literals with underscore
  9. Fork and Join Framework
  10. G1 Garbage Collector
**JDK 1.8 Code Name : Spider Year : 2014**
  1. Lambda Expression
  2. Streams
  3. Functional Interface
  4. Nashorn
  5. Performance Improvement for HashMaps with Key Collisions
  6. Parallel Array Sorting
  7. StringJoiner class
  8. Optional class
  9. Remove permanent generation
  10. Annotation on Java Types
**JDK 1.9 Code Name : Jigsaw Year : 2017**
  1. JShell: the interactive Java REPL
  2. Private interface methods
  3. Process API Updates
  4. Light-Weight JSON API
  5. Money and Currency API for representing, transporting, and performing comprehensive calculations with Money and Currency
  6. Segmented Code Cache
  7. Improve Contended Locking