好用的Spacemacs!

作为Emacs粉,以前最麻烦的莫过于安装各种package和设置各种配置,常常把各种文件拷来拷去的。偶然的机会看到了Spacemacs这个项目,试用之后,感觉真是非常方便。

  • 安装简便,基本就是用git clone得到最新的版本,还可以简单的升级。
  • 默认的配置非常好用,反正比我之前的好,我在配置包丢在网盘上了。😁
  • 安装package非常简单,基本就是几条命令,再不用网上找各种包了。
  • 强大的个人定置,可以分Layer。但其实对我没什么用,基本的已经很好了。

Emacs粉应该果断试试,不会让你失望的!戳这!😋

 

Java坑之Class.isEnum()

发现在这个坑是因为代码里用到了cloning库

在做深度代码拷贝时,发现Enum对象也被Copy了,破坏了Enum对象的唯一性。读了cloning的源代码,其实它考虑了Enum的问题,默认也是跳过的。在其1.9.0版本,它使用了Class.isEnum()来检查,但在1.9.2版本中,检查的代码换成了instanceof Enum, 问题也解决了。对比一下,两种API的区别,

输出是

第二行的输出居然是false, 再看看A2的类签名,不是A,而是一个匿名类A$1。这都是因为A2有Override toString方法,Java产生的了一个匿名类。再看看isEnum的实现,

这下都清楚了,JDK里使用通过基本类是否是Enum的方法,判断当前类是否是Enum, 但当有匿名类的出现,父类就不再是Enum,isEnum的检查也就失效了。

难道Enum的匿名类就不是Enum了吗?😈

这个坑大家要小心啊!

使用Java Dynamic Proxy API实现简单的Function Decorator

Python里有非常方便的Function Decorator语法糖,使用起来非常简便。如果想在Java里做类似的事情,可以使用Dynamic Proxy API来实现。

看看这个小例子。有一组Web服务接口,需要访问数据库得到所需的数据。比如,

代码里的Analyzer类会去数据库找到相应的数据。

为了提高访问的效率,加入memcached,在真正的数据库访问之前,先去查看有没有相应的Cache,代码会变成类似的样子,

如果每个服务接口都要做同样的事,可想而知,会有非常多的重复代码。这时就可以利用Dynamic Proxy API来大大的优化代码实现,非常灵活。

Dynamic Proxy API只能针对接口,所以要为原来Analyzer类写一个接口类,如:

然后我们的代理实现类要继承自InvocationHandler,并通过Proxy.newProxyInstance生成真正的代理。看下面的实现,

有了动态代理,原来Web服务接口的实现就非常简洁了。

Java自带的Dynamic Proxy API虽然有些限制,但使用起来还是非常简单的。听说还有更强大的CGLib,有机会现研究一下。😄

Eclipse里生成Guava-based的hashCode()和equals()

做Java开发的常常要重写类的hashCode()和equals()。一般情况下,可以套常用的模板。Eclipse就套用这些模板,直接生成默认实现,可实现比较冗长,比如下面的例子

有类A,

Eclipse的默认实现是这样的,

显然实现比较冗长,也比较乱,包含了很多细节,有些也不符合代码规范(比如if后没有花括号)。

用过Guava的同学都知道,使用Objects类可以大大简化这两个函数的实现。我试着扩展了Eclipse JDT,套用Guava的实现模板,那代码就漂亮多了。Guava隐藏了大量的实现细节。

如下,

具体的代码实现在Github上,点这

主要分如下有几步,

  • Project Explorer的上下文菜单中加入新的功能选项。
  • 通过Eclipse里事件得到Java CompliationUnit,使用ASTParser得到类里的Non-Static Member Field,然后就套用新模板吧。
  • 一个源文件中可能包含多个Java Class,所以还要有个Dialog来选择在哪个类中实现方法 。

其他细节都在代码里的,有兴趣的就看看吧。😁

聊聊ClassLoader in Java World

ClassLoader是Java技术中非常主要的概念,原因是它用来加载Java Class。如果没有Class,也就没有对象;没有对象,就没有之后的一切了。

Java ClassLoader的默认实现是一种双亲结构,即总是尝试让Parent ClassLoader加载类。这样有一些优点,当然也有很大的限制,比如就不利于不同Module对多版本类的加载。更多的细节,在下面我做的PPT里。

还有些新的理解和发现。

  • 自定义的ClassLoader可以把Parent ClassLoader设置为null,如果再把loadClass函数重写,就可以完全屏蔽default classLoader的影响。如OSGi的Bundle ClassLoader的最终的Parent就不是Bootstrap ClassLoader(Bundle ClassLoader的实现还是会去从默认ClassLoader去加载java.*的类)。
  • 程序执行时,ClassLoader的选择。做几个小实验你就会发现,默认的ClassLoader是“加载当前执行函数所在类的ClassLoader”。在OpenJDK的源码中一通Search,就可以找到一些端倪。

