尝试Java,从入门到Kotlin(上)
之前一直使用C#开发,最近由于眼馋Java生态环境,并借着工作服务化改造的契机,直接将新项目的开发都转到Java上去。积攒些Java开发经验,应该对.NET开发也会有所启发和益处。
从理论上说,Java和C#语言差别不大,毕竟难听地说,C#就是抄Java出来的。程序语言简史如是介绍这两种语言:
然而随着时间流逝语言发展,个人认为,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处理异常。但是很多时候,异常没办法在这个时刻处理,必须要抛出。那么还有另一种方案:将异常转换为RuntimeException
,RuntimeException
是所谓的Unchecked Exception,它不是类型系统的一部分,不需要用throws
标注,所以不会导致函数类型变化。另一方面,编译器也无法检测出是否可能会抛出RuntimeException。无论采用哪种方案,都使得这个Lambda函数变得没那么好看。
泛型
Java的泛型原理和C#不同。C#是运行时泛型,在程序运行的时候仍然能获取泛型的类型信息。而Java的泛型是类型擦除(Type Erasure)式泛型。名称听起来很高大上,意思是Java的泛型仅仅用于编译时类型检查,类型检查完成后,类型信息就被编译器擦除。在最后生成的字节码中中,泛型类型都被改为Object
类型。
比如这句:
HashMap<TK, TV> map = new HashMap<TK, TV>();
编译后变成:
HashMap map = new HashMap();
Type Erasure方式的影响主要有两个:
- 运行时无法判断类型;
- 运行时无法动态生成泛型具现化的类的实例。
像下面两句:
x instanceof T
new T()
在Java中都会编译出错。而这在C#中都是很常见的代码。在C#中,我们可以有这样的Json反序列化方法:
T parse<T>(string jsonStr)
这个方法将jsonStr
反序列化为类型T
的一个对象。这种写法看起来十分自然。然而在Java中无法实现。因为在parse
方法中需要在运行时实例化T
的一个对象,而Java在运行时这些泛型都已经被擦除,无法获取类型T
的信息,从而无法实例化。要在Java实现类似的方法,需要额外将一个Class
对象放到参数:
T parse(String jsonStr, Class<T> 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,通过Data
,Getter
,Setter
等注解,让编译器在编译时自动生成getter方法和setter。
尝试Java,从入门到Kotlin(上)的更多相关文章
- 尝试Java,从入门到Kotlin(下)
上篇已提(tu)到(cao)Java中的各种坑.习惯了C#的各种特性和语法糖后,再转到Java感觉比较别扭.最后本着反正Java也不是很熟悉,干脆再折腾折腾其他语言的破罐子破摔的心态,逛了一圈JVM语 ...
- 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!
本文原题“<NIO 入门>,作者为“Gregory M. Travis”,他是<JDK 1.4 Tutorial>等书籍的作者. 1.引言 Java NIO是Java 1.4版 ...
- 自学 Java 怎么入门
自学 Java 怎么入门? 595赞同反对,不会显示你的姓名 给你推荐一个写得非常用心的Java基础教程:java-basic | 天码营 这个教程将Java的入门基础知识贯穿在一个实例中,逐 ...
- 《Velocity java开发指南》中文版(上)转载
文章引自:http://sakyone.iteye.com/blog/524289 1.开始入门 Velocity是一基于java语言的模板引擎,使用这个简单.功能强大的开发工具,可以很容易的将数据对 ...
- java秀发入门到优雅秃头路线导航【教学视频+博客+书籍整理】
目录 一.Java基础 二.关于JavaWeb基础 三.关于数据库 四.关于ssm框架 五.关于数据结构与算法 六.关于开发工具idea 七.关于项目管理工具Mawen.Git.SVN.Gradle. ...
- Java Annotation入门
Java Annotation入门作者:cleverpig 版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明作者:cleverpig(作者的Blog:http:/ ...
- 《JAVA 从入门到精通》 - 正式走向JAVA项目开发的路
以前很多时候会开玩笑,说什么,三天学会PHP,七天精通Nodejs,xx天学会xx ... 一般来说,这样子说的多半都带有一点讽刺的意味,我也基本上从不相信什么快速入门.我以前在学校的时候自觉过很多门 ...
- Java NIO入门(二):缓冲区内部细节
Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...
- 三、Android NDK编程预备之Java jni入门创建C/C++共享库
转自: http://www.eoeandroid.com/thread-264971-1-1.html 应网友回复,答应在两天前要出一篇创建C/C++共享库的,但由于清明节假期,跟朋友出去游玩,丢手 ...
- C功底挑战Java菜鸟入门概念干货(一)
一.认识Java 1.Java 程序比较特殊,它必须先经过编译,然后再利用解释的方式来运行. 2.Byte-codes 最大的好处是——可越平台运行,可让“一次编写,处处运行”成为可能. 3.使用 ...
随机推荐
- 代码覆盖率 (Code Coverage)从简到繁 (一)
代码覆盖率(Code Coverage)是反映测试用例对被测软件覆盖程度的重要指标,也是衡量测试工作进展情况的重要指标.它也是对测试工作进行量化的重要指标之一,测试工作往往不如开发那样激动人心,一个重 ...
- Mysql篇--Linux中安装Mysql
一.前述 由于Windows安装Mysql非常麻烦,所以分享一篇Linux中对MySQL的搭建,废话不多说,来,come on. 二.步骤 2.1 yum安装 yum install mysql-se ...
- 听说,霸都.NET技术社区准备搞线下聚会了?
嗨,你听说了没有?霸都.NET技术社区准备搞线下聚会了! 啥时候的事情啊? 最近才知道的消息啊! 那你是从哪里知道的消息呢? .NET Core项目实战交流群(637326624)啊! 那这次合肥.N ...
- 【转】msfvenom使用指南
msfvenom命令行选项如下: Options: -p, --payload <payload> 指定需要使用的payload(攻击荷载).如果需要使用自定义的payload,请使用'- ...
- php 定时任务
crontab第一次使用真是个坑 第一次使用crontab 时,会出现no crontab for root - using an empty one“Select a editor ......”下 ...
- C#版 - Leetcode 306. 累加数 - 题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...
- vue keep-alive 实现详情返回列表保留页面数据
实现功能 详情页返回列表页,列表页保留上次浏览位置 其它页面进入到列表表,列表页刷新 当详情页有数据改变时,列表页也要更新该条数据 实现思路 用keep-alive保留列表页面数据 activated ...
- Java多线程父子线程关系 多线程中篇(六)
有的时候对于Java多线程,我们会听到“父线程.子线程”的概念. 严格的说,Java中不存在实质上的父子关系 没有方法可以获取一个线程的父线程,也没有方法可以获取一个线程所有的子线程 子线程的消亡与父 ...
- -1-2 java 面向对象基本概念 封装继承多态 变量 this super static 静态变量 匿名对象 值传递 初始化过程 代码块 final关键字 抽象类 接口 区别 多态 包 访问权限 内部类 匿名内部类 == 与 equal
java是纯粹的面向对象的语言 也就是万事万物皆是对象 程序是对象的集合,他们通过发送消息来相互通信 每个对象都有自己的由其他的对象所构建的存储,也就是对象可以包含对象 每个对象都有它的类型 也就是 ...
- 基于.Net进行前端开发的技术栈发展路线(二)
前言 上一篇<我的技能树>文章分享了我的技能成长过程,还未完成,今天继续跟大家分享. 01 我的技能树 我的当前的技能树: 其中,标注为黄色旗帜的是基本掌握,标注为红色旗帜的为使用熟练.未 ...