今天我们来聊一下Go 和Java,本篇文章主要是想给对后台开发的初学者和有意向选择Go语言的有经验的程序员一些建议,希望能帮助各位自上而下的来了解一下Java和Go的全貌。
作为一个多年的Java后端开发,用的时间久了就会发现Java语言一些问题,所谓婚前风花雪月,婚后柴米油盐,当年那些吸引我的优点,现在在我看来已经成缺点。而这个时候Go出现了,它带着更好的背景,更便利的语法,更快的速度来了,之前怕它乱来,但是也怕它不来,现在它来了,来的正当时。
当年Java凭借着跨平台和自动GC,并借着互联网的东风,迅速蹿红,并在移动互联网时代彻底爆发,随着多核处理器的普及和云原生的到来,Java的问题也逐渐显现:
内核线程模型
而此时Go这个天生并发、语法简洁跨平台的语言初露锋芒,在这个并发时代,Go如鱼得水,回想当年Java的如日中天,彼时彼刻恰如此时此刻。
接下来我们从多个维度对比一下Go和Java,
随着越来越多的后台Java应用转移到Go, 我觉得有必要来深入的聊一聊这两个语言了,我们从 语言层面(语言特性、速度和易用性、内存使用等方面)
、 社区活跃度
来PK一下,进而总结出这两个 语言的优缺点
以及这两个语言的 开发方向
,并给各位正在纠结下个项目要不要用Go的开发者一些 建议
。
简洁性
Go 是一种 极简主义语言 ,是一种静态类型、编译、多范式和通用的编程语言,正式的Go 语言规范只有 50多页,有很多例子,而且相当容易阅读,这使得学习语言和阅读和编写程序变得更容易。
而Java® 语言规范目前有700多页。大部分复杂性是由于 持续扩展或添加新功能 造成的。
Go 和 Java 都是 C 家族语言,所以它们具有相似的语法。因此,Java 开发人员可以很容易读懂 Go 代码,反之亦然。Go 不需要在语句末尾使用分号( ;
),只有少数情况例外。相对来说说,Go 的行分隔方式更清晰,更易读。
面向对象
Java是面向对象的语言,有完整的继承体系,方便的实现多态的机制,能灵活的构造可重用性和易维护性的代码,并且通过OOP能简洁的实现反射机制。这些特性非常符合构造复杂的项目,但由于复杂性同时也导致编码的成本提升。
比如Java的反射实现就很简单,他只需要获取类中的信息就可以:
Class clazz = o.getClass(); Constructor cs = clazz.getConstructor(); Method[] methods = cs.getDeclaredFields();
而Go不是面向对象的,它没有传统意义上的继承或反射,构建系统通过组合和嵌入结构体的方式来实现,也就是所说的 鸭子类型 ,多态也是通过接口来实现的,Go 没有类的概念,并且结构体只包含了已声明的字段。因此,我们需要借助“reflection”包来获得所需的信息:
type Foo struct {
A int `tag1:"First Tag"
tag2:"Second Tag"`
B string
}
f := Foo{A: 10, B: "Salutations"}
fType := reflect.TypeOf(f)
switch t.Kind(fType)
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
// ...
}
}
虽然这不是一个大问题,但由于 Go 中没有结构体的构造函数,所以很多原始类型必须单独处理,并且需要考虑到指针。在 Go 中,我们可以进行指针传递或值传递。Go 的结构体可以将函数作为字段。所有这些都让 Go 的反射变得更加复杂。除此之外,虽然整体上灵活度不如Java,但是它易于编写和维护。
并发性
Go 作为一种为现代多核计算机设计的语言,简单优雅的并发,并且具有强大的并发模型,其设计基于 两级线程模型改进的GMP模型 ,这样能大大减少并发切换线程的性能开销,而且这些模型统一封装到语言级别的调度层,只需通过关键字 go
就可以开启协成,提高了易用性。
Java语言上没有协成的概念,Java的线程模型依然用的 内核级线程模型 ,多线程开发依然需要复杂的实现,而且实现方式有很多种而不用拖着一个像,你需要了解每种实现方式的优缺点才能写出高性能的代码,除了这些还需要了解各种锁,来保障你写的线程是安全的。具体可以看之前的一篇文章线程的实现方式: 线程实现千种百种,而我却独终你那一种 。
内存管理
Go 的主要功能之一是垃圾收集,尽管 Java 也有垃圾收集,但它并没有Go的那么快,虽然随着G1和ZGC的出现缩短了与Go的差距,但显然Go更擅长管理内存。它不包含引用链接,而是包含指针,而且Go的垃圾收集器经过大量优化以防止STW。整体上Go的垃圾收集方法更精细。这点我们后面会出单独的文章来详细聊聊
其他
除了以上的语言特性,还有:
异常:Go 不使用异常,而是使用错误(error)来表示诸如文件结束之类的事件,并使用运行时恐慌(panic)来表示运行时错误,例如尝试索引数组越界。
泛型:Java的泛型通过类型擦除来实现,使一些代码更清晰,但是不支持泛型数组,并且具有上限和下限的类型通配符等,这让编码变得很复杂。而Go泛型没有Java的复杂,它有一些内置的泛型数据类型,比如,切片和map等,使用起来比较方便清晰易懂。
安全性:Java语言本身并不能保护你免受漏洞的侵害,但它的某些功能可以使您免受常见的安全漏洞的侵害。比如没有指针能避免一些未经授权的访问内存操作。其次Java有不同权限的访问修饰符,为每个应用程序创建不同级别的访问权限。从 Go 1.13 开始,go 命令默认使用 Go 模块镜像和 Go 校验和数据库下载和验证模块,语言层面内置安全策略。具体可查阅 Go Module 镜像、索引和校验和数据库
Java自1995年以来一直存在,它还用于很多设备,而且由于它的向上兼容性,导致了很多功能本可以基于新的标准重新实现以提高性能,但恰恰因为兼容性让他放弃了这些,所以有很多功能效率依然是之前的标准编写的。
而Go是没这个问题的,因为它的库要比Java小的多,而且是按照现代的标准编写的,因此性能上更胜一筹。
由于Java的语法标准比较多样化,导致每个程序员写出来的Java代码都有不同的风格,而Go从设计之处就考虑到这一点,Go的代码更加的简洁和紧凑,它删除了不必要的括号和一些多余的符号,这也减少了出错的概率,更加的易于编写。
所以在编码速度和易用性上Go更胜一筹。
众所周知,Java是JVM平台的语言,一处编译处处运行,这个是Java引以为傲的优点,但它的运行时环境必须在JVM上,这就导致了Java运行时的臃肿,浪费了一部分资源。
而Go通过编译成可执行文件巧妙的解决了这个问题,虽然它不是跨平台性语言,但它在编码器层面依然可以实现一套代码编译出不同平台的执行文件,可以直接在各个平台上运行,而不用拖着一个想JVM一样的运行时环境。
Go运行时环境就是系统环境,而Java还需要一个虚拟机环境(JVM), 所以在这一点上我觉得Go这种是比较好的。
Java已经存在了很长时间,几乎所有的web开发、后台开发、Android开发都在使用它,成千上万的人活跃在Java社区并提供大量的开源支持,对于后台开发有着一套完整的解决方案,比如,spring体系可以构建出一套高性能且稳定的服务。
而Golang算是个新项目,虽然社区一样很活跃,但依然弥补不了它资源匮乏的事实,虽然对于后台开发也有整套的方案,但它还远不足以匹敌Java。
其实除了上面这些维度,还有很多维度,比如泛型,异常,函数式编程等语法特点,这些我们就一笔带过了,那么基于以上的比较我们可以总结一下这两个语言的优缺点:
Go的优点
缺点
Java的优点
缺点
没有一种语言适合所有的工作,但有些语言比其他语言更适合更多的工作。
Go 最适合开发以下类型的应用程序
Web 服务器
、 API
、 应用框架
、 分布式存储服务
等。Docker
、 Kubernetes
和 Istio
等。Java开发的方向
Java和Go都是高级语言,相比于C++、C有更好的可读性。Java是面向对象的,一种基于对象和行为而不是功能和逻辑组织的软件模型,并且OOP可以提供极大的可重用性和效率,相对于Go可能比较难上手。而Go语言语法简洁并且是一个比较新的语言,对初学者更加的友好。
结论:Go 更适合初学者,并且被认为比 Java 更容易学习。
其实对于有经验的程序员来说,很难找到不懂Java的,就当前的各大厂商来看,国内的一线厂商都逐渐向Go靠拢,Google、Facebook、BAT、字节、小米、京东等对Go工程师的需求都很高,如果你是后台开发有机会建议深入的学习一下,就像我们公司招不来Go开发都是招Java开发来写Go的。。。
结论: 学
小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。如果在阅读过程中有疑问,请留言讨论,最后祝愿各位顺利拿到心仪的offer。