- 即将到来的 JDK8 最为引人入胜之处非 Lambda 表达式莫数了,这在其他动态语方,如 Ruby, Groovy, Scala 等语言中早已大行其道。一旦 JDK 搭上了 Lambda 这趟车,从此操作事件,线程,处理集合时又大为方便了。关于现阶段如何体验 JDK8 的特性可以参考 抢鲜设置 JDK8 的编程环境,印象。
本文主要参考于官方的 State of the Lambda,并对源码或反编译出字节码,作一定的深入以助于各位理解,在 JVM 中是如何实现 Lambda 的。
Lambda 表达式,又称闭包(Closure),或称匿名方法(anonymous method)。这在其他语言中,如 Ruby, Groovy, Scala, JavaScript 等,甚至是在 C# 中运用得如火纯清的特性,JDK8 这才问候他,真有些晚了。没有 Lambda 时,Java 不得不求助于匿名类的回调方法来达到相似的目的,为了捕获外部变量,变量必须声明为 final。
一见到 Lambda,第一个反应就是 Lambda 表达式(局部而已),其实我们这里要说的 JDK8 的 Lambda 包含以下几块内容:- Lambda 表达式,俗称闭包或匿名方法
- 方法和构造器引用
- 扩充的目标类型和更强的类型推断
- 接口中的默认静态方法
说到 Lambda,我们不得不了解一下当前背景,例如下面一个典型的事件处理场景: Read More - JDK 发展过程中,第一次变化最大数 JDK1.5,加入了变长参数,泛型。泛型的最大的受益者是集合。JDK7 虽说引进了同时捕获多个异常(Multi-Catch),更聪明一点类型推断,资源的释放等,但我觉得变化还不大。接下来众人期望的 JDK8 的 Lambda 表达式才是激动人心的,恐怕这一特性的大赢家仍是集合。
这样 JDK 才不至于离 C# 太远,纯粹语言上讲,我更景仰 C#,比如它的匿名类型,更不论人家的 Lambda 了。
var person = new { Name = "Unmi", Website = "http://unmi.cc" };
Console.WriteLine(person.Name);
这要到 Scala 中才能见到这种影子。注: JDK 从 1.5 起就加入了象 Chrome, Firefox 那样的版本党了,所以这个版本也叫做 JDK5,不管是后来的 JDK6, JDK7 等等,其实在命令行下 java -version 显示出来的也还是 1.5.0, 1.7.0_40 这种理智的版本号的。
回过神来,我们要说的是 JDK7 对异常的处理,不讲同时捕获多个异常和 try-with-resource 的处理,而要说的是捕获异常再次抛出时进步,这在某方面得益于 JDK7 类型推断。JDK7 类型推断对于泛型来说,它可以不用这么写 Read More - 和 JDK7 还没有热和,却开始关注 JDK8 起来了,JDK8 已进行到了 M8 开发预览版了,其中包含了一个千呼万唤的功能,即 Lambda 闭包的支持。在当前有对闭包特性的诉求,而 Java 本身不提供时,我们不得不转而求助于 JVM 上的其他的语言, 像 Scala, Groovy, JRuby 等。
不得不说 Scala 给我们带来了不少的快感,以致于想以更多的精力投入到 Scala 编程中去,不过还正在换取项目实践的机会。JDK8 引入 Lambda 后同样也是能更好的解决多核计算的问题,从程序员的角度来看,只要觉得 Lambda 能给我们带来无与伦比的灵活与便利性就足够了,水很深。
JDK8 还有增加的功能就是 JEP(JDK Enhancement-Proposal) 中的了。
来这里 http://openjdk.java.net/projects/jdk8/ 看看 JDK8 的里程碑2012/04/26 M12012/06/14 M22012/08/02 M32012/09/13 M42012/11/29 M52013/01/31 M62013/06/13 M7 Feature Complete2013/09/05 M8 Developer PreviewRead More - 很早很久以前写过一篇 在 xslt 调用 java 方法的日志 XSLT 调用 Java 的类方法, 其中介绍是使用 org.apache.xalan.processor.TransformerFactoryImpl 实现的例子,JDK 本身就是用这个的。但是在 Tomcat 环境下,它有它自己的 XSLT 默认实现是 net.sf.saxon.TransformerFactoryImpl, 这时候 XSLT 中的内容略有不同,而且显示更简便一些。
这么说吧, xalan 支持以下两种调用 java 方法的方式,而 saxon 只认得第二种
1. 声明到包,调用时带上类名1<?xml version="1.0" encoding="UTF-8"?> 2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 3 xmlns:java="cc.unmi.commons" exclude-result-prefixes="java"> 4 5 <xsl:output method="xml"/> 6 7 <xsl:template match="user/name"> 8 <li><xsl:value-of select='java:XsltFunctions.replace(.)'/></li> 9 </xsl:template> 10</xsl:stylesheet>
Read More - JUnit 的测试用例总是由 Runner 去执行,JUnit 提供了 @RunWith 这个测试类的 Annotation, 可来指定自定义的 Runner。如果未指定特别的 Runner,那么会采用默认的 Runner,可能不同的环境,如 Eclipse,控制台下会有不同的默认 Runner。
如果不清楚 Runner 是什么,那么可能见过 @RunWith(SpringJUnit4ClassRunner.class) 这个东西,它有助你加载 Spring 的配置文件,及与 Spring 相关的事物。
那么自定义的 Runner 有什么用呢?它可以截获到 @BeforeClass, @AfterClass, @Before, @After 这些事件,也就是能在测试类开始和结束执行前后,每个测试方法的执行前后处理点事情。
比如说从外部读取内容进行初始化测试数据,而且 JUnit 本身就提供了 @RunWith(Parameterized.class) 这个参数化 Runner,用了为带参数测试方法循环填充数据进行测试。JUnit 的参数化测试比 C# 还是要笨拙一些,C# 直接用方法注解一行行设置参数,我想 JUnit 稍加定制的话也行的。 Read More - 被问及 Java 多线程,多会想到 Thread, Runnable,更通常是用 new Thread(){public void run(){...}}.start() 来启动一个线程。那都是 JDK 1.5 之前的年代了,现在还这么回答就 Out 了。用用 JDK 1.5 给我们带来的 java.util.concurrent 吧,更酷了。这里不涉及它的并发集合类,同步互斥机制,只说线程及线程池的应用举例。
1. 新的启动线程的方式:Read More1public static void main(String[] args) throws Exception { 2 Callable<Integer> callable = new Callable<Integer>() { 3 public Integer call() throws Exception { 4 System.out.println("callable executed."); 5 return new Random().nextInt(100); 6 } 7 }; 8 9 FutureTask<Integer> future = new FutureTask<Integer>(callable); 10 new Thread(future).start(); 11 12 System.out.println("do your things here"); 13 14 System.out.println(future.get()); 15} - 1 环视基础
环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的。环视匹配的最终结果就是一个位置。
环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
环视按照方向划分有顺序和逆序两种,按照是否匹配有肯定和否定两种,组合起来就有四种环视。顺序环视相当于在当前位置右侧附加一个条件,而逆序环视相当于在当前位置左侧附加一个条件。表达式
说明
(?<=Expression)
逆序肯定环视,表示所在位置左侧能够匹配Expression
(?<!Expression)
逆序否定环视,表示所在位置左侧不能匹配Expression
(?=Expression)
顺序肯定环视,表示所在位置右侧能够匹配Expression
(?!Expression)
顺序否定环视,表示所在位置右侧不能匹配Expression
Read More - 元组类型,即 Tuple 常在脚本语言中出现,例如 Scala 的 ("Unmi", "fantasia@sina.com", "blahbla")。元组可认为是象数组一样的容器,它的目的是让你方便构造和引用,例如 Pair 可认为是一个只能存两个元素的元组,像是个 Map; 真正的元组应该是可以任意多个元素的容器,绕来绕去,它还是数组,或列表,所以我们实现上还是要借助于数组或是列表。
先看 Scala 中什么是元组:1val tuple = ("Unmi", "fantasia@sina.com", "blahblah...") 2println(tuple._1) //输出 Unmi
Scala 中访问从 1 开始,用 ._1 方式来访问其中的元素。
参照于此,写出一个 Java 版本的 Tuple,为增长你的键盘的使用寿命,我们把方法名也缩短了,例如 make 缩写为 mk,引用元素的方法名为 _,仍然保持 Java 的习惯,索引从 0 开始: Read More - 我们在 Java 中经常会碰到如何把 InputStream 转换成 String 的情形,比如从文件或网络得到一个 InputStream,需要转换成字符串输出或赋给别的变量。
未真正关注这个问题之前我常用的办法就是按字节一次次读到缓冲区,或是建立 BufferedReader 逐行读取。其实大可不必费此周折,我们可以用 Apache commons IOUtils,或者是 JDK 1.5 后的 Scanner,还可用 Google Guava 库的 CharStreams。到了 JDK7,若要从文件中直接得到字符串还能用 java.nio.file.Files#readAllLines 和 java.nio.file.Files#readAllBytes 方法。
下面看各个例子,为能够实际用运,例子写在 main 方法里,并从文件获得一个 InputStream,代码中把可能要捕获的异常抛出来。再就是注意处理输入输出流时有涉及到字符集,字符集乱了就乱码了,默认字符集是 System.getProperty("file.encoding"),通常我们都用 UTF-8,异常 UnsupportedEncodingException 继承自 IOException。
下面的 6 个方法中应该有一个你能看得上的吧,用 Groovy,Scala 的除外,若未找到一个遂意的,告诉我,你有好办法更应该告诉我。
1. 使用 JDK 5 的 Scanner Read More - Scala 在处理字符串方面终于也与时俱进了,引入了字符串插件,这在许多脚本语言中就早已这么做了。有了这个特性,字面量字符串和变量连接可以不需要总是用加号进行丑陋的连接了。有些脚本语言会是只对双引号字符串解析其中的变量,单引号的不会,当然Scala 是要区分字符串和字符类型。
直白的讲字符串插值就是,val name="Unmi"; val greeting=s"Hello $name"; greeting 的值就是 "Hello name"。产生效应的就是那个 s 方法。
Scala 2.10.0 为我们提供了三种字符串插值的方式,分别是 s, f 和 raw。它们都是定义在 StringContext 中的方法。
s 字符串插值器
可以解析字符串中的变量,可以调用方法,还能进行计算。实际调用的是 StringContext 中的 s 方法。 Read More