Java 8 可重复注解的理解与应用

Java 8 之前如何重复使用注解

在 Java 8 之前我们不能在一个类型重复使用同一个注解,例如 Spring 的注解 @PropertySource 不能下面那样来引入多个属性文件

@PropertySource("classpath:config.properties")
@PropertySource("file:application.properties")
public class MainApp {}

上面的代码无法在 Java 7 下通过编译,错误是: Duplicate annotation

于是我们在 Java 8 之前想到了一个方案来规避 Duplicate Annotation 的错误: 即声明一个新的 Annotation 来包裹 @PropertySource, 如 @PropertySources

@Retention(RetentionPolicy.RUNTIME)
public @interface PropertySources {
  PropertySource[] value();
}

然后使用时两个注解齐上阵 阅读全文 >>

类别: Java/JEE, Java8. 标签: . 阅读(143). 评论(0) »

Mockito 如何 mock 返回值为 void 的方法

最初接触 Mockito 还思考并尝试过如何用它来 mock 返回值为 void 的方法,然而 Google 查找到的一般都会说用 doThrow() 的办法

doThrow(new RuntimeException()).when(mockObject).methodWithVoidReturn();

因为无法使用常规的 when(mockObject.foo()).thenReturn(...) 的方法。

当时我就纳闷,为何我想 mock 一个返回值为 void 的方法,却是在模拟抛出一个异常,现在想来如果一个返回值为 void 的方法,为何要去 mock 这个方法呢?

回想一个我们要 mock 一个方法的意图是什么:

  1. 在特定输入参数的情况下期待需要的输出结果(返回值)
  2. 在方法抛出某种类型异常调用者作出的反应

对于 void 返回值的方法,如果要验证有没有被调用过几次可以在事后用 verify() 方法去断言。所以基本上对于 void 返回值的方法一般可不用去 mock 它,只需用  verify() 去验证,或者就是像前面一样模拟出现异常时的情况。

所以本文并不像是去直接回答标题所示的问题: Mockito 如何 mock  返回值为  void 的方法,而是如何应对 mock  对象的  void 方法 阅读全文 >>

类别: Java/JEE. 标签: . 阅读(873). 评论(0) »

Mockito 中捕获 mock 对象方法的调用参数

Mockito 可以帮助我们创建 Mock 对象,mock 被调用的方法,断言调用次数,在方法参数不易确定的情况下还能帮我们捕获参数。下面是我们第一个问题:

为什么要捕获调用参数

在被 mocker 方法调用参数明确的情况下可无需捕获参数,例如,下面的情景:

@Test
public void dontCaptureArgument() {
  UserDao userDao = Mockito.mock(UserDao.class);
  UserService userService = new UserService(userDao);

  User user = new User(1, "Yanbin");
  userService.saveUser(user); //假如它的实现是 userDao.save(user)

  verify(userDao, times(1)).save(user); //断言了 userDao.save(user) 操作的还是 user 对象
}

如果 UserService 的 save(user) 最终操作的不是同一个对象,它的实现稍加变化如下 阅读全文 >>

类别: Java/JEE. 标签: . 阅读(264). 评论(0) »

5 个最好的 Vim 速查卡 (Cheat Sheet)

Vim(Vi Improved) 早已替代了 Vi, 它存在于大多数的 Linux 发行版中。所以基本上 Vi 和 Vim 在你的系统中就是同一个程序,我用的 Mac, vi 命令就是一个指向到 vim 的链接

ls -l $(which vi)
lrwxr-xr-x 1 root wheel 3 Sep 20 23:47 /usr/bin/vi -> vim

macOS Sierra 自带的 Vi/Vim 版本仍然是 7.4,我用 brew install macvim 安装了最新版的 Vim 8.0, 由于只想启动 MacVim 控制台的 Vim,  所以把 vi/vim 命令链接到新版 Vim 上。

alias vim=/usr/local/Cellar/macvim/8.0-121/MacVim.app/Contents/MacOS/Vim
alias vi=vim