在源文件src\interp\engine\interp.c中,有executeJava()函数中,执行ByteCode之前,先准备了MethodBlock的指针,它中间

可以看看GETSTATIC这个指令的实现(此指令会在读取类的静态方法时调用)。可以看到resolveField()方法,并在mb的Class指针传入。idx是Static Field对应Constant Pool里的index。

resolveField中被调用resolveClass函数

resolveClass又回调用findClassFromClass(其实是个Macro),同样传入class指针。看看Macro的定义,就可以很清楚了。

是从ClassBlock结构中找到对应的ClassLoader.

其实记住这个结论就好。这样就可以完全打错传统的ClassLoader的限制,比如OSGi Plugin/Bundle里的所有类就是由OSGi自己的加载器加载的,非常灵活,可以实现非常牛逼的功能!

 

读《与熊共舞》

《与熊共舞》的重点在于风险管理,从风险的定义,讲到如何发现风险并管理风险,再阐述工具、如何量化等等,结构非常紧凑,例证很多,很有条理,读起来很流畅。熊节的翻译真不是盖的,一级棒!正如简体中文版上封面上所写,它确实算得上和《人件》、《人月神话》等并驾的好书。

在组织或团队中,当你发现风险,你有勇气说出来吗?也许会,也许不会,但请必须学会。风险具现的后果是对项目、组织,甚至社会造成很大的影响,想想航天飞机失事的事故吧。软件开发工程师不能简单的用“加班”做为“风险缓解”手段,有时再怎么加班也无济于事。“职业”的做法就是报告风险,无论项目处在什么阶段。

对于团队的Lead更有挑战的是,要习惯用风险图向自己的老板汇报,而不是拍胸脯说“在某某日这个项目一定做完“。在讲这话时,真的那么有底气吗?需求的不确定,估算的不确定,技术难点的不确定,代码遗留问题的不确定,人员的不确定等等,对于开发都是风险,而且常常发生的过程中。对于开发团队来说,对控制范围之内的风险最好的缓解就是平时多下功夫。和产品工程师做充分的需求分析与确认可以降低需求方面的不确定,代码全员所有会降低估算的不确定,时常的代码重构会降低遗留问题,积极培训可以降低技术风险等。当然这些都是成本、时间、人才,有看的见的,也有看不见的,但对团队和组织,这些活动都非常重要,特别在关键时刻。风险总是存在,只是可大可小。对于无法控制的风险,如需求变化的风险,对R&D,那应该属于”别人的风险“,自己是无法避免。团队还要有自己的风险仓库,项目做得多了,就从慢慢从中受益。

开发的方式也很重要。如使用增量式就可以减少风险,其实很好理解,把一个项目拆成若干个小的单元,范围小了,反馈快了,当然不确定就少了。只是能不能用就难说了,有时不在开发方,很多用户也不一定能接受。

书里提到了很多工具和方法也挺有意思,如”灾难头脑风暴“,用噩梦、水晶球等富有启发性的活动帮助团队发现风险;Riskology的Excel开上去就非常强大,需要的时候不妨一试。

总之,非常推荐大家读一读这本书!

最后附上我做的脑图。

与熊共舞

 

 

初识Scala

开门见山,Scala是真心的复杂、难学,但学着上瘾。因为它有太多吸引人的特性,超传统Java好几条街,即使Java 8也赶不上。(一点题外话,现在Java语言本身的特性,甚至连C++1x的也赶不上,发展的太慢,没有创新)。

简单说说有哪些有趣的特性。

强类型语言

这算不上什么特性,只是某种理念,但我觉得非常重要。类型安全的语言让人写起来的放心,日后也更容易维护。

函数对象

Scala本身是一门FP语言,函数的地位是第一位,非常简单就可定义函数,且函数可以做为对象传递给其他函数或由其他函数生成,非常方便,不再需要提前定义接口。

相当强大的灵活性吧。这个例子还展示了一些特性

  • 函数的参数可以有默认参数,再不用多个函数重载版本
  • 使用type定义类型的别名,很像C++11里的using

Match Expression

首先把它理解成表达式,不是简单的流程控制。这个特性比switch..case强大太多了。

这部分的语法还真是挺复杂的,有兴趣的找找Tutorial学习一下,不在这里一一展示了。

Objects, Case Classes, Traits

面向对象方面,除了传统的Java特性之外,还新添加了几个新的成员。

  • Object就是JVM上的一种单例实现,Lazy initialization。
  • Case Class可以看成一种语法糖,可以生成Instantiable的类,并自动生成一些常用的函数,如apply(), copy(), equals()等。
  • Trait则是为多继承准备的。从OO的角度看,多继承是完全合情合理的,只是实现上会有很多问题,所以设计从语言层面去掉了这种可能。

此外Scala还有很多的特性和超多的语法糖,以后慢慢再续上。