函數(shù)式編程與面向?qū)ο缶幊蘙2]: 靜態(tài)類型語言的表達(dá)力 靜態(tài)類型語言與動(dòng)態(tài)類型語言

函數(shù)式編程與面向?qū)ο缶幊蘙2]: 靜態(tài)類型語言的表達(dá)力 靜態(tài)類型語言與動(dòng)態(tài)類型語言

之劍

2016.5.3 21:43:20


像Java或者C#這樣強(qiáng)類型的準(zhǔn)靜態(tài)語言在實(shí)現(xiàn)復(fù)雜的業(yè)務(wù)邏輯纽疟、開發(fā)大型商業(yè)系統(tǒng)罐韩、以及那些生命周期很長(zhǎng)的應(yīng)用中也有著非常強(qiáng)的優(yōu)勢(shì)

下面我們就來學(xué)習(xí)一下這些知識(shí).

有三個(gè)名詞容易混淆:

  • Dynamic Programming Language (動(dòng)態(tài)語言或動(dòng)態(tài)編程語言)
  • Dynamically Typed Language (動(dòng)態(tài)類型語言)
  • Statically Typed Language (靜態(tài)類型語言)

先定義一下標(biāo)準(zhǔn):

強(qiáng)類型語言(靜態(tài)類型語言)

是指需要進(jìn)行變量/對(duì)象類型聲明的語言,一般情況下需要編譯執(zhí)行污朽。例如C/C++/Java/C#

弱類型語言(動(dòng)態(tài)類型語言)

是指不需要進(jìn)行變量/對(duì)象類型聲明的語言散吵,一般情況下不需要編譯(但也有編譯型的)。例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等蟆肆。

1 靜態(tài)類型語言

靜態(tài)類型語言的類型判斷是在運(yùn)行前判斷(如編譯階段)矾睦,比如C#、java就是靜態(tài)類型語言炎功,靜態(tài)類型語言為了達(dá)到多態(tài)會(huì)采取一些類型鑒別手段枚冗,如繼承、接口亡问,而動(dòng)態(tài)類型語言卻不需要官紫,所以一般動(dòng)態(tài)語言都會(huì)采用dynamic typing肛宋,常出現(xiàn)于腳本語言中.

不過,是不是動(dòng)態(tài)類型語言與這門語言是不是類型安全的完全不相干的州藕,不要將它們聯(lián)系在一起!

沒有單元測(cè)試或者單元測(cè)試沒有達(dá)到語句覆蓋或者更強(qiáng)的弱條件組合覆蓋酝陈,從而導(dǎo)致某些非正常流程發(fā)生時(shí)床玻,流經(jīng)這些未被測(cè)試的語句導(dǎo)致語法錯(cuò)誤而最終整個(gè)程序都掛掉.對(duì)于業(yè)務(wù)系統(tǒng)來說,這是非常嚴(yán)重的事情沉帮。

1.1 優(yōu)點(diǎn)

靜態(tài)類型語言的主要優(yōu)點(diǎn)在于其結(jié)構(gòu)非常規(guī)范锈死,便于調(diào)試贫堰,方便類型安全

現(xiàn)在有這樣一種趨勢(shì),那就是合并動(dòng)態(tài)類型與靜態(tài)類型在一種語言中待牵,這樣可以在必要的時(shí)候取長(zhǎng)補(bǔ)短(下面在第4節(jié)中:在Scala語言的特色時(shí)介紹).

現(xiàn)在開發(fā)效率比以前高多了其屏,主要原因是因?yàn)殚_發(fā)語言和編譯器的進(jìn)步,這個(gè)趨勢(shì)缨该,只會(huì)繼續(xù)下去偎行,不要抱著過去的教條不放,java也是在不斷改進(jìn)的贰拿,加了reflection, 加了assert蛤袒,加了泛型,下個(gè)版本膨更,也要加腳本支持了妙真。

其實(shí)靜態(tài)類型語言,除了性能方面的考量之外荚守,最大的優(yōu)勢(shì)就是可以提供靜態(tài)類型安全珍德,編譯器可以檢查你的每一個(gè)函數(shù)調(diào)用是不是書寫了正確的名字,是不是提供了正確類型的參數(shù)矗漾。這樣一個(gè)系統(tǒng)菱阵,配合自定義類型的功能,可以讓很多錯(cuò)誤(比許多人想象的要多)在編譯時(shí)就能被發(fā)現(xiàn)和定位缩功。

1.2 缺點(diǎn)

缺點(diǎn)是為此需要寫更多的類型相關(guān)代碼晴及,導(dǎo)致不便于閱讀、不清晰明了嫡锌。

2 動(dòng)態(tài)類型語言

所謂的動(dòng)態(tài)類型語言虑稼,意思就是類型的檢查是在運(yùn)行時(shí)做的,比如如下代碼是不是合法的要到運(yùn)行時(shí)才判斷(注意是運(yùn)行時(shí)的類型判斷):

def sum(a, b):
return a + b

2.1 優(yōu)點(diǎn)

動(dòng)態(tài)類型語言的優(yōu)點(diǎn)在于方便閱讀势木,不需要寫非常多的類型相關(guān)的代碼蛛倦;動(dòng)態(tài)語言代表著更快更簡(jiǎn)單的技術(shù)大趨勢(shì),因此它將必然成為未來構(gòu)建軟件和互聯(lián)網(wǎng)技術(shù)的主角啦桌。

動(dòng)態(tài)語言足夠靈活溯壶,因此雖然它能夠讓人更集中精力思考業(yè)務(wù)邏輯的實(shí)現(xiàn),同時(shí)也向人工智能的方向走得更近一些甫男,但因此它也更依賴于開發(fā)人員本身的技術(shù)功底且改,初學(xué)者、中級(jí)開發(fā)者板驳,難以很好的利用它又跛。 而靜態(tài)類型語言,與我們計(jì)算機(jī)教學(xué)的基本科目(c/pascal/basic)延續(xù)性比較好若治,所以對(duì)于剛畢業(yè)的學(xué)生而言慨蓝,更好接受和學(xué)習(xí)感混。

2.2 缺點(diǎn)

缺點(diǎn)自然就是不方便調(diào)試,命名不規(guī)范時(shí)會(huì)造成讀不懂礼烈,不利于理解等弧满。

3 動(dòng)態(tài)類型語言的表達(dá)力

動(dòng)態(tài)語言通常更方便開發(fā)較小的項(xiàng)目,因?yàn)榭梢詿o需聲明類型而節(jié)省了很多麻煩此熬。另外一個(gè)答案是谱秽,動(dòng)態(tài)類型解除了程序員的束縛,可以最大的 發(fā)揮程序員的編程技能摹迷,能最有效的利用編程語言里的各種特征和模式疟赊。但這些能力都是一把雙刃劍,更多的依賴于程序員的個(gè)人才能峡碉,如果用不好近哟,或用的過度, 都會(huì)產(chǎn)生負(fù)面的害處鲫寄。

  • 觀點(diǎn)一:靜態(tài)類型語言因?yàn)轭愋蛷?qiáng)制聲明吉执,所以IDE可以做到很好的代碼感知能力刺覆,因?yàn)橛蠭DE的撐腰三妈,所以開發(fā)大型系統(tǒng),復(fù)雜系統(tǒng)比較有保障谤碳。

對(duì)于像Java來說未斑,IDEA/Eclipse確實(shí)在代碼感知能力上面已經(jīng)非常強(qiáng)了咕宿,這無疑能夠增加對(duì)大型系統(tǒng)復(fù)雜系統(tǒng)的掌控能力。但是除了Java擁有這么強(qiáng)的IDE武器之外蜡秽,似乎其他語言從來沒有這么強(qiáng)的IDE府阀。C#的Visual Studio在GUI開發(fā)方面和Wizard方面很強(qiáng),但是代碼感知能力上和Eclipse差的不是一點(diǎn)半點(diǎn)芽突。至于Visual C++根本就是一個(gè)編譯器而已试浙,更不要說那么多C/C++開發(fā)人員都是操起vi吭哧吭哧寫了幾十萬行代碼呢。特別是像Linux Kernel這種幾百萬行代碼寞蚌,也就是用vi寫出來的阿田巴,夠復(fù)雜,夠大型挟秤,夠長(zhǎng)生命周期壹哺。

  • 觀點(diǎn)二:靜態(tài)語言相對(duì)比較封閉的特點(diǎn),使得第三方開發(fā)包對(duì)代碼的侵害性可以降到很低煞聪。

也就是說靜態(tài)類型語言可以保障package的命名空間分割斗躏,從而避免命名沖突逝慧,代碼的良好隔離性昔脯。但是這個(gè)觀點(diǎn)也缺乏說服力啄糙。

靜態(tài)類型語言中C,VB都缺乏良好的命名空間分割,容易產(chǎn)生沖突云稚,但是并沒有影響他們做出來的系統(tǒng)就不夠大隧饼,不夠復(fù)雜。

而動(dòng)態(tài)類型語言中Ruby/Python/Perl都有比較好的命名空間静陈,特別是Python和Perl燕雁,例如CPAN上面的第三方庫成噸成噸的,也從來沒有聽說什么沖突的問題鲸拥。

誠(chéng)然像PHP拐格,JavaScript這樣缺乏命名空間的動(dòng)態(tài)語言很容易出現(xiàn)問題,但是這似乎是因?yàn)樗麄內(nèi)狈O機(jī)制導(dǎo)致的刑赶,而不是因?yàn)樗麄儎?dòng)態(tài)類型導(dǎo)致的吧捏浊?

說到大型系統(tǒng),復(fù)雜業(yè)務(wù)邏輯系統(tǒng)撞叨,Google公司很多東西都是用python開發(fā)的金踪,這也證明了動(dòng)態(tài)類型語言并非不能做大型的復(fù)雜的系統(tǒng)。其實(shí)我個(gè)人認(rèn)為:

動(dòng)態(tài)類型語言牵敷,特別是高級(jí)動(dòng)態(tài)類型語言胡岔,反而能夠讓人們不需要分心去考慮程序編程問題,而集中精力思考業(yè)務(wù)邏輯實(shí)現(xiàn)枷餐,即思考過程即實(shí)現(xiàn)過程靶瘸,用DSL描述問題的過程就是編程的過程,這方面像Unix Shell毛肋,ruby奕锌,SQL,甚至PHP都是相應(yīng)領(lǐng)域當(dāng)之無愧的DSL語言村生。而顯然靜態(tài)類型語言基本都不滿足這個(gè)要求惊暴。

那靜態(tài)類型語言的優(yōu)勢(shì)究竟是什么呢?我認(rèn)為就是執(zhí)行效率非常高趁桃。所以但凡需要關(guān)注執(zhí)行性能的地方就得用靜態(tài)類型語言辽话。其他方面似乎沒有什么特別的優(yōu)勢(shì)。

4 Java語言的問題

4.1 生產(chǎn)力問題

開發(fā)調(diào)試慢卫病,整體解決方案復(fù)雜油啤。這只是相對(duì)而言,對(duì)于熟練的開發(fā)這也許不是問題蟀苛,作為企業(yè)級(jí)解決方案而言益咬,Java語言確實(shí)比較繁重,即使依賴了很多自動(dòng)編譯帜平、動(dòng)態(tài)加載幽告、打包并部署的持續(xù)集成工具梅鹦,調(diào)試速度依然很慢,與現(xiàn)在的快節(jié)奏的開發(fā)要求有明顯矛盾. 不過, Java語言的生態(tài)不僅僅是語言, 而是JVM. 所以java語言只是JVM生態(tài)的一個(gè)語言.后來者, 有Scala, Groovy, Fantom, Clojure, Ceylon, Kotlin 和Xtend–mostly等.

4.2 表達(dá)力問題

總體來說Java語言的編寫過程更傾向于過程式的開發(fā)冗锁,在上一層面上封裝了面向?qū)ο蟮奶卣骱托袨槠胨簦Z言的設(shè)計(jì)是上個(gè)世紀(jì)九十年代的風(fēng)格,不是說語言本身不好是其抽象能力不夠冻河,即使到了Java8也只是對(duì)Lambda表達(dá)式進(jìn)行了支持箍邮,因此引入了Functional Interface也即只有一個(gè)方法的接口,和接口里邊的帶具體實(shí)現(xiàn)的方法(為了兼容以前的代碼不得不作出的讓步)叨叙。Java語言發(fā)展到現(xiàn)在其語言特性龐大锭弊,如果要完全了解需要幾百頁的文檔,在其發(fā)展過程中又只做加法沒又減法擂错,語言慢慢風(fēng)格混雜廷蓉,變成了現(xiàn)在這種四不像的狀態(tài),函數(shù)式的特性硬生生的嫁接在原來的面向?qū)ο筇匦灾稀?br> ??
????一段Java 實(shí)體類代碼

??
??

package com.femon.entity;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author 一劍 2015年12月23日 下午4:10:18
 */
@Entity
@Table(name = "cm_service")
public class Service {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private String name;
    private String host;
    private String requestUrl;
    private String responseBody;
    private String expect;
    private String method;
    private int paramsType;// 1 : 普通參數(shù)請(qǐng)求串query str
    // 2 : header參數(shù)
    // 3: 表單方式提交參數(shù)
    // 4: json post請(qǐng)求
    private String paramsMap;
    private String platform;// H5 Web App

    private int todaySuccessTimes;
    private int todayFailTimes;
    /**
     * 0 失敗 1 正常
     */
    private int state;

    private int totalSuccessTimes;
    private int totalFailTimes;
    private Date gmtCreate;
    private Date gmtModify;

    /**
     * platform.
     * 
     * @return the platform
     * @since JDK 1.7
     */
    public String getPlatform() {
        return platform;
    }

    /**
     * platform.
     * 
     * @param platform
     *            the platform to set
     * @since JDK 1.7
     */
    public void setPlatform(String platform) {
        this.platform = platform;
    }

    public String getParamsMap() {
        return paramsMap;
    }

    public void setParamsMap(String paramsMap) {
        this.paramsMap = paramsMap;
    }

    public Date getGmtCreate() {
        return gmtCreate;
    }

    public void setGmtCreate(Date gmtCreate) {
        this.gmtCreate = gmtCreate;
    }

    public Date getGmtModify() {
        return gmtModify;
    }

    public void setGmtModify(Date gmtModify) {
        this.gmtModify = gmtModify;
    }

    public int getTodaySuccessTimes() {
        return todaySuccessTimes;
    }

    public void setTodaySuccessTimes(int todaySuccessTimes) {
        this.todaySuccessTimes = todaySuccessTimes;
    }

    public int getTodayFailTimes() {
        return todayFailTimes;
    }

    public void setTodayFailTimes(int todayFailTimes) {
        this.todayFailTimes = todayFailTimes;
    }

    public int getTotalSuccessTimes() {
        return totalSuccessTimes;
    }

    public void setTotalSuccessTimes(int totalSuccessTimes) {
        this.totalSuccessTimes = totalSuccessTimes;
    }

    public int getTotalFailTimes() {
        return totalFailTimes;
    }

    public void setTotalFailTimes(int totalFailTimes) {
        this.totalFailTimes = totalFailTimes;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl;
    }

    public String getResponseBody() {
        return responseBody;
    }

