我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java效率提升神器之Guava-Joiner

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java效率提升神器之Guava-Joiner

姊妹篇:Java效率提升神器jOOR

在我们的开发中经常会用到Guava中的一些功能。但是我们所使用到的只是Guava API中的小的可怜的一个子集。我们大家一起来发掘一下Guava中更多的一些功能。

Joiner

这是在我们代码中出现频率比较高的一个功能。经常需要将几个字符串,或者字符串数组、列表之类的东西,拼接成一个以指定符号分隔各个元素的字符串,比如要将一个用List保存的字符集合拼起来作为SQL语句的条件,在知道Joiner之前我们会这样做。

ArrayList<String> conditions = new ArrayList<String>();
conditions.add("condition1");
conditions.add("condition2");
conditions.add("condition3");

private String buildCondition(ArrayList<String> conditions) {
    StringBuilder sb = new StringBuilder();
    for (String condition : conditions) {
        sb.append(condition);
        sb.append(" or ");
    }
    int index = sb.lastIndexOf(" or ");
    return index > 0 ? sb.substring(0, index) : sb.toString();
}  // condition1 or condition2 or condition3

基本上会手写循环去实现,代码瞬间变得丑陋起来。并且循环完了还得删除最后一个多余的or。

使用Guava工具,我们能够轻而易举的完成字符串拼接这一简单任务。借助 Joiner 类,代码瞬间变得优雅起来。

Joiner.on(" or ").join(conditions);

被拼接的对象集,可以是硬编码的少数几个对象,可以是实现了 Iterable 接口的集合,也可以是迭代器对象。

除了返回一个拼接过的字符串,Joiner 还可以在实现了 Appendable 接口的对象所维护的内容的末尾,追加字符串拼接的结果。

StringBuilder sb = new StringBuilder("result:");
Joiner.on("#").appendTo(sb, 1, 2, 3);
System.out.println(sb);     //result:1#2#3

我们看下面这个例子:

Joiner.on("#").join(1, null, 3)

如果传入的对象中包含空指针,会直接抛出空指针异常。Joiner 提供了两个方法,让我们能够优雅的处理待拼接集合中的空指针。

如果我们希望忽略空指针,那么可以调用 skipNulls方法,得到一个会跳过空指针的 Joiner 实例。如果希望将空指针变为某个指定的值,那么可以调用 useForNull 方法,指定用来替换空指针的字符串。

Joiner.on("#").skipNulls().join(1, null, 3);      //1#3
Joiner.on("#").useForNull("").join(1, null, 3);   //1##3

Joiner.MapJoiner

MapJoiner 是 Joiner 的内部静态类,用于帮助将 Map 对象拼接成字符串。

 Map<Integer, Integer> test = new HashMap<Integer, Integer>();
 test.put(1, 2);
 test.put(3, 4);
 Joiner.on("#").withKeyValueSeparator("=").join(test); //1=2#3=4

withKeyValueSeparator 方法指定了键与值的分隔符,同时返回一个 MapJoiner 实例。

Joiner.on("#").withKeyValueSeparator("=").join(ImmutableMap.of(1, 2, 3, 4));  //1=2#3=4

源代码分析

源码来自Guava 18.0。Joiner类的源码一共458行。大部分都是注释。 Joiner 只能通过 Joiner.on 函数来初始化,它的构造方法是私有的。


public static Joiner on(String separator) {
	return new Joiner(separator);
}

public static Joiner on(char separator) {
	return new Joiner(String.valueOf(separator));
}

整个 Joiner 类最核心的函数莫过于 <A extends Appendable> appendTo(A, Iterator<?>),一切的字符串拼接操作,最后都会调用到这个函数。这就是所谓的全功能函数,其他的一切 appendTo 只不过是它的重载,一切的join不过是它和它的重载的封装。


  public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
    checkNotNull(appendable);
    if (parts.hasNext()) {
      appendable.append(toString(parts.next()));
      while (parts.hasNext()) {
        appendable.append(separator);
        appendable.append(toString(parts.next()));
      }
    }
    return appendable;
  }

