高效Java,提高java性能的方式

  高效Java,提高java性能的方式

  

目录

连接器连接器。MapJoiner源代码分析拼接映射键值对伴侣:Java效率提升神器jOOR

 

  番石榴中的一些函数在我们的开发中经常用到。但是我们用的只是番石榴API的一个很小很可怜的子集。让我们来探索一下番石榴的更多功能。

  00-1010这是我们代码中经常出现的一个特性。通常需要将几个字符串或字符串数组、列表等拼接成一个字符串,并用指定的符号分隔每个元素。例如,我们将拼写保存在List中的一组字符作为SQL语句的一个条件。我们将在了解Joiner之前这样做。

  ArrayList string conditions=new ArrayList string();conditions . add( condition 1 );conditions . add(“condition 2”);conditions . add(“condition 3”);private String build condition(ArrayList String conditions){ StringBuilder sb=new StringBuilder();for(字符串条件:条件){ sb.append(条件);某人追加(或);} int index=sb . lastindexof( or );返回索引0?sb.substring(0,index): sb . tostring();}//条件1或者条件2或者条件3基本都会用手写循环实现,代码瞬间变丑。并且在循环结束后,必须删除最后的冗余or。

  使用番石榴工具,我们可以轻松地完成简单的字符串拼接任务。在Joiner类的帮助下,代码瞬间变得优雅起来。

  Joiner.on(或)。加入(条件);拼接对象集可以是一些硬编码的对象、实现Iterable接口的集合或迭代器对象。

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

  StringBuilder sb=new StringBuilder( result : );Joiner.on(# )。附录(sb,1,2,3);system . out . println(sb);//结果:1 # 2 # 3我们看下面这个例子:

  Join.on (# )。join (1,null,3)如果传入的对象包含空指针,会直接抛出空指针异常。Joiner提供了两种方法,允许我们优雅地处理要拼接的集合中的空指针。

  如果我们想忽略空指针,我们可以调用skipNulls方法来获得一个Joiner实例,它将跳过空指针。如果要将空指针更改为指定的值,可以调用useForNull方法来指定一个字符串来替换空指针。

  Joiner.on(# )。skipNulls()。join(1,null,3);//1#3Joiner.on(# )。useForNull(“”)。join(1,null,3);//1##3

  

Joiner

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

 

  MapInteger,Integer test=new HashMapInteger,Integer();test.put(1,2);test.put(3,4);Joiner.on(# )。withKeyValueSeparator(=)。加入(测试);//1=2#3=4withKeyValueSeparator方法指定键和值之间的分隔符,并返回MapJoiner实例。

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

  odian">

  

源代码分析

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

 

  

/*** Returns a joiner which automatically places {@code separator} between consecutive elements.*/public static Joiner on(String separator) {return new Joiner(separator);}/*** Returns a joiner which automatically places {@code separator} between consecutive elements.*/public static Joiner on(char separator) {return new Joiner(String.valueOf(separator));}

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

 

  

/** * Appends the string representation of each of {@code parts}, using the previously configured * separator between each, to {@code appendable}. * * @since 11.0 */ 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内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: