go语言和java

一句话概括go语言和java的特点

  • Java「就业最好」:岗位多,工资高。这个趋势也许会持续5-10年。
  • Go语言「最有前途」,语言优秀,家底丰厚,但暂时就业岗位还不是很多。

语言特性

  • Go是一种命令式语言,
  • Java则是一种声明式语言。

Go语言

GO作为编程界的小鲜肉。进年来Go社区非常的活跃,高并发能力无人能及。即具有像Python一样的简洁代码、开发速度,又具有C语言一样的执行效率,优势突出。


还是从根本去了解Go语言吧

1. 设计Go语言是为了解决当时Google开发遇到的问题

  • 大量的C++代码,同时又引入了Java和Python
  • 成千上万的工程师
  • 数以万计行的代码
  • 分布式的编译系统
  • 数百万的服务器


2. Google开发中的痛点

  • 编译慢
  • 失控的依赖
  • 每个工程师只是用了一个语言里面的一部分
  • 程序难以维护(可读性差、文档不清晰等)
  • 更新的花费越来越长
  • 交叉编译困难


3. 如何解决当前的问题和痛点?

  • Go希望成为互联网时代的C语言。多数系统级语言(包括Java和C#)的根本编程哲学来源于C++,将C++的面向对象进一步发扬光大。但是Go语言的设计者却有不同的看法,他们认为值得学习的是C语言。C语言经久不衰的根源是它足够简单。因此,Go语言也是足够简单。
  • 所以,他们当时设计Go的目标是为了消除各种缓慢和笨重、改进各种低效和扩展性。Go是由那些开发大型系统的人设计的,同时也是为了这些人服务的;它是为了解决工程上的问题,不是为了研究语言设计;它还是为了让我们的编程变得更舒适和方便。
  • 但是结合Google当时内部的一些现实情况,如很多工程师都是C系的,所以新设计的语言一定要易学习,最好是类似C的语言;20年没有出新的语言了,所以新设计的语言必须是现代化的(例如内置GC)等情况。最后根据实战经验,他们向着目标设计了Go这个语言。


4. Go语言的特色

  • 没有继承多态的面向对象
  • 强一致类型
  • interface不需要显式声明(Duck Typing)
  • 没有异常处理(Error is value)
  • 基于首字母的可访问特性
  • 不用的import或者变量引起编译错误
  • 完整而卓越的标准库包
  • Go内置runtime(作用是性能监控、垃圾回收等)


5. Go语言的优势

5.1 学习曲线容易

Go语言语法简单,包含了类C语法。因为Go语言容易学习,所以一个普通的大学生花几个星期就能写出来可以上手的、高性能的应用。在国内大家都追求快,这也是为什么国内Go流行的原因之一。

5.2 效率:快速的编译时间,开发效率和运行效率高

开发过程中相较于 Java 和 C++呆滞的编译速度,Go 的快速编译时间是一个主要的效率优势。Go拥有接近C的运行效率和接近PHP的开发效率。

5.3 出身名门、血统纯正

之所以说Go出身名门,从Go语言的创造者就可见端倪,Go语言绝对血统纯正。其次Go语言出自Google公司,Google在业界的知名度和实力自然不用多说。Google公司聚集了一批牛人,在各种编程语言称雄争霸的局面下推出新的编程语言,自然有它的战略考虑。而且从Go语言的发展态势来看,Google对它这个新的宠儿还是很看重的,Go自然有一个良好的发展前途。

5.4 自由高效:组合的思想、无侵入式的接口

Go语言可以说是开发效率和运行效率二者的完美融合,天生的并发编程支持。Go语言支持当前所有的编程范式,包括过程式编程、面向对象编程、面向接口编程、函数式编程。程序员们可以各取所需、自由组合、想怎么玩就怎么玩。

5.5 强大的标准库

这包括互联网应用、系统编程和网络编程。Go里面的标准库基本上已经是非常稳定了,特别是我这里提到的三个,网络层、系统层的库非常实用。**Go 语言的 lib 库麻雀虽小五脏俱全。**Go 语言的 lib 库中基本上有绝大多数常用的库,虽然有些库还不是很好,但我觉得不是问题,因为我相信在未来的发展中会把这些问题解决掉。

5.6 部署方便:二进制文件,Copy部署

这一点是很多人选择Go的最大理由,因为部署太方便了,所以现在也有很多人用Go开发运维程序。


6. Go开源项目

: 无人不知的虚拟化平台,开源的应用容器引擎,借助该引擎,开发者可以打包他们的应用,移植到任何平台上。

: go本身,也是用go语言实现的,包括他的编译器,要研究go源代码的可以看此项目录

: Google出品,用于调度和管理docker的开源容器管理系统,利用他,可以方便的管理你的docker实例,哪怕非常多,也是目前最流行的docker管理系统。

: 一款基于git的代码托管系统,类似于github和gitlab,不过其小巧易用,功能强大,部署方便,也有不少用户在使用。

: 开源的文件同步系统,它使用了其独有的对等自由块交换协议,速度很快,据说可以替换BitTorrent Sync。

: 一款开源监控度量的看板系统,可以接Graphite、Elasticsearch、InfluxDB等数据源,定制化很高。

: 一款分布式的,可靠的K-V存储系统,使用简单,速度快,又安全。

: 一款更便捷使用github的工具,包装并且扩展了git,提供了很多特性和功能,使用和git差不多。

: 可伸缩的数据库,使用场景主要用来存储测量数据,事件点击以及其他等实时分析数据,用来做监控性能很不错。

: 快速的,跨平台的HTTP/2 Web服务器。

: 国产开源的高性能Web框架,让你快速的开发Go Web应用服务,谢大主笔。


7. Golang资料补给包


Go与java对比

语法对比

功能对比

异常错误处理对比

错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是 。

错误和异常需要分类和管理,不能一概而论。错误和异常的分类可以以是否终止业务过程作为标准错误是业务过程的一部分,异常不是不要随便捕获异常,更不要随便捕获再重新抛出异常。


Java中,Throwable是所有错误(Error)和异常 (Exception) 的基类,整的来说,它们都是程序运行过程中可能出现的问题,区别在哪里呢? Exception是可预料的,而Error是不可预料的。Exception我理解为在程序运行中正常情况下意料之中发生的事,是可以被程序员处理,补救,有机会回到正常处理流程的,而Error在程序运行中非正常情况下发生后是无法被处理,恢复,比如内存溢出,栈溢出等。


Go中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error。error处理过程类似于C语言中的错误码,可逐层返回,直到被处理。

Golang中引入两个内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。

Recover之后还是被返回Error所处理,什么含义呢,就是在意料之外的panic发生时,在defer中通过recover捕获这个恐慌,转化为错误通过方法返回值告诉方法调用者。

其实从字面意思,Go中弱化了异常,一切皆错误,都被包装成类似Code,Message的形式返回方法调用者,直到有调用者去处理, 这也是Go的设计精髓,简化没必要存在的。


错误处理

在Go代码中 if err!=ni 随处可见,尤其是业务代码开发中。Go没有类似 try catch 这样的语句,Go对错误的价值观是可编程,我们看下面的代码:

从顺序角度来看,Go更能被理解,每一个方法都有一个结果值和一个可能发生的错误值,Go中程序员对err有更多的操作空间,有更多的可编程性。Java需要更多的语法和更多理解,Java中相对可编程性弱化了许多。


异常处理

Java中通过 throw new 抛出一个异常,通过 tryca che捕获,而Go中通过 panic抛出一个恐慌,通过 defer和recover来处理,实现类似的功能。代码如下:

对Java异常包装后是否和Go的错误设计有异曲同工之妙,同样的Go通过panic和defer,recover也可以为try,cache, throw这样的处理,但语言层面的设计的本质是不一样的。


Java中对异常和错误有一个比较清晰的边界,通过类继承体系进行隔离,错误并不在程序员的考虑范围之内,通过异常体系和控制流程来实现业务逻辑,往往也容易被滥用;而Go中并没有,且弱化了异常的概念,并提供了将异常转化为错误的方法。一切皆错误,拥有更好的可编程性,但同时也带来诸如 iferr!=nil的这样的代码到处都是,不同的编程语言对异常错误体系设计不一样,也代表不同开发者的思想,没有对与错。


并发包对比


内存管理对比

堆内存管理

Go 语言的内存分配器就借鉴了 TCMalloc(Thread-Caching Malloc) 的设计实现高速的内存分配,它的核心理念是使用多级缓存根据将对象根据大小分类,并按照类别实施不同的分配策略。Go 语言的内存分配器会根据申请分配的内存大小选择不同的处理逻辑,运行时根据对象的大小将对象分成微对象((0, 16B))、小对象([16B, 32KB])和大对象((32KB, +∞))三种。内存分配器不仅会区别对待大小不同的对象,还会将内存分成不同的级别分别管理,TCMalloc 和 Go 运行时分配器都会引入线程缓存(Thread Cache)、中心缓存(Central Cache)和页堆(Page Heap)三个组件分级管理内存。这些都可以理解为基于基础字段类型、工程中对象大小现状等做的一些约定优化。


为了让内存回收更加高效,从Sun JDK 1.2开始对堆采用了分代管理方式。可以氛围年轻代和老年代。当年轻代需要回收时会触发Minor GC(也称作Young GC)。对象在被创建时,内存首先是在年轻代进行分配(注意,大对象可以直接在老年代分配)。年轻代由Eden Space和两块相同大小的Survivor Space(又称S0和S1)构成。老年代用于存放在年轻代中经多次垃圾回收仍然存活的对象,可以理解为比较老一点的对象。


垃圾回收

Java和Go语言都有垃圾回收器,会自动清理堆内存中已经不再使用的dead内存对象。两者垃圾回收的算法基础都是标记清除(Mark-Sweep)算法。标记清除收集器是跟踪式垃圾收集器,其执行过程可以分成标记(Mark)和清除(Sweep)两个阶段:标记阶段 — 从根对象出发查找并标记堆中所有存活的对象;清除阶段 — 遍历堆中的全部对象,回收未被标记的垃圾对象并将回收的内存加入空闲链表。

go为了解决原始标记清除算法带来的长时间 STW(Stop The World),多数现代的追踪式垃圾收集器都会实现三色标记算法的变种以缩短 STW 的时间。详细参考go内存总结。该算法目前在java的GC中还未采用。


Java 中针对不同代的内存特定,提出了包含线性、并发、并行标记清除和 G1 四个垃圾收集器。可以在命令行中选择。因为他需要平衡其他各种因素,因此没有一个 GC 算法的目标能将暂停时间降低到 Go 水平。可以通过重新启动程序在 GC 之间切换,因为编译是在程序运行时完成(这里指 JIT 编译器),所以不同算法所需的不同内存屏障可以根据需要编译和优化到代码中。Go 的垃圾收集器是一个并发的,三色,标记扫描收集器,这是一个由 Dijkstra 在 1978 年首次提出的想法。


Java GC默认算法是吞吐量收集器(throughput collector),默认情况下没有任何暂停时间目标。这种默认选择也是人们认为 Java GC 有点吸引力的一个原因:开箱即用,它试图使您的应用程序尽可能快地运行,并尽可能少的内存开销,而暂停时间不是该算法首要考虑的。Go 将暂停时间优化作为首要目标,以至于它似乎愿意将程序减慢至任何数量级,以获得较短暂停。