对于云原生时代的后端业务开发和项目系统学习,选Go Or Java?

简介: 现在的后端主流语言无非是 C++、Go、Java、Python这几类,这4个语言是近些年来不同时代不同业务阶段的后端语言开发代表。

前言


现在的后端主流语言无非是 C++、Go、Java、Python这几类,这4个语言是近些年来不同时代不同业务阶段的后端语言开发代表。


Go是这两三年的后起之秀,其设计理念是“正交化组件设计的哲学”。目前大部分大厂的新型业务都开始全面拥抱Go了,我认为Go正是迎合云原生、云平台、云计算平台时代的最好语言。


正是因为Go轻量、上手快、强大的特点,所以Go运行起来成本相对来说会很低,对于部署、维护、运营、管理来说,都会简单很多。而上述的这些特点,也正是目前云生态最需要的东西。只要轻量、好维护、功能大,就意味着能够用最简单的成本做最需要做的事情。


Go用Runtime代替了虚拟机,所以对于磁盘空间、内存的需求都会比Java小很多,同时Go的语法比传统面向对象的语言会容易上手、简单很多,维护性、运营性都会非常好。而对于CPU性能要求,Go和Java是大相径庭的,差不了太多,而C++则是比不上Go和Java了。


Go因为其轻量、正交化组件设计哲学的设计理念,目前在生态上来说还没有像Java Spring一样的全家桶,但目前大厂已经对Go进行很多增量应用,并不用担心配套的一些框架、轮子等等。各个大厂已经开始让他们的Go项目具备了一定的可复用、可沉淀能力,能够用Go去完成各种应用方案。


开山之词:简洁度比较


Go 和 Java 都是 C 家族语言,所以它们具有相似的语法。因此,Java 开发人员可以很容易读懂 Go 代码,反之亦然。Go 不需要在语句末尾使用分号(’;’),只有少数情况例外。


Go 和 Java 都使用了垃圾收集器(GC),用来帮助防止内存泄漏。与 C++ 不同,C 家族的程序员需要处理内存泄漏问题。垃圾回收器是自动化内存管理的一个特性,减轻了程序员的负担。

Go 的 GC 并未使用“弱世代假设”,但它的表现仍然非常出色,并且 STW(Stop-the-World)的时间非常短。在 1.5 版中,STW 降得更多,并且很稳定,而在 1.8 版中,它降到了 1 毫秒以下。如下图所示。

Go 的 GC 只有少量的一些选项,即用于设置初始垃圾回收目标百分比的 GOGC 变量。而 Java 有 4 个不同的垃圾回收器,每个垃圾回收器都有大量的选项。


尽管 Java 和 Go 都被认为是跨平台的,但 Java 需要 Java 虚拟机(JVM)来解释编译后的代码,而 Go 是将代码编译成目标平台的二进制文件。与 Go 相比,Java 对平台的依赖程度更低,因为 Go 每次都需要为新平台编译二进制文件。从测试和 DevOps 的角度来看,分别为不同的平台编译二进制文件非常耗时,并且跨平台的 Go 编译在某些情况下不起作用,尤其是在使用 CGo 时。而对于 Java,你可以在安装了 JVM 的任何地方使用相同的 jar。Go 需要的 RAM 更小一些,并且不需要安装和管理虚拟机。


反射。Java 的反射更方便、更流行也更常用,而 Go 的反射似乎更复杂。Java 是一种面向对象的编程语言,因此除原始类型之外的所有东西都被视为对象。如果要使用反射,可以创建一个类,并从类中获取所需的信息,如下所示:通过简单的一些反射声明,就可以进行访问构造函数、方法和属性,然后调用或对它们赋值。

Go 没有类的概念,并且结构体只包含了已声明的字段。因此,我们需要借助“reflection”包来获得所需的信息:

由于 Go 中没有结构体的构造函数,所以很多原始类型必须单独处理,并且需要考虑到指针。在 Go 中,我们可以进行指针传递或值传递。Go 的结构体可以将函数作为字段。所有这些都让 Go 的反射变得更加复杂。


可访问性。Java 有 private、protected 和 public 修饰符,为数据、方法和对象提供了不同的访问作用域。Go 有与 Java 的 public 和 private 相似的 exported/unexported,但没有修饰符。以大写字母开头的所有内容都将被导出,对其他包可见,未导出(小写)的变量或函数仅在当前包中可见。


大不相同:Go的独特之处

Go 不是面向对象编程语言。Go 没有类似 Java 的继承机制,因为它没有通过继承实现传统的多态性。实际上,它没有对象,只有结构体。它可以通过接口和让结构体实现接口来模拟一些面向对象特性。此外,你可以在结构体中嵌入结构体,但内部结构体无法访问外部结构体的数据和方法。Go 使用组合而不是继承将一些行为和数据组合在一起。


Go 是一种命令式语言,Java 是一种声明式语言。Go 没有依赖注入,我们需要显式地将所有东西包装在一起。因此,在使用 Go 时尽量少用“魔法”之类的东西。一切代码对于代码评审人员来说都应该是显而易见的。Go 程序员应该了解 Go 代码如何使用内存、文件系统和其他资源。