这段代码的第一个技巧是使用 if 和 while 来实现了比较优雅的分隔符拼接,避免了在末尾插入分隔符的尴尬;第二个技巧是使用了自定义的 toString 方法而不是 Object#toString 来将对象序列化成字符串,为后续的各种空指针保护开了方便之门。

来看一个比较有意思的 appendTo 重载。

public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
    try {
        this.appendTo((Appendable)builder, (Iterator)parts);
        return builder;
    } catch (IOException var4) {
        throw new AssertionError(var4);
    }
}

在 Appendable 接口中,append 方法是会抛出 IOException 的。然而 StringBuilder 虽然实现了 Appendable,但是它覆盖实现的 append 方法却是不抛出 IOException 的。于是就出现了明知不可能抛异常,却又不得不去捕获异常的尴尬。

这里的异常处理手法十分机智,异常变量命名为 impossible,我们一看就明白这里是不会抛出 IOException 的。但是如果 catch 块里面什么都不做又好像不合适,于是抛出一个 AssertionError,表示对于这里不抛异常的断言失败了。

另一个比较有意思的 appendTo 重载是关于可变长参数。

public final <A extends Appendable> A appendTo(A appendable, @Nullable Object first, @Nullable Object second, Object... rest) throws IOException {
    return this.appendTo((Appendable)appendable, (Iterable)iterable(first, second, rest));
}

注意到这里的 iterable 方法,它把两个变量和一个数组变成了一个实现了Iterable 接口的集合,非常精妙的实现!

private static Iterable<Object> iterable(final Object first, final Object second, final Object[] rest) {
    Preconditions.checkNotNull(rest);
    return new AbstractList() {
        public int size() {
            return rest.length + 2;
        }
        public Object get(int index) {
            switch(index) {
            case 0:
                return first;
            case 1:
                return second;
            default:
                return rest[index - 2];
            }
        }
    };
}

要想看明白这段代码,需要熟悉AbstractList类中迭代器的实现。迭代器内部维护着一个游标,cursor。迭代器的两大关键操作,hasNext 判断是否还有没遍历的元素,next 获取下一个元素,它们的实现是这样的。

public boolean hasNext() {
        return cursor != size();
}
public E next() {
        checkForComodification();
    try {
    E next = get(cursor);
    lastRet = cursor++;
    return next;
    } catch (IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
    }
}

hasNext 中关键的函数调用是size方法,获取集合的大小。next 方法中关键的函数调用是get方法,获取第 i 个元素。Guava 的实现返回了一个被覆盖了 size 和 get 方法的 AbstractList,巧妙的复用了由编译器生成的数组,避免了新建列表和增加元素的开销。

拼接Map键值对

MapJoiner 实现为 Joiner 的一个静态内部类,它的构造函数和 Joiner 一样也是私有,只能通过 withKeyValueSeparator来生成实例。类似地,MapJoiner 也实现了 appendTo 方法和一系列的重载,还用 join 方法对 appendTo 做了封装。

MapJoiner 整个实现和 Joiner 大同小异,在实现中大量使用 Joiner 的 toString 方法来保证空指针保护行为和初始化时的语义一致。

到此这篇关于Java效率提升神器之Guava-Joiner的文章就介绍到这了,更多相关Java Guava-Joiner内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java效率提升神器之Guava-Joiner

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java效率提升神器之Guava-Joiner怎么使用

今天小编给大家分享一下Java效率提升神器之Guava-Joiner怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。J
2023-07-02

Java效率提升神器jOOR怎么使用

今天小编给大家分享一下Java效率提升神器jOOR怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Java中的原生反射
2023-07-02

MySQL提升大量数据查询效率的优化神器

目录前言查看SQL执行频率 定位低效率执行SQLexplain分析执行计划trace分析优化器执行计划使用索引优化SQL优化大量插入数据优化insert语句优化order by语句2、两种排序方式3、Filesort 的优化优化group
2022-07-06

Go语言库全面解析:五款提升开发效率的神器

Go语言作为一种快速、高效的编程语言,越来越受到开发人员的青睐。在Go语言的生态系统中,有许多优秀的库(library)可以帮助开发人员提高工作效率,简化开发过程。本文将对五款提升开发效率的神器进行全面解析,为读者呈现这些优秀的库的特点、用
Go语言库全面解析:五款提升开发效率的神器
2024-02-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录