之前一直使用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处理异常。但是很多时候,异常没办法在这个时刻处理,必须要抛出。那么还有另一种方案:将异常转换为RuntimeExceptionRuntimeException是所谓的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,通过DataGetterSetter等注解,让编译器在编译时自动生成getter方法和setter。

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

尝试Java,从入门到Kotlin(上)相关推荐

  1. 小白零基础学习Java开发入门教程奉上,希望对你有所帮助!

    "持久和新"是编程语言方面对Java的适当评估. 想要进入互联网行业,想转向编程,Java无疑是一个非常普遍的选择. 但是,Java毕竟是一种编程语言,并且仍然存在一些技术障碍.如 ...

  2. kotlin t class.java_尝试Java,从入门到Kotlin(下)

    上篇已提(tu)到(cao)Java中的各种坑.习惯了C#的各种特性和语法糖后,再转到Java感觉比较别扭.最后本着反正Java也不是很熟悉,干脆再折腾折腾其他语言的破罐子破摔的心态,逛了一圈JVM语 ...

  3. B站百万播放量Java零基础教程视频(适合Java 0基础,Java初学入门),史上最细Java零基础教学视频

    是否还在为学习Java如何入门而烦恼? 是否还在为Java软件如何安装而烦恼? 是否还在找寻着适合零基础的Java视频教程? 动力节点教学总监老杜159集课堂实录Java零基础视频教程,从初学者角度出 ...

  4. 一文回顾 Java 入门知识(上)

    Java前世今生 Java最早是由SUN公司(已被Oracle收购)的詹姆斯·高斯林(高司令,人称Java之父)在上个世纪90年代初开发的一种编程语言,最初被命名为Oak,目标是针对小型家电设备的嵌入 ...

  5. 叮!您收到一份超值Java基础入门资料!

    摘要:Java语言有什么特点?如何最大效率的学习?深浅拷贝到底有何区别?阿里巴巴高级开发工程师为大家带来Java系统解读,带你掌握Java技术要领,突破重点难点,入门面向对象编程,以详细示例带领大家J ...

  6. Java RMI 入门

    Java RMI 入门 如何通信 实战 完整代码   Java RMI 指 JDK 内置的关于实现远程方法调用(Remote Method Invocation)的 API.这些 API 位于包 ja ...

  7. swagger 怎么去掉get delete_自学 Java 怎么入门?

    给你推荐一个写得非常用心的Java基础教程:码邦主2020年最新的Java视频教程 这个教程将Java的入门基础知识贯穿在一个实例中,逐步深入,可以帮助你快速进入Java编程的世界.万事开头难,逐步跟 ...

  8. python kotlin_用Java和Python模仿Kotlin构建器

    python kotlin 介绍 Kotlin可能现在是我最喜欢的语言,可能它提供的最酷的功能之一是基于几个功能构建的类型安全的生成器(稍后解释). 我发现自己真的很想在其他两种主要语言(Java和P ...

  9. java 8入门与实践_30个Java入门技巧和最佳实践

    java 8入门与实践 Java是最流行的编程语言之一-无论是Win应用程序,Web应用程序,移动,网络,消费电子产品,机顶盒设备,Java随处可见. 在Java上运行的设备超过30亿. 据Oracl ...

  10. java gradle入门_Gradle入门:我们的第一个Java项目

    java gradle入门 这篇博客文章描述了如何使用Gradle编译和打包一个简单的Java项目. 我们的Java项目只有一个要求: 我们的构建脚本必须创建一个可执行的jar文件. 换句话说,我们必 ...

最新文章

  1. SQL效率低下原因主要有
  2. 知乎真的一天不如一天了吗?
  3. 离线计算中的幂等和DataWorks中的相关事项
  4. 二叉链表之寻找两节点的最近公共祖先☆
  5. 【数据结构与算法】算法的时间复杂度
  6. Alpha阶段事后分析报告
  7. 股价/期货等时间序列数据的整合检验、Grach建模
  8. 汉源高科2个万兆光24千兆网口万兆机架式工业交换机支持G.8032(ERPS)标准的以太环网交换机
  9. js 用指定字符分割字符串
  10. 云服务器和虚拟主机的区别
  11. TwinCAT 3 安全门程序
  12. 哨兵2号波段_Sentinel2 哨兵二号数据下载及处理教程
  13. c语言.jpg图片转成数组_电脑使用图片转换器打开heic图片方法
  14. 洛谷P2664 树上游戏 【点分治 + 差分】
  15. Curent branch is not synced with latest origin/master!
  16. table表格自动换行
  17. 万亿数字化市场,数据科学为何能扛起“价值担当”?
  18. 模拟小信号调理电路(智能车电磁组)
  19. 一番谈话,深自反思。
  20. 基于Go语言星座查询~

热门文章

  1. ios Develop mark
  2. 【URAL】1091 Tmutarakan Exams
  3. SQL2000联机丛书:使用和维护数据仓库
  4. 计算机艺术未来发展趋势,计算机技术对现代艺术设计的影响
  5. S-T平面图中利用最短路求最小割(BZOJ 1001)
  6. sklearn库安装_没有依赖库也能跑机器学习模型!推荐一个强大工具m2cgen
  7. c语言增强,C语言提高-day5
  8. oracle全局索引 前缀索引_Oracle 分区索引介绍和实例演示
  9. 上传图片被防火墙拦截_Web安全:文件上传漏洞
  10. 子程序调用与宏定义的异同_如何用数控系统进行简单的宏程序调用?老师傅告诉你,用G65就行...