本人正在阅读 《Becoming Functional》这本书,且对 Scala 的使用经验已有数年,所以品读的同时更是对头脑中函数编程的概念进行重新整理。函数编程并非一定要诸多语言特性的支持,它是一种不同的思维方式;比如说我们公司项目如今还是用的 Java 7,但我们一直以函数式思维来书写我们的代码。我们正在从 Java 7 升级到 Java 8,待到 Java 8 时代码行文肯定要比现在简练的多,但函数式编程思维未变。
下面是函数式编程基本概念- First-class functions: 函数是第一类型
- Pure functions: 纯函数,无边界效应,输出依赖于输入,易测试。像数据库的函数而非存储过程
- Recursion: 递归,Scala 强调尾递归优化,避免坠入 StackOverflow
- Immutable variables: 这在 OO 里也是一种不错的模式,它与 Pure function 也是相辅的。可能是首先映入函数式编程思维的概念,它不关乎并发性能,解决了并发冲突
- Nostrict evaluation: 即变量值的赖加载,变量不到用时不初始化。在 Java 只能用方法来模拟实现
- Statements: 表达式优于控制结构,语句可以有返回值的,如 val a = if (condition) 1 else 2
- Pattern Matching: 模式匹配,不光是通常对数值或字符串的 switch/case, 还能应用到任何对象的匹配,进行类型检查或从对象中提取元素
《Becoming Functional》逐章对上面七大概念进行讲解.
First-class functions: 函数是第一类型 Read More- 今天才发现 Jackson 其实是支持 Json-Path 的,但以前一直不知道,关键是 Jackson 的文档也没见提到。所以很久以前是自己给 Jackson 写了一个简陋的 Json-Path 支持类,这个是为测试代码用的,所以基本够用。想要更全面的功能可使用 https://github.com/jayway/JsonPath 这个项目。对于 Jackson 中如何使用 Json-Path, 我还会进一步研究下。
我写的 RichJsonNode 类是一个 Scala 版本,最早也写过一个 Java 版本,还有一个基于 GSON 的 Java 版本的。这里只贴出 Scala 版源码。支持的基本方法及语法如下:
a/b, a/b[2], a/b[1]/c, a[1]/b, $[0]
selectNode(path), selectString(path), selectInt(path), selectDouble(path), selectBollean(path), hasField(path) 和 arrayLength(path)
源码如下: Read More 初学 Java 的人很不经意间就会把常量定义在接口中,大概唯一的理由是接口不能实例化,而使用接口中定义的常量也是不用附着在实例上的。 这主要还是 JDK 本身给我们做了很多这样的榜样, 如 java.io.ObjectStreamConstans, 多是出现在 Enum 类型到来之前。
其实 Java 的接口常量是一种反模式,理由如下:
1. 接口是不能阻止被实现或继承的, 也就是说子接口或实现中是能够覆盖掉常量的定义(重名),这样通过父,子接口(或实现) 去引用常量是可能不一致的
2. 同样的,由于被实现或继承,造成在继承树中可以用大量的接口, 类 或实例去引用 同一个常量,从而造成接口中定义的常量污染了命名空间。(Java 编译器竟然允许使用实例去引用类变量)
3. 接口暗含的意思是:它是需被实现的,代表着一种类型,它的公有成员是要被暴露的 API。而在接口中定义的常量说不上是 API4. 这点有些重复,Java 允许通过子类去引用父类中定义的常量,各级对像实例去引用父类的常量,所以这会造成相当的混乱不堪。定义的常量不能保证单一的引用方式。
参见: Effective java 第 19 条: 接口只用于定义类型
既然接口中不适于定义常量,那么该在何处为常量安家呢?接口为 实现/继承 而生,如果放在类中,并且这个类是 final,且封闭掉构造方法就行。 于是我们先前的接口常量定义 Read More
随着 Mac 下终端的使用日益增多,系统默认的 bash 已经满足不了需求了,于是有了更为强劲的 fish 和 zsh,以及它们各自的强心剂 Oh-My-Fish 和 Oh-My-Zsh. 我的选择是 Fish 和 Oh-My-Fish。
到目前为止,最新的 fish 2.2.0 于 2015 年 7 月 12 日发布,Release notes 如下 http://fishshell.com/release_notes.html,其中显著改变有:
- Abbreviations: the new `abbr` command allows for interactively-expanded abbreviations, allowing quick access to frequently-used commands (#731).
- Vi mode: run `fish_vi_mode` to switch fish into the key bindings and prompt familiar to users of the Vi editor (#65).
- New inline and interactive pager, which will be familiar to users of zsh (#291).
- Underlying architectural changes: the `fishd` universal variable server has been removed as it was a source of many bugs and security problems. Notably, old fish sessions will not be able to communicate universal variable changes with new fish sessions. For best results, restart all running instances of `fish`.
- The web-based configuration tool has been redesigned, featuring a prompt theme chooser and other improvements.
- New German, Brazilian Portuguese, and Chinese translations.
我对第二点比较感兴趣,即增加了 vi 模式,在 fish 下运行
fish_vi_mode命令, 或者在~/.config/fish/config.fish中加上fish_vi_mode便自动进入 vi 模式。 Read More枚举的声明很简单, 像
enum Gender { Male, Female }, 其余事情就是 Java 编译器帮我们干的了,所以 enum 也就是一块语法糖。有了枚举确实是很方便,避免了传统常量的无范围性。那么编译器到底在后面做了什么呢?以及理解了这个之后我们可以怎么去使用 Java 的枚举, 下面就从这个例子说起:public enum Gender {
Male,
Female
}把上面的编译成 Gender.class, 然后用 javap -c Gender 反编译出来就是 Read More
Coursera 上的 Functional Programming Principle in Scala 视频教程,合成了英文字幕,应该没有多大必要性翻译成中文字幕,本人觉得大家的英语都比我强,因为它是我永久的,历史的伤口。
该课程共有七周的课时,算下来每天十至二十多分钟的时间。
开始教程
- 课程介绍 (2:44)
- Linux 下工具设置 (12:24)
- Mac OS X 下工具安装 (12:17)
- Windows 下工具安装 (10:37)
- 指导: 编程作业 (8:47)
第一周:函数和求值 Read More
- 因为写过类似下面的一段代码来实始化一个匿名实例看上面的
1package cc.unmi; 2 3public class Test { 4 public String name; 5 6 public static Test buildTest(final String name) { 7 Test test = new Test(){{ 8 this.name = name; //希望把 buildTest() 方法参数中的 name 赋给 this.name 9 }}; 10 System.out.println(test.name); // 仍然是 null 11 return test; 12 } 13}buildTest()方法中的this.name = name希望能把方法参数 final String name 中的 name 值赋值给 this.name, 但是无效,this.name = name 是在把自己赋给自己。 Read More - 伴随着 Play1, 我们原来使用的 JSON 库是 Gson. 回忆下 Gson 是怎么自定义序列化对象的 JSON 格式,大概是这样子的
GsonBuilder()..registerTypeHierarchyAdapter(Cat.class, new Cat());
然后 Cat 需要实现 JsonSerializer 的 serialize() 方法。
来到了 Play2 中,JSON 库变成了 Jackson,那么 Jackson 该如何为对象自定义 JSON 格式呢?
例如,默认时 Jackson 对 Map 类型输出的是一个 JSON 对象
Map("key1"->"value1", "key2"->"value2") 转换成 JSON 是 {"key1":"value1", "key2":"value2"}
当为适应某些客户端,对于 LinkedHashMap 类型,我们想要输出的是一个有序的 JSON 数组: [{"key1":"value1"},{"key2":"value2"}]
我们就应该自定义某些 Map 的序列化格式,实现方法有两种,addSerializer 和 @JsonSerialize,不管哪种方式都需事先具体化 JsonSerializer 类,并实现它的 serialize 抽象方法
所以我先来实现一个能序列化 Map 的 JsonArrayMapSerializer 类 Read More
本文基本是参照着 用Grunt与livereload构建实时预览的开发环境 实操了一遍,直接实现能实时预览文件列表,内容页面。不用刷新页面了,这比以前开发网页程序都简单。
这里要用到的 Grunt 插件有
grunt-contrib-connect, 用来充当一个静态文件服务器,本身集成了 livereload 功能
grunt-contrib-watch, 监视文件的改变,然后执行指定任务,这里用来刷新grunt serve打开的页面
以下是个辅助的插件
load-grunt-tasks, 省事的插件,有了这个可以不用写一堆的grunt.loadNpmTasks('xxx'),再多的任务只需要写一个require('load-grunt-tasks')(grunt)。
参考的文档中提到了 time-grunt 插件,可用来显示每一个任务所花的时间和百分比,由于此示例中基本就 watch 任务占了百分百的时间。
下面是 Grunt 项目的两个基本的文件 Read More
最近重新在 Eclipse 中打开旧的 Maven 项目,总有些什么错误,备受折磨。期间试手了 Ant+Ivy, 现今试用了下 Gradle,感觉不错,它应该才是我真想要的,Maven 差不多该扔到一边去了。
Gradle 像 sbt 构建工具一样,也不会帮我们生成默认的目录布局,这些要自己来做。这不是什么麻烦事,因为只需做一次,可预先写好初始化脚本,幸好本人已习惯 shell 操作。
假设我们有这样的build.gradle文件apply plugin: 'java'
我们执行
apply plugin: 'war' //有这行时我们需要创建 src/main/webapp 目录
apply plugin: 'eclipse'gradle eclipse后是不会生成src目录的,工程下的源文件目录是需要自己来生成的。Gradle 参考 Maven 的标准目录布局,即1src 2 ├── main 3 │ ├── java 4 │ ├── resources 5 │ └── webapp 6 └── test 7 ├── java 8 └── resources
我们有两种办法初始化目录布局 Read More