首页 > 尝试Java,从入门到Kotlin(上)

尝试Java,从入门到Kotlin(上)

之前一直使用C#开发,最近由于眼馋Java生态环境,并借着工作服务化改造的契机,直接将新项目的开发都转到Java上去。积攒些Java开发经验,应该对.NET开发也会有所启发和益处。

从理论上说,Java和C#语言差别不大,毕竟难听地说,C#就是抄Java出来的。程序语言简史如是介绍这两种语言:

576869-20181201130818044-2137394956.png

然而随着时间流逝语言发展,个人认为,C#在语言层面已经大大领先了Java。关于Java和C#的比较这几篇文章http://blog.zhaojie.me/2010/04/why-java-sucks-and-csharp-rocks-1-thoughts-and-goals.html有着详细的描述。下面我总结一下我在趟过的坑,以供转型或学习的同学参考。

本文并非要比出这些语言谁优谁劣。有时候,好或坏是非常主观的判断,不同人有着不同的看法,强行断定好坏只会引起无畏的争论。这些语言有着各自的特点,有各自适合的场景。就像下面要谈到的Checked Exception特性,这是个很好的特性,但是在一些情况下也会引起不少麻烦。

Checked Exception

Java是Checked Exception的。这就是说,如果你写了一个方法,这个方法会抛出一些异常,那么你需要用throws关键字标明这个方法会抛出哪些异常。这个特性很难说是好还是不好。Checked Exception本质上是一种类型系统,它明确规定了一个方法除了返回值类型以外,还可能抛出什么异常。这样调用方函数就能够明确地知晓应该处理或者传递哪些异常。这个特性在用得好的人手里,对正确处理各种边边角角的异常十分有用。然而,如果在你无法自己选队友,无法控制开发人员的水平的情况下,你很可能会发现,所有的方法都被标记为throws Exception

Lambda,以及与Checked Exception产生的奇怪反应

Java的Lambda本质上仍然是一个对象。事实上,Java的Lambda函数是一个满足Functional Interface接口的对象。比如下面代码,声明了一个具有一个int参数,返回一个int参数的函数。

@FunctionalInterface
interface AFunction {int invokeBalaBala(int a);
}

我们可以这样定义一个这个函数的变量:AFunction f = x -> 2 * x;

Java的Lambda和Checked Exception结合在一起后,产生了一个非常棘手的问题。由于Checked Exception是类型系统的一部分,一个不抛出异常的函数和一个会抛出异常的函数,它们的类型是不相同的。这就导致了Java的Lambda泛用性大大减少而且不是很好用。以对List的map操作为例,我们可以用如下代码将list里的每个元素翻倍:

list = list.stream().map(x -> 2 * x).collect(Collectors.toList());

这里map接收一个类型为输入一个int参数,返回一个int值的函数。然而,如果我们需要给它的函数有可能抛出异常,比如这个函数会去读取文件、访问网络服务、或者做Json反序列化,则由于类型不同,Java编译器将会报错。

// 这个编译器会报错
list.stream().map(x -> JsonUtil.parse(x)).collect(Collectors.toList());

解决方案一种是在函数体中使用try cache处理异常。但是很多时候,异常没办法在这个时刻处理,必须要抛出。那么还有另一种方案:将异常转换为RuntimeExceptionRuntimeException是所谓的Unchecked Exception,它不是类型系统的一部分,不需要用throws标注,所以不会导致函数类型变化。另一方面,编译器也无法检测出是否可能会抛出RuntimeException。无论采用哪种方案,都使得这个Lambda函数变得没那么好看。

泛型

Java的泛型原理和C#不同。C#是运行时泛型,在程序运行的时候仍然能获取泛型的类型信息。而Java的泛型是类型擦除(Type Erasure)式泛型。名称听起来很高大上,意思是Java的泛型仅仅用于编译时类型检查,类型检查完成后,类型信息就被编译器擦除。在最后生成的字节码中中,泛型类型都被改为Object类型。

比如这句:

HashMap map = new HashMap();

编译后变成:

HashMap map = new HashMap();

Type Erasure方式的影响主要有两个:

  • 运行时无法判断类型;
  • 运行时无法动态生成泛型具现化的类的实例。

像下面两句:

x instanceof T
new T()

在Java中都会编译出错。而这在C#中都是很常见的代码。在C#中,我们可以有这样的Json反序列化方法:

T parse(string jsonStr)

这个方法将jsonStr反序列化为类型T的一个对象。这种写法看起来十分自然。然而在Java中无法实现。因为在parse方法中需要在运行时实例化T的一个对象,而Java在运行时这些泛型都已经被擦除,无法获取类型T的信息,从而无法实例化。要在Java实现类似的方法,需要额外将一个Class对象放到参数:

T parse(String jsonStr, Class type)

这样Java才能使用这个type,在运行时使用反射的方式生成类型T的实例。

Getter/Setter

在面向对象哲学中,字段属于实现细节,应该设为private使它隐藏在类的内部。但是在实际中,有很多字段需要直接访问和修改。从功能实现上讲,直接把字段设为public也是可以的。但是这样做的坏处在于未来功能扩展时,这个字段的含义、存储方式可能发生变化,导致每个使用了这个字段的代码都需要修改。因此,应该将字段的访问封装的方法中,即使只是很简单的访问和设置,也应该实现getter方法和setter方法。

C#和Python有property特性支持快速定义和调用getter方法和setter方法。Ruby则依靠函数调用可以省略括号的特性,使getter方法看起来很像直接访问字段。Java没有使用特性支持getter和setter方法,而是约定必须实现字段名前加get的getter方法(然而这里有个不一致的地方,如果字段是布尔类型,则加is)和字段名前加set的setter方法。这导致的一个问题是开发时需要编写大量的getter方法和setter方法。为Java冗长的特点贡献了一份力量。遵循这个规范很重要,以为在很多常用库,比如Json序列化,会以getter方法作为字段存在的依据。