    public void setResponseBody(String responseBody) {
        this.responseBody = responseBody;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getExpect() {
        return expect;
    }

    public void setExpect(String expect) {
        this.expect = expect;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public int getParamsType() {
        return paramsType;
    }

    public void setParamsType(int paramsType) {
        this.paramsType = paramsType;
    }

    /**
     * TODO
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Service [id=" + id + ", name=" + name + ", host=" + host + ", requestUrl=" + requestUrl
                + ", responseBody=" + responseBody + ", expect=" + expect + ", method=" + method + ", paramsType="
                + paramsType + ", paramsMap=" + paramsMap + ", platform=" + platform + ", todaySuccessTimes="
                + todaySuccessTimes + ", todayFailTimes=" + todayFailTimes + ", state=" + state + ", totalSuccessTimes="
                + totalSuccessTimes + ", totalFailTimes=" + totalFailTimes + ", gmtCreate=" + gmtCreate + ", gmtModify="
                + gmtModify + "]";
    }}
    
    
   
   
   

而其實(shí),我們?cè)缇椭?雖然這些 getter,setter都是模板化的東西, 可以自動(dòng)生成的,但是這么冗余的代碼,看起來還是不爽!那些寫Java代碼的牛逼程序員老鳥們里面有一個(gè)叫Martin Odersky的, 就整了一個(gè)基于JVM的支持函數(shù)式又無縫融合OOP的程序設(shè)計(jì)語言Scala. 這樣的實(shí)體類代碼,在Scala中寫作如下:


package com.steda.entity

import java.util.Date
import javax.persistence.{Entity, GeneratedValue, GenerationType, Id}

import scala.beans.BeanProperty

@Entity
class TedaCase {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @BeanProperty
  var id: Long = _
  @BeanProperty
  var name: String = _
  @BeanProperty
  var interfaceId: Long = _
  @BeanProperty
  var paramJsonStr: String = _
  @BeanProperty
  var expectOutput: String = _
  @BeanProperty
  var actualOutput: String = _
  @BeanProperty
  var dataSourceId: Long = _
  @BeanProperty
  var clearSql: String = _
  @BeanProperty
  var tddlApp: String = _
  @BeanProperty
  var state: Integer = _
  @BeanProperty
  var runTimes: Integer = _
  @BeanProperty
  var owner: String = _
  @BeanProperty
  var gmtCreate: Date = _
  @BeanProperty
  var gmtModify: Date = _
}

我們?cè)倏匆粋€(gè)Controller層的寫作, Scala可以與Java生態(tài)中優(yōu)秀的框架無縫融合, 比如Spring,Junit. 尤其當(dāng)今發(fā)展勢(shì)頭正猛的SpringBoot, JPA等框架, 更是大大的提升了開發(fā)測(cè)試的生產(chǎn)力.

<pre><code>

package com.steda.controller

import java.util.Date

import com.steda.dao.{DataSourceDao, TedaCaseDao}
import com.steda.entity.TedaCase
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.ui.Model
import org.springframework.util.StringUtils
import org.springframework.web.bind.annotation._
import org.springframework.web.servlet.ModelAndView

@RestController
@RequestMapping(Array("/tedacase"))
class TedaCaseController @Autowired()(
private val tedaCaseDao: TedaCaseDao,
private val dataSourceDao: DataSourceDao) {

@RequestMapping(Array("/newPage/{interfaceId}"))
def goNewPage(@PathVariable(value = "interfaceId") interfaceId: Long, model: Model): ModelAndView = {
model.addAttribute("dataSources", dataSourceDao.findAll())
model.addAttribute("interfaceId", interfaceId)
new ModelAndView("/tedacase/new")
}

@RequestMapping(Array("/editPage/{id}"))
def goEditPage(model: Model, @PathVariable(value = "id") id: Long): ModelAndView = {
val tedacase = tedaCaseDao.findOne(id)
model.addAttribute("tedacase", tedacase)
model.addAttribute("dataSources", dataSourceDao.findAll())
new ModelAndView("/tedacase/edit")
}

@RequestMapping(Array("/detailPage/{id}"))
def goDetailPage(model: Model, @PathVariable(value = "id") id: Long): ModelAndView = {
val tedacase = tedaCaseDao.findOne(id)
model.addAttribute("tedacase", tedacase)
new ModelAndView("/tedacase/detail")
}

@RequestMapping(value = {
Array("", "/")
}, method = Array(RequestMethod.GET))
def list(model: Model, @RequestParam(value = "tedaCaseName", required = false) tedaCaseName: String): ModelAndView = {
var tedaCases: java.util.List[TedaCase] = new java.util.ArrayList[TedaCase]
if (!StringUtils.isEmpty(tedaCaseName)) {
tedaCases = tedaCaseDao.findByName(tedaCaseName)
} else {
tedaCases = tedaCaseDao.findAll()
}
model.addAttribute("tedaCases", tedaCases)
model.addAttribute("tedaCaseName", tedaCaseName)
new ModelAndView("/tedacase/list")
}

@RequestMapping(value = Array("/postnew"), method = Array(RequestMethod.POST))
@ResponseBody
def newOne(@RequestParam(value = "name") name: String, @RequestParam(value = "interfaceId") interfaceId: Long,@RequestParam(value = "paramJsonStr") paramJsonStr: String,@RequestParam(value = "expectOutput") expectOutput: String, @RequestParam(value = "owner") owner: String,@RequestParam(value = "clearSql") clearSql: String, @RequestParam(value = "dataSourceId") dataSourceId: Long, @RequestParam(value = "tddlApp") tddlApp: String) = {
val teda = new TedaCase()
teda.clearSql = clearSql
teda.dataSourceId = dataSourceId
teda.interfaceId = interfaceId
teda.tddlApp = tddlApp
teda.expectOutput = expectOutput
teda.owner = owner
teda.paramJsonStr = paramJsonStr
teda.name = name
teda.state = -1 // -1 未執(zhí)行 0 失敗 1 成功
teda.runTimes = 0
teda.gmtCreate = new Date()
teda.gmtModify = new Date()
tedaCaseDao.save(teda)
}

@RequestMapping(value = Array("/postedit"), method = Array(RequestMethod.POST))
@ResponseBody
def editOne(@RequestParam(value = "id") id: Long, @RequestParam(value = "name") name: String,@RequestParam(value = "paramJsonStr") paramJsonStr: String,@RequestParam(value = "expectOutput") expectOutput: String, @RequestParam(value = "owner") owner: String,@RequestParam(value = "clearSql") clearSql: String, @RequestParam(value = "dataSourceId") dataSourceId: Long, @RequestParam(value = "tddlApp") tddlApp: String) = {

val teda = tedaCaseDao.findOne(id)
teda.clearSql = clearSql
teda.dataSourceId = dataSourceId
teda.tddlApp = tddlApp
teda.expectOutput = expectOutput
teda.owner = owner
teda.paramJsonStr = paramJsonStr
teda.name = name
teda.gmtModify = new Date()
tedaCaseDao.save(teda)

}

}

</pre></code>

4.3 資源消耗問題

Java語言號(hào)稱一次編譯马昙,處處運(yùn)行桃犬,就在于它基于一個(gè)需要首先先安裝到他所謂的處處的JDK,通過JVM解析編譯完成后的字節(jié)碼來運(yùn)行,跟操作系統(tǒng)的接口也是在JVM托管的行楞。這樣的好處是JVM可以在實(shí)時(shí)運(yùn)行的時(shí)候?qū)ψ止?jié)碼進(jìn)行進(jìn)一步的優(yōu)化攒暇,也就是大名鼎鼎的JIT,問題是所有的機(jī)器上都要安裝可以兼容你的應(yīng)用程序的JDK,同時(shí)JVM啟動(dòng)消耗的資源不少子房,起碼數(shù)百M(fèi)形用,且啟動(dòng)速度緩慢,同樣的直接編譯成目標(biāo)操作系統(tǒng)二進(jìn)制可執(zhí)行程序的服務(wù)证杭,啟動(dòng)起來消耗的資源小很多且速度快了很多田度。

在當(dāng)前差異化的芯片結(jié)構(gòu)中,像C解愤、GO镇饺、RUST這種能直接運(yùn)行于操作系統(tǒng)之上不基于某些龐大繁重的VM之上還是很有必要的,比如物聯(lián)網(wǎng)的控制芯片送讲,通常內(nèi)存也只有幾百K奸笤,適用性更強(qiáng)一些,而且現(xiàn)在LLVM架構(gòu)的編譯器能夠帶來性能的大幅優(yōu)化哼鬓,所以編譯依然是一個(gè)很好的選擇监右,除非JIT能夠逆天的達(dá)到解釋執(zhí)行的極限,因此假如我們看到某些語言有Java語言的開發(fā)能力和內(nèi)存安全特性异希,依然是可以考慮的健盒。

5 Haskell, Go, Scala

5.1 Haskell

他雖然很老但是一直是作為學(xué)院派函數(shù)式語言的代表,其純函數(shù)式的特性和簡(jiǎn)潔漂亮的語法(糖)讓人看了非常舒服,在接觸了面向過程和面向?qū)ο蟮拈_發(fā)后扣癣,如果要學(xué)習(xí)一種新的寫代碼的思路惰帽,面向函數(shù)式的語言是目前最好的選擇了,而Haskell有是函數(shù)式語言的先驅(qū)和集大成者搏色,很多函數(shù)式語言的語法都是從Haskell借鑒來的善茎。

作為純函數(shù)式語言券册,Haskell將必然會(huì)產(chǎn)生Side-Effect的代碼比如IO操作放到了一起频轿,也即monad風(fēng)格的部分,而其他的函數(shù)可以保證完全的函數(shù)式特征烁焙,對(duì)于同樣的輸入無論運(yùn)行多少次結(jié)果都是一樣的航邢,跟數(shù)學(xué)中函數(shù)的定義一樣嚴(yán)格,函數(shù)式是一種CPU友好的語言骄蝇,在當(dāng)前多核計(jì)算機(jī)發(fā)展?fàn)顩r下膳殷,函數(shù)式可以讓程序非常安全的在多個(gè)核心上并發(fā)而不用擔(dān)心大量的數(shù)據(jù)交互和side-effect, 從而在語言編譯過程中能夠針對(duì)并發(fā)進(jìn)行大幅的優(yōu)化九火。語言本身的很多寫法也跟數(shù)學(xué)中的定義很接近赚窃,比如定義一個(gè)集合

ghci> [x*2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]

看起來很像數(shù)學(xué)定義,語言可謂優(yōu)雅漂亮岔激,看著很舒服勒极。作為學(xué)院派語言,語言自身設(shè)計(jì)的要求不可謂不嚴(yán)格虑鼎,完美的闡述了函數(shù)式是什么意思辱匿,但是語言的復(fù)雜度較高,學(xué)習(xí)曲線很陡峭炫彩,很難保證團(tuán)隊(duì)成員的接收程度匾七,也很難招到相關(guān)的技術(shù)人才。從效率上來講江兢,Haskell可以優(yōu)化的跟C語言的級(jí)別類似昨忆,但如果對(duì)某些特性不熟悉稍微改動(dòng)一些就會(huì)造成性能的大幅下降,對(duì)新手不算友好杉允。

同時(shí)在函數(shù)式不那么擅長(zhǎng)的領(lǐng)域Haskell的商業(yè)化程度很低扔嵌,我們不可能都用Haskell來寫一些語法解釋或者正則解析等,涉及IO的分布式存儲(chǔ)和計(jì)算都相對(duì)很初級(jí)夺颤,尤其是對(duì)于我們比較感興趣的數(shù)據(jù)挖掘機(jī)器學(xué)習(xí)領(lǐng)域沒有成熟的解決方案痢缎,對(duì)于Web項(xiàng)目支持的尚可,有優(yōu)秀的Yesod框架作為代表世澜。

總的來說独旷,Haskell值的學(xué)習(xí)但不會(huì)在大型的生產(chǎn)環(huán)境中使用。

5.2 Scala

Scala語言的出現(xiàn)目的很明確,感覺就是為了替代Java而存在嵌洼,在Java語言越來越力不從心的今天案疲,能夠有一門語言既繼承了它廣大的生態(tài)系統(tǒng),又能夠在表達(dá)能力和開發(fā)效率大大改進(jìn)的情況麻养,可以說是很有希望的褐啡。

Scala從一開始就是一門設(shè)計(jì)良好的語言,幾乎完美的集合了函數(shù)式的特性和面向?qū)ο蟮奶匦员畈m然他的函數(shù)式不是純函數(shù)式备畦。其面向?qū)ο蟮母杏X更像Ruby而不是Java,所有的東西都是對(duì)象许昨,包括簡(jiǎn)單類型例如Int懂盐,以及函數(shù)本身都是一種對(duì)象,這樣在這個(gè)層面實(shí)現(xiàn)了面向?qū)ο蠛秃瘮?shù)式的統(tǒng)一糕档。

Scala運(yùn)行于JVM之上莉恼,能夠無縫的使用所有的原來Java語言所開發(fā)的各種庫,語言上作為Java的超集速那,遷移過來只會(huì)更強(qiáng)大而不會(huì)打折俐银。

Java8的出現(xiàn)雖然增加了針對(duì)集合的stream api以及Lambda表達(dá)式這種函數(shù)式特性的支持,但只會(huì)讓人們覺得Java與Scala更像了端仰,即使Java在以后的發(fā)展過程中擁有了所有的Scala的能力.

打個(gè)比方一塊歪歪扭扭的經(jīng)過各種后期焊接所建造起來的機(jī)器和一個(gè)一開始就有目的的設(shè)計(jì)出來的結(jié)構(gòu)精密捶惜、風(fēng)格統(tǒng)一、表達(dá)高效的機(jī)器比較榆俺,后者更像前者的重構(gòu)售躁,而前者雖然如日中天但已經(jīng)是暮年的四不像,不停的往身上增加各種各樣的功能.

也許Java9會(huì)有進(jìn)步茴晋,但現(xiàn)在我看到Java8后反而更傾向于Scala陪捷。

Scala的元編程能力可以讓他修改自己的語言定義,不只是實(shí)現(xiàn)某些業(yè)務(wù)邏輯诺擅,這樣從符號(hào)層面上市袖,scala可以做到自洽,除了核心的一些規(guī)則烁涌,其他的都可以被自己根據(jù)狀態(tài)調(diào)整所修改苍碟,這種能力可以極大的擴(kuò)展語言自身的能力,當(dāng)然也帶來了一些負(fù)面效果撮执,每學(xué)習(xí)一種新的包不只是了解他的API微峰,而是學(xué)習(xí)了一種新的語言,風(fēng)格可能跟scala大不相同抒钱。

強(qiáng)有力的證明蜓肆,大數(shù)據(jù)生態(tài)系統(tǒng)代表-Spark&Kafka颜凯,一個(gè)是分布式計(jì)算一個(gè)是分布式大規(guī)模數(shù)據(jù)吞吐,都證明了Scala的開發(fā)能力和效率仗扬。

Scala的問題其實(shí)也有跟Java類似的地方症概,首先這個(gè)語言雖然是重新設(shè)計(jì)的,但是使用起來復(fù)雜度依然很高早芭,對(duì)于范型的繼承彼城,+-等范型標(biāo)注不好理解,

5.3 Go

Go語言目前呈現(xiàn)了很火爆的趨勢(shì)退个,由于其簡(jiǎn)單募壕,整個(gè)語言的specification也不過十幾頁,最多半天就能夠完全了解并上手寫一些小工具帜乞。GO語言最初是希望替代C和C++成為新的系統(tǒng)語言司抱,自帶GC垃圾回收筐眷,不過最終更多的是替代了python來開發(fā)一些服務(wù)或者工具黎烈,并沒有成為系統(tǒng)級(jí)別的語言。
??Go語言有很多的優(yōu)點(diǎn)匀谣,編譯速度快照棋,有協(xié)程和Channel做并發(fā)支持和通信,有很多官方的網(wǎng)絡(luò)協(xié)議的庫武翎,非常適合于寫一些網(wǎng)絡(luò)服務(wù)烈炭,啟動(dòng)一個(gè)http的接口服務(wù)只需要幾行代碼。目前github上也有大量的第三方項(xiàng)目使用go語言來開發(fā)應(yīng)用或者擴(kuò)展go的功能宝恶,在使用的時(shí)候直接import即可符隙。Go的多返回機(jī)制也還不錯(cuò),節(jié)省了大量的無意義數(shù)據(jù)結(jié)構(gòu)和不可讀的Map的使用垫毙,總的來說Go在其擅長(zhǎng)的領(lǐng)域生產(chǎn)力很高霹疫,寫起來比較流暢,靜態(tài)類型也足夠的安全综芥。目前Docker生態(tài)系統(tǒng)里邊的各種工具都是Go來寫的丽蝎。最新發(fā)布的1.5版本使得交叉編譯更加容易,靜態(tài)鏈接庫的方式使生成的可執(zhí)行文件在相同CPU架構(gòu)的操作系統(tǒng)都能運(yùn)行膀藐,減少了額外查找依賴的問題屠阻,對(duì)我們現(xiàn)在基本同構(gòu)的Linux服務(wù)器而言,也打到了一次編譯處處運(yùn)行的目的额各。同時(shí)Go語言在運(yùn)行時(shí)消耗的資源也比Java要小国觉,啟動(dòng)速度更快,確實(shí)是輕量級(jí)服務(wù)的優(yōu)選虾啦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末麻诀,一起剝皮案震驚了整個(gè)濱河市蚜枢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌针饥,老刑警劉巖厂抽,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丁眼,居然都是意外死亡筷凤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門苞七,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藐守,“玉大人,你說我怎么就攤上這事蹂风÷В” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵惠啄,是天一觀的道長(zhǎng)慎恒。 經(jīng)常有香客問我,道長(zhǎng)撵渡,這世上最難降的妖魔是什么融柬? 我笑而不...
    開封第一講書人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮趋距,結(jié)果婚禮上粒氧,老公的妹妹穿的比我還像新娘。我一直安慰自己节腐,他們只是感情好外盯,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翼雀,像睡著了一般饱苟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锅纺,一...
    開封第一講書人閱讀 52,337評(píng)論 1 310
  • 那天掷空,我揣著相機(jī)與錄音,去河邊找鬼囤锉。 笑死坦弟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的官地。 我是一名探鬼主播酿傍,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼驱入!你這毒婦竟也來了赤炒?” 一聲冷哼從身側(cè)響起氯析,我...
    開封第一講書人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎莺褒,沒想到半個(gè)月后掩缓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遵岩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年你辣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尘执。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舍哄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出誊锭,到底是詐尸還是另有隱情表悬,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布丧靡,位于F島的核電站蟆沫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窘行。R本人自食惡果不足惜饥追,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一图仓、第九天 我趴在偏房一處隱蔽的房頂上張望罐盔。 院中可真熱鬧,春花似錦救崔、人聲如沸惶看。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纬黎。三九已至,卻和暖如春劫窒,著一層夾襖步出監(jiān)牢的瞬間本今,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工主巍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冠息,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓孕索,卻偏偏與公主長(zhǎng)得像逛艰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子搞旭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容