Java 要求开发人员更多地地关注程序的业务逻辑,知道如何创建、过滤、修改和存储数据。系统底层和数据库方面的东西都是通过配置和注解来完成的(比如通过 Spring Boot 等通用框架)。我们尽可能把枯燥乏味的东西留给框架去做。这样做很方便,但控制也反转了,限制了我们优化整个过程的能力。


在Java中,定义变量得这样:String 变量;而Go中:需要这样定义:变量 string。


Go的并发

简单优雅的并发。Go 具有强大的并发模型,叫作“通信顺序进程”或 CSP。Go 使用 n-to-m 分析器,允许在 n 个系统线程中执行 m 个并发。启动并发例程非常简单,只需使用 Go 的一个关键字即可,例如:

go doWork()

这样就可以并发执行 doWork()。


进程之间的通信可以通过共享内存(不推荐)和通道来完成。我们可以使用与环境变量 GOMAXPROCS 定义的进程数一样多的核心,并带来非常健壮和流畅的并行性。默认情况下,进程数等于核心数。


Go 提供了一种特殊模式来运行二进制文件,并可以检测执行竟态条件。我们可以通过这种方式测试并证明自己的程序是不是并发安全的。

go run -race app.go

应用程序将在竞态检测模式下运行。

Go 提供了很多开箱即用且非常有用的基本功能,例如用于并发的“sync”包。“Once”类型的单例可以这么写:

sync 包还为并发 map 实现、互斥锁、条件变量和 WaitGroup 提供了一种结构体。atomic 包支持并发安全转换和数学运算——它们基本上是编写并发代码所需的一切。


Go的指针

通过指针,Go 可以更好地控制如何分配内存、垃圾回收器负载以及其他在 Java 中无法实现的性能调优。与 Java 相比,Go 更像是一种低级的语言,并且支持更容易、更快的性能优化。


Go的性能分析器

Go 的性能分析工具让性能问题分析变得便捷和轻松。Go 的分析器可以揭示程序的内存分配和 CPU 使用情况,并在可视化图形中展示出来,让性能优化变得非常容易。Java 也有很性能分析器,比如 Java VisualVM,但它们都比 Go 的复杂,而且依赖 JVM 的运行情况,因此它们提供的统计信息与垃圾回收器的运行相关。


Go的类型

“如果它走路像鸭子,并且像鸭子一样嘎嘎叫,那它一定就是鸭子”。在 Go 中就是这样的:无需定义某种结构体是否实现了给定的接口,只要这个结构体具有与给定接口相同的方法签名,那它就是实现了这个接口。这非常有用,作为代码库的调用端,你可以定义外部库结构体所需的任意接口。而在 Java 中,对象必须显式声明实现了哪些接口。


Go的CGo

Go 可以与 C 语言集成,因此你可以在 Go 项目中开发带有 C 代码片段的应用程序。开发人员可以使用 CGo 创建调用 C 代码的 Go 程序包。Go 为 exclude/include 给定平台的 C 代码片段提供了各种构建选项。


Go的将函数作为参数

Go 函数可以作为变量传递给另一个函数或作为结构体的字段。这种多功能性令人耳目一新。Java 8 引入了 lambda,但它们不是真正的函数,只是单函数对象。


同时函数也可以返回多个参数,这个也非常的有帮助对于日常开发。

瑕疵劣势:Go的不足


没有泛型

1.8版本之前没有泛型(除非通过接口来实现)。在 Go 中,如果在同一个包中有两个函数具有不同的参数但含义相同,必须给它们指定不同的名字。例如这段代码:

这样一来,你就会得到很多方法,它们做的事情差不多,但名字都不一样,而且看起来很“丑”。


另外,Go 也没有继承多态性。被嵌入到结构体里的结构体只知道其自己的方法,对“宿主”结构体的方法一无所知。对于像我这样的开发人员来说,这尤其具有挑战性,因为我们是从其他 OOP 语言(最基本的概念之一就是继承)过渡到 Go 的。


不过,随着时间的推移,我开始意识到这种处理多态性的方法只是另一种思维方式,而且是有道理的,因为组合比继承更加可靠,并且运行时间是可变的。


错误处理。在 Go 中,完全由你来决定返回什么错误以及如何返回错误,因此作为开发人员,你需要负责返回和传递错误。毫无疑问的是,错误可能会被隐藏掉,这是一个痛点。时刻要记得检查错误并把它们传递出去,这有点烦人,而且不安全。


当然,你可以使用 linter 来检查隐藏的错误,但这只是一种辅助手段,不是真正的解决方案。在 Java 中,处理异常要方便得多。如果是 RuntimeException,甚至不必将其添加到函数的签名中。

Go在1.18版本支持泛型,虽然泛型很方便,但它会增加复杂性,而且从类型系统和运行时方面来看,泛型的成本很高。在构建 Go 代码时,你需要处理各种不同的类型或使用代码生成。

没有注解