为了减少开发工作量,可以使用IDE自动生成getter方法和setter方法。常见的Java IDE都支持自动生成getter方法和setter方法。另一个方案是使用Lombok,通过DataGetterSetter等注解,让编译器在编译时自动生成getter方法和setter。

转载于:https://www.cnblogs.com/skabyy/p/10049106.html

更多相关:

  • 来源:公众号|计算机视觉工坊(系投稿)作者:仲夏夜之星「3D视觉工坊」技术交流群已经成立,目前大约有12000人,方向主要涉及3D视觉、CV&深度学习、SLAM、三维重建、点云后处理、自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、...

  • 点云PCL免费知识星球,点云论文速读。文章:Real-Time LIDAR-Based Urban Road and Sidewalk Detection for Autonomous Vehicles作者:Ern˝o Horváth  , Claudiu Pozna ,and Miklós Unger编译:点云PCL代码:http...

  • 文章:Semantic Histogram Based Graph Matching for Real-Time Multi-Robot Global Localization in Large Scale Environment作者:Xiyue Guo, Junjie Hu, Junfeng Chen, Fuqin Deng, T...

  • 点云PCL免费知识星球,点云论文速读。文章:Robust Place Recognition using an Imaging Lidar作者:Tixiao Shan, Brendan Englot, Fabio Duarte, Carlo Ratti, and Daniela Rus编译:点云PCL(ICRA 2021)开源代码:...

  • 文章:A Survey of Calibration Methods for Optical See-Through Head-Mounted Displays作者:Jens Grubert , Yuta Itoh, Kenneth Moser编译:点云PCL本文仅做学术分享,如有侵权,请联系删除。欢迎各位加入免费知识星球,获取PD...

  • 我们接触过java需要的小伙伴们都知道java是一门强大而又复杂的编程语言,现如今在互联网行业,java的身影随处可见,可能刚学习的小伙伴们会被java语言庞大的体系图吓到,不过知识毕竟是一个积累的过程,接下来对于新手来说,看看哪些是java程序员必学的内容吧。1:html,html−超文本标记语言,这是用来在浏览器上生成用户所看到的...

  • Java工程师数量日益增长,而其薪资不降反升几十年来,Java比其他语言更常名列榜首2019年,Java仍然是最流行的编程语言Java工程师的薪资到底多高?据职友集数据,近一年,全国Java工程师的平均薪资为13400元。然而在右边的投票中,竟有67%的人觉得月薪13400元偏低、偏低、偏低~为了探个究竟,小编特意去招聘网站查询了当下...

  • 因为工作需要使用到ActiveMQ,它是Java语言实现的,所以需要事先安装Java集成环境,下面是我的实操过程,记录如下,参考了文末两篇链接。 一、系统环境说明 rMBP上的VMware Fushion Pro 10.1.1 CentOS 6.9 64bit jdk-8u211-linux-x64.tar.gz 二、安装步骤...

  • 这周基本学完了java的基础中的基础,还不会灵活的应用,相关概念仍然有些模糊。为此,自己将自己学到的知识点做了下系统的复习,并作了相关的笔记。这周编程的大部分时间主要用于小学期PTA的编程作业中(用C++语言),练习java做的比较少,所以现在敲java代码的时候仍然感觉不太熟练,有时候相关的函数引入还要想一下,并且这次发现自己观看...

  • 本周对java的循坏结构和条件语句以及switch分支进行了复习并通过九九乘法表和制作日历来更加熟练使用和理解循环,并用eclipse替代了记事本来编写程序,同时针对记事本编写java程序后台运行出现的GBK不可映射字符问题先后采用了 javac  -encoding  UTF-8  xxx.java进行编译和采用notepad++...

  • Python 与 ABC 的一个重要区别在于其类型系统。ABC 采用静态类型,编译器会检查程序中的变量类型是否保持一致,如果不一致,程序就无法运行。并且,ABC与当时大多数静态语言不同,采用的是类型推导(和 Haskell 一样),而不是类型声明(比如 C 语言)。而 Python 采用动态类型,所有类型检查都是在程序运行过程中,而不...

  • python是计算机二级考试的科目之一,并没有级别的划分。其考试目标是测试考生掌握Python语言知识的程度和对Python语言的编程能力、调试能力和综合应用能力,在当下的应用中是十分重要的。 什么是python Python语言是一种解释运行、面向对象、扩展性强的程序设计语言,是大学生学习计算机编程能力、理解计算机解决问题的方法的...

  • 正在学C,书上老说空指针,或者说void指针,对于我这样的生手来说,理解非常容易造成混淆,因为void这个单词的意思也是空,到底空指针的意思是指指向地址为空的类型呢,还是指void类型的指针呢 (1)空指针所对应的是指指向的对象为空的指针。            不经发问,什么叫指向为空呢?要理解这点,必须理解如下几点(有点啰嗦,但...

  • 一、reponseType 1、什么是reponseType XMLHttpRequest.reponseType属性是一个枚举类型的属性,返回响应数据的类型,他允许我们手动的设置 返回数据的类型。如果我们将它设置为一个空字符串,它将默认的使用"text"类型。 当将reponseType设置为一个特定的类型的时候需要确保服务...

  • SNMP中,数据类型并不多。这里我们就讨论这些数据类型,而不关心这些数据类型在实际中是如何编码的。INTEGER一个变量虽然定义为整型,但也有多种形式。有些整型变量没有范围限制,有些整型变量定义为特定的数值(例如,IP的转发标志就只有允许转发时的或者不允许转发时的这两种),有些整型变量定义一个特定的范围(例如,UDP和TCP的端口号...