这里找来了 5 个最好的 Vim Cheat Sheet, 不仅每个按键本身的操作,还有组合健, 窗口,缓冲区,寄存器等操作。

1. Vim Cheat Sheet for Programmers

阅读全文 >>

类别: Vim. 标签: . 阅读(1,259). 评论(2) »

《Practical Vim》阅读笔记 (1)

Vim 的东西时而学一点,但很快又会忘记,就是最简单的 h, j, k, l 来移动光标都会有所迟疑,因为一直未强迫自己完全脱离方向键来使用 Vim,下个目标是 87 键的键盘都嫌多,打算入一个 61 键的 WSAD 键盘, HHKB 还是有些极端了。

找到了一本学习 Vim 的好书 《Practical Vim》第二版,阅读时把对自己有用的东西仅当笔记记下来备忘,这个其实更应该记录在我的 Evernote 中作为私有笔记。重点的东西我在书中注解了,这里的笔记只能算是一个补充。 阅读全文 >>

类别: Vim. 标签: . 阅读(43). 评论(0) »

Vim 中 Java 代码自动完成 - vim-javacomplete2

用 Java 进行编码基本还是离不开 IntelliJ IDEA 或 Eclipse, 看别人完全用 Vim 进行 Javascript 项目编程很是眼红,估摸着能不能把 Vim 打造成一个更强的 Java IDE。语法高亮是不在话下,最主要是给它加上自动完成功能,不光对当前类,项目中的方法或变能能提示,而且必须像 Java IDE 那样理解所有的项目依赖。这就是今天试用的一个 Vim 插件 vim-javacomplete2,另种可能更好的方案 YouCompleteMe + Eclim 还会再研究。

提到 Vim 的自动完成功能,有必要了解 Vim 自带的提示功能

  1. ctrl - n/p:  Vim 根据当前缓冲区的关键字来提示,像 Sublime 或 Visual Studio Code 中的关键字提示
  2. ctrl - x 进行自动自动完成模式,接着一些操作如 ctrl - l/n/t/i 完成类似于 ctrl - n/p 的操作; ctrl - k 能基于字典自动完成,完整按键是 ctrl - x ctrl -k
  3. ctrl - x ctrl - o, 这个单独拉出来,是使用 Vim 的 Omni Completion 功能来自动完成,因为将要用到的 vim-javacomplete2 就依赖于这个功能

除 YouCompleteMe 插件外,另外还两个 Vim 下的自动完成插件是 NeoCompleteVimCompleteMe

摘要部分算是说完了,现在开始体验 vim-javacomplete2 对 Java 项目的自动完成功能。它所有完成的代码提示不仅要支持基本的 Java 类库, 当前项目的类, 手动添加的 jar 包 ,还能支持 maven, gradle 和 Eclipse 的 .classpath 文件中定义的 classpath, 这完全能应付我们实际中的项目了。实际运作也是一个 C/S 结构,这个插件会启动一个 javavi server, 用 javaparser 来解析依赖, 然后 Vim 中用 omnifunc 经 socket 连接到 javavi server 获得提示列表的。 阅读全文 >>

类别: Vim. 标签: . 阅读(648). 评论(2) »

CompletableFuture 的并发性能研究

今天继续探讨 CompletableFuture 的特性,它并发时的性能如何呢?我们知道集合的 stream() 后的操作是序列化进行的,parallelStream()是能够并发执行的,而用 CompletableFuture 可以更灵活的控制并发。

我们先可以对比一下 parallelStream() 与 CompletableFuture 的性能差异

假设一个这样的耗时 1000 毫秒的计算任务

private static int getJob() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    }
    return 50;
}

分别用下面两个方法来测试,任务数可以通过参数来控制 阅读全文 >>

类别: Java8. 标签: , , . 阅读(188). 评论(0) »

理解 CompletableFuture 的任务与回调函数的线程

