追溯到刚开始学习 Groovy 还是在 2008 年,距今 2018 年有九年半余,曾记下几篇 Groovy 的日志。那时学习 Groovy 并无明确的目的,只因它是脚本语言, 可用来快速验证 Java API。曾经 BeanShell 芸花一现, JRuby 和 Jython 总是别人家的语言照搬而来的。而 Scala,Nashorn(jjs), JShell 更是后来的事,唯有 Groovy 写起来很亲切,完全不懂 Groovy 都没关系,直接上 Java。
现如今之所以重新勾搭上了 Groovy 是因为它仍然坚挺着,在 SoupUI(ReadyAPI) 和 Jenkins 中获得了重视,倒不是因为 Gradle。先前 Groovy 在 Spring 框架中的地位估计要被如今的 Kotlin 取而代之。
好了,回顾完后进入正题,关于 Groovy 如何进行多重赋值,以及延伸到方法返回多个值的情形。这里所说的多重赋值不是指用连等号来同时赋为一个值,
def a = b = c = 100 //不是说的这个
而是指同时对多个变量一步到位的赋成不同的值,要实现这个必须用到 List 类型。看下面一个基本例子(GroovyConsole) Read More
Scala 有一个自身类型(self-type) 的东西,由来已久,居然今天才发现。如果一个类或 trait 指明了 self-type 类型(包括类和特质),它的子类型或是对象也必须是相应的类型。它产生的效果与继承(或 mixin) 颇有几分相似。self-type 的语法是this 的别名: 某一类型(class 或 trait), 直接看一个例子:1class User(val name: String) 2 3trait Tweeter { 4 this: User => //这个表示 Tweeter 本身也必须是一个 User,它的子类型必须想办法符合这一要求 5 def tweet(tweetText: String) = { 6 println(s"$name: $tweetText") 7 } 8} 9 10class VerifiedTweeter(val username: String) 11 extends User(username) with Tweeter { //Tweeter 要求这个类必须是一个 User, 所以需要继承自 User 类 12} 13 14val v = new VerifiedTweeter("Yanbin") 15v.tweet("Hello")
上面this: User =>中的this只是一个别名,可以是self或任何有效标识(如abc: User),这里使用this等于未指定别名,与原本的 this 重叠了。如果声明为非this的话则可以这么用 Read More
Akka 是什么?它提供了 JVM 上的 Actor 编程模型 -- 同时兼顾了并发与分布式。它由 Scala 编写的,替代了 Scala 本身的 Actor。Actor 视线程为重量级的资源,能够以少量的内存胜任更高的并发,类似的东西有纤程,协程。有一个数据对比是同样的 1GB 内存,可以创建 2.7M 个 Actor, 而线程只能创建 4096 个,仅供参考,当然 Java 也是会基于线程池来执行的。
Actor 增加了程序的灵活性,并减轻了复杂度(标准的赞美之辞)。
所谓 Action 编程模型兼顾并发与分布,是由于让你编程时可以不用考虑线程,线程配置成为部署的范畴; Actor 之间通信只能发送异步消息,Actor 可以分布在同一 JVM, 不同 JVM, 或是不同物理机器上。
因为 《Akka IN ACTION》中提供了第一个例子起点着实有点高,所以网上找来了一个了解 Akka Actor 的最简单例子,来自于 Simple Scala Akka Actor examples (Hello, world examples)。并非纯属翻译,主要是为了练手,所以不完全一致: Read More刚开始阅读 《Akka IN ACTION》这本书,刚开始是对
Revolution这个词翻译成中文是革命感到诧异,因为革命通俗来讲就是杀人的意思。至于Revolution英文解释不深究了,只是感叹何以颠覆性的变化就一定要杀人吗?也由此引出了编程中经常面对的
Concurrent(名词为:Concurrency) 和Parallel(名词为:Parallelism) 这两个词,基本上是认为它们是同一个意思。其实不然,下面慢慢道来。如果从英文字典对它们的解释也没有多大区别,差不多都是说同是发生,但字面上
Parallel多了一个平行的意思。所以在中文上,在计算机领域我们约定的翻译是- Concurrent(Concurrency) -- 并发
- Parallel(Parallelism) -- 并行
比如在多线程环境中它们的区别具体体现在:
并发:多个任务在同一个 CPU 核上按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。针对 CPU 内核来说,任务仍然是按细粒度的串行执行。也难怪在 Java 5 中新加的并发 API 的包名是
java.uti.concurrent。 Read More
对列表的去重处理,Java 8 在
Stream接口上提供了类似于 SQL 语句那样的distinct()方法,不过它也只能基于对象整体比较来去重,即通过 equals/hashCode 方法。distinct方法的功效与以往的new ArrayList(new HashSet(books))差不多。用起来是List<Book> unique = book.stream().distinct().collect(Collectors.toList())
并且这种去重方式需要在模型类中同时实现 equals 和 hashCode 方法。
回到实际项目中来,我们很多时候的需求是要根据对象的某个属性来去重。比如接下来的一个实例,一个 books 列表中存在 ID 一样,name 却不同的 book, 我们认为这是重复的,所以需要根据 book 的 id 属性对行去重。在 collect 的时候用到的方法是
collectinAndThen(...), 下面是简单代码: Read More
还是从 OSChina 网站上得知 Clojure 1.9 在 2017 年 12 月发布的,时值这么久才开始真正去了解一下这个新版本。距离上一个版本 1.8 的发布时间(2016 年 1 月), 大概两年才出一个版本,而且总的说来 Clojure 1.9 并没有带来多大惊喜。
唯一能带来点喜气的也就是 Clolure 有了自己的命令行工具了,再也无需寄身于 Leiningen(一个 Clojure 构建工具,相当于 sbt 之于 Scala) 的篱笆之下了。以 Mac OS 平台为例,以前试图用 brew 来直接安装clojure的时候会提示找不到clojure, 建议安装leiningen.$ brew install clojure
在 Clojure 1.9 出来之前,上面的命令会得到如下提示信息Error: No available formula with the name "clojure"
所以那时候不得不用 Read More
Clojure isn't really a program but a library managed as part of a
project and Leiningen is the user interface to that library. To install Clojure you should install Leiningen:
brew install leiningen
and then follow the tutorial:
https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md
初识 Mockito 这个测试框架后,我们要使用 Mock 的属性创建一个被测试类实例时,大概会下面这么纯手工来打造。
假定类
UserService有一个属性UserDao userDao, 需要构造UserService实例时 Mock 内部状态UserDao userDao = Mockito.mock(UserDao.class);
UserService testMe = new UserService(userDao);如此,userDao 的行为就可以自由模拟了,这种纯手工方式都不需要给测试类添加
@RunWith(MockitoJunitRuner.class)
//或
MockitoAnnotations.initMocks(this);因为上面两句是给 Mockito 的注解使用的。
如果所有的 Mock 对象全部通过手工来创建,那就不容易体现出 Mockito 的优越性出来。因此对于被测试对象的创建,Mock 属性的注入应该让
@Mock和@InjectMocks这两个注解大显身手了。标注在实例变量上的
@Mock相当于是Mockito.mock(Class)创建了一个 Mock 对象,而@InjectMock标的实例会寻找到相应 Mock 属性想法构造出被测试类的实例。看下面的例子: Read More
Docker 镜像在未指定仓库时默认是从 Docker Hub 拉取的。如果需向 Docker Hub 推送镜像的话还可用docker login在交互中完成登陆 Docker Hub 的操作。docker login的命令格式是docker login [OPTIONS] [SERVER]
所以我们可以连接到任何的 Docker 镜像仓库,也可以是本机,但我们这里所要介绍的是如何推送镜像到 AWS 给我们提供的 Docker 镜像仓库(Amazon ECR - Amazon Elastic Container Registry)。每个帐号下都有自己独立的仓库,镜像推送到了 Amazon ECR 后我们能够很方便的在 ECS, Batch 服务中使用它,也可以从 ECR 拉取镜像到本地来。
首先我们来做一个运行 Spring Boot Web 的简单的 Docker 镜像,假定已用mvc pacakge生成了一个可独立运行的 jar 包java-webapp-0.0.1-SNAPSHOT.jar。该应用开启一个 Web 服务,访问 http://localhost:8080 显示一行字符串Hello World!
创建一个目录 aws-docker, 并把java-webapp-0.0.1-SNAPSHOT.jar移入该目录,在其下创建Dockerfile文件,文件目录结构如下:aws-docker
Read More
├── Dockerfile
└── java-webapp-0.0.1-SNAPSHOT.jar
Bash 环境
多数时候我们用的是 Bash, 比如个人的 Linux 不愿去定制,远程服务器的由不得你去定制,所以就从 Bash 说起。
默认键绑定
emacs, 操作是ctrl-x, ctrl-e在默认的 Bash 环境下,只要在命令行中按下
ctrl-x, ctrl-e就会把当前命令的内容调入到环境变量$EDITOR指示的编辑器(默认为 emacs)去编辑,编辑后保存退出就会立即执行。如果未安装
Emacs编辑器,在按下ctrl-x, ctrl-e会得到如下提示[vagrant@localhost ~]$
-bash: emacs: command not found如果希望使用
vi来编辑当前命令,就需要设置EDITOR环境变量,比如在.bashrc中加入export EDITOR=vi
那么在命令行中按下
ctrl-x, ctrl-e使用打开vi来编辑当前命令。注:Emacs 要用
ctrl-x, ctrl-c, 再回答y, 命令保存到临时文中; 而 vi 的相应操作是:wq, 至少这个操作上 vi 要简洁些。 Read More初衷只是为了记述一下在 Bash/Zsh 中怎么调用 Vi 编辑当前的命令,但一发挥便涉及到了 Bash/Zsh 的键绑定的话题,无法打住,只得另立新篇。这里也只说 Bash 的键绑定,不会有 Zsh 键绑定的内容。
什么是 Bash 的键绑定(keybing) 呢? 就是在 Bash 中的快捷键方案,即相当于某个 IDE 的快捷键配置,或者叫 Keymap。比如说 IntelliJ IDEA 中可选择的 Keymap 有 Eclipse, Emacs, JBuilder, Mac OS X, Mac OS X 10.5+, NetBean, Visual Studio, 以满足不同使用者的习惯。
相应的 Bash 也为我们提供了两种键绑定的方案,即 emacs(默认) 和 vi 键绑定类型。
Emacs 键绑定
我们大多数天天在 Bash 下无意识中使用着 Emacs 键绑定类型,即使可能从未用过 Emacs 本身。比如我们在 Bash 下的按键组合
ctrl + a 跳到命令行的开始
ctrl + e 跳到命令行末尾
!! 重复最后一个命令
ctrl + l 清屏操作,类似于 clear 命令
ctrl + c 中断/杀掉当前运行的进程 (SIGINT)
ctrl + d 发送 EOF 标记,这会关掉当前的 shell (EXIT)
ctrl + z 发送 SIGTSTP 给当前任务,使其挂起送到后台。(所以如果 vi 未正常退出,而是按 ctrl + z 的话,vi 进程还呆在后台它们都是来自于 Emacs 键绑定。是不是那么的熟悉啊? Read More