尽管可以用代码生成替换一部分编译时注解,但运行时注解是不能替换的。这是有道理的,因为 Go 不是声明式的,并且代码里不应该包含任何“魔法”。我喜欢在 Java 中使用注解,因为它们让代码更优雅、简单和简约。


在为 HTTP 服务器端点生成 swagger 文件时,注解会非常有用。目前在 Go 中需要手动编写 swagger 文件,或者为端点提供特别的注释。每次 API 发生改动时,这都是一件很痛苦的事情。但是,Java 中的注解就像是一种魔法一样,人们通常都不用去关心它们是怎么实现的。


依赖管理

Go 的依赖管理。我之前曾写过一篇关于如何使用 vgo 和 dep 在 Go 中进行依赖管理的文章。Go 的依赖管理的演变之路充满了坎坷。最初,除了“ Gopgk”之外没有其他依赖管理工具,后来发布了实验性的“Vendor”,后被“vgo”取代,然后又被 1.10 版“go mod”取代。如今,我们可以手动或者使用各种 Go 命令(例如“go get”)来修改 go.mod 文件描述符,但这也让依赖关系变得不稳定。


Java 有 Maven 和 Gradle 之类的声明式工具,用来进行依赖关系管理,也用于构建、部署和处理其他 CD/CI 任务。但是,在 Go 中,我们必须使用 Makefile、docker-composes 和 bash 脚本自定义构建所需的依赖管理,这只会使 CD/CI 的过程和稳定性变得更加复杂。


Go包的名称里包括了托管域名。例如:

import "github.com/pkg/main"

这是十分不方便的,因为你不能在不修改项目代码库导入的情况下用自己的实现替换别人的实现。


百家争鸣:主流语言对比

C:优势、缺点、就职方向

优势:底层编程、底层原理、适合编译器、JVM、驱动代码、操作系统内核、嵌入式应用代码等

缺点:开发门槛高、入手慢、理解起来较难、效率低

就职方向:嵌入式开发、物联网硬件、硬件驱动器


C++:优势、缺点、就职方向

优势:兼顾性能和大型软件的开发效率,主流后台服务器的开发语言(腾讯为代表的大厂)

缺点:入门门槛高、精通较难

就职方向:后台服务器、电脑客户端、后台开发、交易系统开发、游戏等


Java:优势、缺点、就职方向

优势:开发效率、性能、跨平台、门槛、生态都非常好,可以开发桌面应用程序、Web应用、分布式系统等

缺点:功能件太多、知识体系太过庞大、部署的东西较多

就职方向:电商系统、大数据处理、金融数据开发、安卓开发


Python:优势、缺点、就职方向

优势:简单易上手、开发工具不敏感

就职方向:人工智能、机器学习、测试开发、爬虫、自动化处理(文件、测开等)


Go:优势、缺点、就职方向

优势:轻量高并发、实现了开发效率和执行效率的完美结合,在多核并发上拥有原生的设计优势。适合服务端开发、分布式系统、微服务、云服务、网络编程、区块链、云平台等

缺点:中小厂用的比较少

就职方向:后台服务开发、云平台开发、分布式开发、区块链开发、架构师、微服务开发



相关文章
|
2天前
|
Java Apache Maven
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
15 6
Java百项管理之新闻管理系统 熟悉java语法——大学生作业 有源码!!!可运行!!!
|
1天前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
18 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
13天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
31 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
14天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
37 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
14天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
24 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
3天前
|
安全 Java API
Java 泛型在安卓开发中的应用
在Android开发中,Java泛型广泛应用于集合类、自定义泛型类/方法、数据绑定、适配器及网络请求等场景,有助于实现类型安全、代码复用和提高可读性。例如,结合`ArrayList`使用泛型可避免类型转换错误;自定义泛型类如`ApiResponse<T>`可处理不同类型API响应;RecyclerView适配器利用泛型支持多种视图数据;Retrofit结合泛型定义响应模型,明确数据类型。然而,需注意类型擦除导致的信息丢失问题。合理使用泛型能显著提升代码质量和应用健壮性。
|
1天前
|
存储 前端开发 Java
Java后端如何进行文件上传和下载 —— 本地版(文末配绝对能用的源码,超详细,超好用,一看就懂,博主在线解答) 文件如何预览和下载?(超简单教程)
本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。
32 1
|
1天前
|
前端开发 Java
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
文章介绍了如何使用SpringBoot创建简单的后端服务器来处理HTTP请求,包括建立连接、编写Controller处理请求,并返回响应给前端或网址。
8 0
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
|
1天前
|
存储 分布式计算 Java
Stream很好,Map很酷,但答应我别用toMap():Java开发中的高效集合操作
在Java的世界里,Stream API和Map集合无疑是两大强大的工具,它们极大地简化了数据处理和集合操作的复杂度。然而,在享受这些便利的同时,我们也应当警惕一些潜在的陷阱,尤其是当Stream与Map结合使用时。本文将深入探讨Stream与Map的优雅用法,并特别指出在使用toMap()方法时需要注意的问题,旨在帮助大家在工作中更高效、更安全地使用这些技术。
8 0
|
1天前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
9 0

热门文章

最新文章