继续对 CompletableFuture 的学习,本然依然不对它的众多方法的介绍,其实也不容易通过一篇述说完所有 CompletableFuture 的操作。此处重点了解下 CompletableFuture 几类操作时所使用的线程,CompletableFuture 的方法重点在它的静态方法以及实现自 CompletionStage 接口的方法,如果是意图异步化编程,反而自我标榜的 Future 中的方法用的少了。

CompletableFuture 根据任务的主从关系为

  1. 提交任务的方法,如静态方法 supplyAsync(supplier[, executor]),  runAsync(runnable[, executor])
  2. 回调函数,即对任务执行后所作出回应的方法,多数方法了,如 thenRun(action), thenRunAsync(action[, executor]), whenComplete(action), whenCompleteAsync(action[, executor]) 等

根据执行方法可分为同步与异步方法,任务都是要被异步执行,所以提交任务的方法都是异步的。而对任务作出回应的方法很多分为两个版本,如

  1. 同步方法,如 thenRun(action), whenComplete(action)
  2. 异步方法,如 thenRunAsync(action[, executor]), whenCompleteAsync(action[, executor]), 异步方法可以传入线程池,否则用默认的

因此所要理解的 CompletableFuture 的线程会涉及到任务与回调函数所使用的线程。 阅读全文 >>

类别: Java8. 标签: , , , . 阅读(232). 评论(0) »

Java 8 CompletableFuture 浅入

Java 1.5 有了 Future, 可谓是跨了一大步,继而 Java 1.8 新加入一个 Future 的实现 CompletableFuture, 从此线程与线程之间可以愉快的对话了。最初两个线程间的协调我采用过 Object 的  wait() 和 notify() , Thread 的 join() 方法,那可算是很低级的 API 了,是否很多 Java 程序都不知道它们的存在,或根本没用过它们。

如果是简单的等待所有线程完成可使用 Java 1.5 的 CountDownLatch, 这里有一篇介绍 CountDownLatch 协调线程, 就是实现的 waitAll(threads) 功能。而 Java 8 的 CompletableFuture 的功能就多去,可简单使用它实现异步方法。虽说 CompletableFuture 实现了 Future 接口,但它多数方法源自于 CompletionStage, 所以还里氏代换,用 Future 来引用 CompletableFuture 实例就很牵强了; 这也是为什么 PlayFramework 自 2.5 开始直接暴露的类型是 CompletionStage 而非其他两个。

顾名思义,CompletableFuture 代表着一个 Future 完成后该干点什么,具体大致有:

  1. Future 完成后执行动作,或求取下一个 Future 的值。then...
  2. 多个 Future 的协调; 同时完成该怎么,其中一个完成该如何。allOf, anyOf

有时候可以把 Future 想像成与线程是一一对应的。 阅读全文 >>

类别: Java/JEE, Java8. 标签: , , , . 阅读(264). 评论(0) »

巩固 Java Future 的使用

Future 还是一 Java 1.5 带进来的产物,但过去那么多年实际代码中却很少有直接接触, 大约它多是隐匿在各种现成框架中默默的为我们服务。Future 本身不代表着多线程,而是代表着需异步计算的结果, 将来的一个期待,至于后来真正的结果不可知。在此之前想要获得一个 Runnable 在其他线程中的计算结果颇费波折,有了 Future 加之它身后的 Callable 一切就变得简单了。

对比一下 Java 1.5 前后的下面几个概念

  1. Callable 相当于之前的 Runnable, 只是 Callable 是有返回值的
  2. ExecuteService.submit(callable): Future 就类似于之前的 Thread(runnable)
    只是前者 submit 后立即执行,通过 get() 获得结果,后者用 start() 方法启动,runnable 是没有结果的。如果你也不想关心 Future 的结果也能 ExecuteService.submit(runnable)

只有 callable 被提交(到线程池) 后返回的 Future 才可能会有结果, 所以下面的代码永远等不到结果

Future<String> future = new FutureTask<>(() -> "Never");
String result = future.get();

最容易理解的 Future 基本使用代码如下: 阅读全文 >>

类别: Java/JEE. 标签: , . 阅读(58). 评论(0) »
Page 4 of 102« First...23456...102030...Last »