Java常用工具包-Guava

常用判断

null值

  1. System.out.println("===========equals方法=============");
  2. System.out.println(Objects.equal(null, 'a'));//false
  3. System.out.println(Objects.equal(null, null));//true
  4. System.out.println(Objects.equal('a', null));//false
  5. System.out.println(Objects.equal('a', 'a'));//true
  6. System.out.println("===========isNullOrEmpty方法=============");
  7. System.out.println(Strings.isNullOrEmpty(null));//true
  8. System.out.println(Strings.isNullOrEmpty(" "));//false
  9. System.out.println(Strings.isNullOrEmpty(emptyToNull(" ")));//false
  10. System.out.println(Strings.isNullOrEmpty(""));//true

另外如判断:

  1. List<String> list = new ArrayList<String>();
  2. list.add("");
  3. list.add("null");
  4. list.add(null);
  5. list.add("zhangsan");
  6. Optional<String> possible;
  7. for (int i = 0; i < list.size(); i++) {
  8. System.out.print("真实值为:" + list.get(i) + ",emptyToNull(list.get(i))处理后的值为:" + emptyToNull(list.get(i)) + ",");
  9. possible = Optional.fromNullable(emptyToNull(list.get(i)));
  10. System.out.println("索引:" + i + ",值:" + possible.or("novalue"));
  11. }

输出:

真实值为:,emptyToNull(list.get(i))处理后的值为:null,索引:0,值:novalue
真实值为:null,emptyToNull(list.get(i))处理后的值为:null,索引:1,值:null
真实值为:null,emptyToNull(list.get(i))处理后的值为:null,索引:2,值:novalue
真实值为:zhangsan,emptyToNull(list.get(i))处理后的值为:zhangsan,索引:3,值:zhangsan
其中emptyToNull是把空字符串,转化为null。而字符串本身为”null“是正常值,为null,才是空值。

优雅的检验参数-工具类Preconditions

  1. Object current_id = null;
  2. checkArgument(current_id != null, "当前子任务名称不能为空");

输出:

Exception in thread “main” java.lang.IllegalArgumentException: 当前子任务名称不能为空
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:134)
at com.cenrise.GuavaCheck.main(GuavaCheck.java:24)

Preconditions里面的方法:

1 .checkArgument(boolean) :
功能描述:检查boolean是否为真。 用作方法中检查参数
失败时抛出的异常类型: IllegalArgumentException

2.checkNotNull(T):
功能描述:检查value不为null, 直接返回value;
失败时抛出的异常类型:NullPointerException

3.checkState(boolean):
功能描述:检查对象的一些状态,不依赖方法参数。 例如, Iterator可以用来next是否在remove之前被调用。
失败时抛出的异常类型:IllegalStateException

4.checkElementIndex(int index, int size):
功能描述:检查index是否为在一个长度为size的list, string或array合法的范围。 index的范围区间是[0, size)(包含0不包含size)。无需直接传入list, string或array, 只需传入大小。返回index。
失败时抛出的异常类型:IndexOutOfBoundsException

5.checkPositionIndex(int index, int size):
功能描述:检查位置index是否为在一个长度为size的list, string或array合法的范围。 index的范围区间是[0, size)(包含0不包含size)。无需直接传入list, string或array, 只需传入大小。返回index。
失败时抛出的异常类型:IndexOutOfBoundsException

6.checkPositionIndexes(int start, int end, int size):
功能描述:检查[start, end)是一个长度为size的list, string或array合法的范围子集。伴随着错误信息。
失败时抛出的异常类型:IndexOutOfBoundsException

使用Joiner

典型的使用原生的java处理拼接字符串的方法:

  1. public String buildString(List<String> stringList, String delimiter){
  2. StringBuilder builder = new StringBuilder();
  3. for (String s : stringList) {
  4. if(s !=null){
  5. builder.append(s).append(delimiter);
  6. }
  7. }
  8. builder.setLength(builder.length() delimiter.length());
  9. return builder.toString();
  10. }

注意:这里需要移除最后一个分隔符。
原生的java实现其实也不是很复杂,但是使用Google Guava类库中的Joiner来实现的话更加简洁:
Joiner.on("|").skipNulls().join(stringList);
上面的skipNulls方法是忽略了stringList中为null的空值。当然,Joiner中也可以指定空值得替代,比如如下的代码:
Joiner.on("|").useForNull("no value").join(stringList);
有几点需要说明:Joiner类不仅能处理String类型的数据,还能处理数组,迭代对象以及任何对象的可变参数类。其实也是调用了Object的toString()方法。另外如果空值存在集合中,并且skipNulls活着useForNull都没有指定的话,NullPointerException异常将会抛出。还有,一旦Joiner对象创建,将会是不变的。比如如下的useForNull将不会起任何作用:

  1. Joiner stringJoiner = Joiner.on("|").skipNulls();
  2. //the useForNull() method returns a new instance of the Joiner!
  3. stringJoiner.useForNull("missing");
  4. stringJoiner.join("foo","bar",null);

Joiner类不仅可以返回String对象,还可以返回StringBuilder对象:

  1. StringBuilder stringBuilder = new StringBuilder();
  2. Joiner joiner = Joiner.on("|").skipNulls();
  3. //returns the StringBuilder instance with the values foo,bar,baz appeneded with "|" delimiters
  4. joiner.appendTo(stringBuilder,"foo","bar","baz")

Joiner类可以作用于实现了Appendable的所有类:

  1. FileWriter fileWriter = new FileWriter(new File("path")):
  2. List<Date> dateList = getDates();
  3. Joiner joiner = Joiner.on("#").useForNulls(" ");
  4. //returns the FileWriter instance with the valuesappended into it
  5. joiner.appendTo(fileWriter,dateList);

Joiner类也可以作用于Map对象:

  1. public void testMapJoiner() {
  2. //Using LinkedHashMap so that the original order is preserved
  3. String expectedString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
  4. Map<String,String> testMap = Maps.newLinkedHashMap();
  5. testMap.put("Washington D.C","Redskins");
  6. testMap.put("New York City","Giants");
  7. testMap.put("Philadelphia","Eagles");
  8. testMap.put("Dallas","Cowboys");
  9. String returnedString = Joiner.on("#").withKeyValueSeparator("=").join(testMap);
  10. assertThat(returnedString,is(expectedString));
  11. }

字段串操作

模块部分内容来源自:google guava中定义的String操作

  1. public class GuavaString {
  2. /**
  3. * 字符串是否为空
  4. */
  5. @Test
  6. public void testIsNullOrEmpty() {
  7. String input = "";
  8. boolean isNullOrEmpty = Strings.isNullOrEmpty(input);
  9. System.out.println("输入值 " + (isNullOrEmpty ? "是" : "不是") + " null or empty.");
  10. }
  11. /**
  12. * 获得两个字符串相同的前缀或者后缀
  13. */
  14. @Test
  15. public void testCommonPrefixSuffix() {
  16. String a = "com.jd.coo.Hello";
  17. String b = "com.jd.coo.Hi";
  18. String ourCommonPrefix = Strings.commonPrefix(a, b);
  19. //a,b 相同的前缀是: com.jd.coo.H
  20. System.out.println("a,b 相同的前缀是: " + ourCommonPrefix);
  21. String c = "com.google.Hello";
  22. String d = "com.jd.Hello";
  23. String ourSuffix = Strings.commonSuffix(c, d);
  24. //c,d 相同的后缀是: .Hello
  25. System.out.println("c,d 相同的后缀是: " + ourSuffix);
  26. }
  27. /**
  28. * Strings的padStart和padEnd方法来补全字符串
  29. */
  30. @Test
  31. public void testpadStartEnd() {
  32. int minLength = 4;
  33. //在后面补完,4位。如前边是12,补全4位,使用0,应该是1200;如果是123,补全4位是1230.前边补全类似
  34. String padEndResult = Strings.padEnd("123", minLength, '0');
  35. System.out.println("padEndResult is " + padEndResult);
  36. String padStartResult = Strings.padStart("1", 2, '0');
  37. System.out.println("padStartResult is " + padStartResult);
  38. }
  39. /**
  40. * 使用Splitter类来拆分字符串
  41. * Splitter类可以方便的根据正则表达式来拆分字符串,可以去掉拆分结果中的空串,可以对拆分后的字串做trim操作,还可以做二次拆分。
  42. * 我们先看一个基本的拆分例子:
  43. */
  44. @Test
  45. public void testSplitter() {
  46. //JDK
  47. String splitterStr = ",a,,b,";
  48. String[] strArray = splitterStr.split(",");
  49. //length:4
  50. System.out.println("length:" + strArray.length);
  51. //GUAVA
  52. List<String> listStr = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(splitterStr);
  53. //length:[a, b]
  54. System.out.println("length:" + listStr);
  55. String str = "xiaoming=11,xiaohong=23";
  56. Map<String, String> map = Splitter.on(",").withKeyValueSeparator("=").split(str);
  57. //{xiaoming=11, xiaohong=23}
  58. System.out.println(map);
  59. //GUAVA,Splitter的onPattern方法传入的是一个正则表达式,其后紧跟的trimResults()方法表示要对结果做trim,omitEmptyStrings()表示忽略空字符串,split方法会执行拆分操作。
  60. Iterable<String> splitResults = Splitter.onPattern("[,,]{1,}")
  61. .trimResults()
  62. .omitEmptyStrings()
  63. .split("hello,word,,世界,水平");
  64. for (String item : splitResults) {
  65. //分别输出:hello、word、世界、水平
  66. System.out.println(item);
  67. }
  68. //split返回的结果为Iterable<String>,我们可以使用for循环语句来逐个打印拆分字符串的结果。
  69. //Splitter还有更强大的功能,做二次拆分,这里二次拆分的意思是拆分两次,例如我们可以将a=b;c=d这样的字符串拆分成一个Map<String,String>。
  70. //二次拆分首先是使用onPattern做第一次的拆分,然后再通过withKeyValueSeperator('')方法做第二次的拆分。
  71. String toSplitString = "a=b;c=d,e=f";
  72. Map<String, String> kvs = Splitter.onPattern("[,;]{1,}").withKeyValueSeparator('=').split(toSplitString);
  73. for (Map.Entry<String, String> entry : kvs.entrySet()) {
  74. System.out.println(String.format("%s=%s", entry.getKey(), entry.getValue()));
  75. }
  76. }
  77. /**
  78. * 有拆分字符串必然就有合并字符串,guava为我们提供了Joiner类来做字符串的合并
  79. * Splitter类可以方便的根据正则表达式来拆分字符串,可以去掉拆分结果中的空串,可以对拆分后的字串做trim操作,还可以做二次拆分。
  80. * 我们先看一个基本的拆分例子:
  81. */
  82. @Test
  83. public void testJoiner() {
  84. String joinResult = Joiner.on(" ").join(new String[]{"hello", "world"});
  85. System.out.println(joinResult);
  86. // 上面例子中我们使用Joiner.on(" ").join(xx)来合并字符串。很简单也很有效。
  87. //
  88. // Splitter方法可以对字符串做二次的拆分,对应的Joiner也可以逆向操作,将Map<String,String>做合并。我们看下下面的例子:
  89. String toSplitString = "a=b;c=d,e=f";
  90. Map<String, String> kvs = Splitter.onPattern("[,;]{1,}").withKeyValueSeparator('=').split(toSplitString);
  91. for (Map.Entry<String, String> entry : kvs.entrySet()) {
  92. System.out.println(String.format("%s=%s", entry.getKey(), entry.getValue()));
  93. }
  94. Map<String, String> map = new HashMap<String, String>();
  95. map.put("a", "b");
  96. map.put("c", "d");
  97. String mapJoinResult = Joiner.on(",").withKeyValueSeparator("=").join(kvs);
  98. System.out.println(mapJoinResult);
  99. // 使用withKeyValueSeparator方法可以对map做合并。合并的结果是:a=b,c=d
  100. }
  101. /**
  102. * 大小写转换
  103. * CaseFormat是一种实用工具类,以提供不同的ASCII字符格式之间的转换。
  104. * UPPER_CAMEL,即我们常说的"驼峰式"编写方式;其次,我们常用的是:UPPER_UNDERSCORE,即我们常用的常量命名法,
  105. */
  106. @Test
  107. public void testCaseFormat() {
  108. //testData
  109. System.out.println(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, "test-data"));
  110. //testData
  111. System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "test_data"));
  112. //TestData
  113. System.out.println(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "test_data"));
  114. //testdata
  115. System.out.println(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "testdata"));
  116. //test_data
  117. System.out.println(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "TestData"));
  118. //test-data
  119. System.out.println(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, "testData"));
  120. }
  121. /**
  122. * 字符匹配
  123. */
  124. @Test
  125. public void testCharMatcher() {
  126. // 移除字符串中的数字
  127. String str = CharMatcher.DIGIT.removeFrom("ac2dgc45dbg4");
  128. System.out.println(str);
  129. // 只保留字符串中的数字
  130. String str1 = CharMatcher.DIGIT.retainFrom("ac2dgc45dbg4");
  131. System.out.println(str1);
  132. //使用*替换字符串中的数字
  133. String str2 = CharMatcher.DIGIT.replaceFrom("ac2dgc45dbg4", "*");
  134. System.out.println(str2);
  135. // 移除字符串中a-z的所有小写字母
  136. String str3 = CharMatcher.inRange('1', 'z').removeFrom("0a0bcz8xy5mDgilBpoDyegA");
  137. System.out.println(str3);
  138. }
  139. }

[TOC]
缓存,在我们日常开发中是必不可少的一种解决性能问题的方法。简单的说,cache 就是为了提升系统性能而开辟的一块内存空间。
缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升。

缓存在很多系统和架构中都用广泛的应用,例如:
1.CPU缓存
2.操作系统缓存
3.本地缓存
4.分布式缓存
5.HTTP缓存
6.数据库缓存
等等,可以说在计算机和网络领域,缓存无处不在。可以这么说,只要有硬件性能不对等,涉及到网络传输的地方都会有缓存的身影。

Guava Cache(本地缓存)

Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好。
Guava Cache有两种创建方式:

  1. cacheLoader
  2. callable callback
    通过这两种方法创建的cache,和通常用map来缓存的做法比,不同在于,这两种方法都实现了一种逻辑——从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法来获取这个值。但不同的在于cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。

cacheLoader方式实现实例:
  1. LoadingCache<String, String> cahceBuilder = CacheBuilder
  2. .newBuilder()
  3. .build(new CacheLoader<String, String>() {
  4. @Override
  5. public String load(String key) throws Exception {
  6. String strProValue = "hello " + key + "!";
  7. return strProValue;
  8. }
  9. });
  10. System.out.println("jerry value:" + cahceBuilder.apply("jerry"));
  11. System.out.println("jerry value:" + cahceBuilder.get("jerry"));
  12. System.out.println("peida value:" + cahceBuilder.get("peida"));
  13. System.out.println("peida value:" + cahceBuilder.apply("peida"));
  14. System.out.println("lisa value:" + cahceBuilder.apply("lisa"));
  15. cahceBuilder.put("harry", "ssdded");
  16. System.out.println("harry value:" + cahceBuilder.get("harry"));

输出:

jerry value:hello jerry!
jerry value:hello jerry!
peida value:hello peida!
peida value:hello peida!
lisa value:hello lisa!
harry value:ssdded

callable callback的实现:
  1. /**
  2. * callable callback的实现
  3. *
  4. * @throws Exception
  5. */
  6. @Test
  7. public void testcallableCache() throws Exception {
  8. Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
  9. String resultVal = cache.get("jerry", new Callable<String>() {
  10. public String call() {
  11. String strProValue = "hello " + "jerry" + "!";
  12. return strProValue;
  13. }
  14. });
  15. System.out.println("jerry value : " + resultVal);
  16. resultVal = cache.get("peida", new Callable<String>() {
  17. public String call() {
  18. String strProValue = "hello " + "peida" + "!";
  19. return strProValue;
  20. }
  21. });
  22. System.out.println("peida value : " + resultVal);
  23. }

输出:
jerry value : hello jerry!
peida value : hello peida!

cache的参数说明:

回收的参数:

  1. 大小的设置:CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(long)
  2. 时间:expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)
  3. 引用:CacheBuilder.weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues()
  4. 明确的删除:invalidate(key) invalidateAll(keys) invalidateAll()
  5. 删除监听器:CacheBuilder.removalListener(RemovalListener)
    refresh机制:
  6. LoadingCache.refresh(K) 在生成新的value的时候,旧的value依然会被使用。
  7. CacheLoader.reload(K, V) 生成新的value过程中允许使用旧的value
  8. CacheBuilder.refreshAfterWrite(long, TimeUnit) 自动刷新cache

基于泛型的实现:

  1. /**
  2. * 不需要延迟处理(泛型的方式封装)
  3. *
  4. * @return
  5. */
  6. public <K, V> LoadingCache<K, V> cached(CacheLoader<K, V> cacheLoader) {
  7. LoadingCache<K, V> cache = CacheBuilder
  8. .newBuilder()
  9. .maximumSize(2)
  10. .weakKeys()
  11. .softValues()
  12. .refreshAfterWrite(120, TimeUnit.SECONDS)
  13. .expireAfterWrite(10, TimeUnit.MINUTES)
  14. .removalListener(new RemovalListener<K, V>() {
  15. @Override
  16. public void onRemoval(RemovalNotification<K, V> rn) {
  17. System.out.println(rn.getKey() + "被移除");
  18. }
  19. })
  20. .build(cacheLoader);
  21. return cache;
  22. }
  23. /**
  24. * 通过key获取value
  25. * 调用方式 commonCache.get(key) ; return String
  26. *
  27. * @param key
  28. * @return
  29. * @throws Exception
  30. */
  31. public LoadingCache<String, String> commonCache(final String key) throws Exception {
  32. LoadingCache<String, String> commonCache = cached(new CacheLoader<String, String>() {
  33. @Override
  34. public String load(String key) throws Exception {
  35. return "hello " + key + "!";
  36. }
  37. });
  38. return commonCache;
  39. }
  40. @Test
  41. public void testCache() throws Exception {
  42. LoadingCache<String, String> commonCache = commonCache("peida");
  43. System.out.println("peida:" + commonCache.get("peida"));
  44. commonCache.apply("harry");
  45. System.out.println("harry:" + commonCache.get("harry"));
  46. commonCache.apply("lisa");
  47. System.out.println("lisa:" + commonCache.get("lisa"));
  48. }

输出:

peida:hello peida!
harry:hello harry!
peida被移除
lisa:hello lisa!

基于泛型的Callable Cache实现:

  1. private static Cache<String, String> cacheFormCallable = null;
  2. /**
  3. * 对需要延迟处理的可以采用这个机制;(泛型的方式封装)
  4. * @param <K>
  5. * @param <V>
  6. * @param key
  7. * @param callable
  8. * @return V
  9. * @throws Exception
  10. */
  11. public static <K,V> Cache<K , V> callableCached() throws Exception {
  12. Cache<K, V> cache = CacheBuilder
  13. .newBuilder()
  14. .maximumSize(10000)
  15. .expireAfterWrite(10, TimeUnit.MINUTES)
  16. .build();
  17. return cache;
  18. }
  19. private String getCallableCache(final String userName) {
  20. try {
  21. //Callable只有在缓存值不存在时,才会调用
  22. return cacheFormCallable.get(userName, new Callable<String>() {
  23. @Override
  24. public String call() throws Exception {
  25. System.out.println(userName+" from db");
  26. return "hello "+userName+"!";
  27. }
  28. });
  29. } catch (ExecutionException e) {
  30. e.printStackTrace();
  31. return null;
  32. }
  33. }
  34. @Test
  35. public void testCallableCache() throws Exception{
  36. final String u1name = "peida";
  37. final String u2name = "jerry";
  38. final String u3name = "lisa";
  39. cacheFormCallable=callableCached();
  40. System.out.println("peida:"+getCallableCache(u1name));
  41. System.out.println("jerry:"+getCallableCache(u2name));
  42. System.out.println("lisa:"+getCallableCache(u3name));
  43. System.out.println("peida:"+getCallableCache(u1name));
  44. }

输出:

peida from db
peida:hello peida!
jerry from db
jerry:hello jerry!
lisa from db
lisa:hello lisa!
peida:hello peida!

说明:Callable只有在缓存值不存在时,才会调用,比如第二次调用getCallableCache(u1name)直接返回缓存中的值

guava Cache数据移除

guava做cache时候数据的移除方式,在guava中数据的移除分为被动移除和主动移除两种。

被动移除数据的方式,guava默认提供了三种方式:
1.基于大小的移除:看字面意思就知道就是按照缓存的大小来移除,如果即将到达指定的大小,那就会把不常用的键值对从cache中移除。
定义的方式一般为 CacheBuilder.maximumSize(long),还有一种一种可以算权重的方法,个人认为实际使用中不太用到。就这个常用的来看有几个注意点,
其一,这个size指的是cache中的条目数,不是内存大小或是其他;
其二,并不是完全到了指定的size系统才开始移除不常用的数据的,而是接近这个size的时候系统就会开始做移除的动作;
其三,如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
2.基于时间的移除:guava提供了两个基于时间移除的方法
expireAfterAccess(long, TimeUnit) 这个方法是根据某个键值对最后一次访问之后多少时间后移除
expireAfterWrite(long, TimeUnit) 这个方法是根据某个键值对被创建或值被替换后多少时间移除
3.基于引用的移除:
这种移除方式主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除

主动移除数据方式,主动移除有三种方法:
1.单独移除用 Cache.invalidate(key)
2.批量移除用 Cache.invalidateAll(keys)
3.移除所有用 Cache.invalidateAll()
如果需要在移除数据的时候有所动作还可以定义Removal Listener,但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)

一、只读设置

  1. package Guava;
  2. import java.util.ArrayList;
  3. import java.util.Collections;
  4. import java.util.List;
  5. import com.google.common.collect.ImmutableList;
  6. /**
  7. * 只读设置
  8. */
  9. public class Demo01 {
  10. public static void main(String[] args) {
  11. List<String> list = new ArrayList<>();
  12. list.add("a");
  13. list.add("b");
  14. list.add("c");
  15. //对原有的List进行包装,相当于原有List的视图,快照,不够安全.
  16. List<String> readList = Collections.unmodifiableList(list);
  17. //java.lang.UnsupportedOperationException
  18. //readList.add("d");//报错
  19. list.add("d");//改变原有List 视图也一起改变 不报错
  20. System.out.println(readList);
  21. //Guava
  22. //对比查看 初始化List guava对只读设置安全可靠 并且相对简单
  23. List<String> immutableList = ImmutableList.of("a","b","c");
  24. //java.lang.UnsupportedOperationException
  25. //immutableList.add("d");//报错
  26. System.out.println(immutableList);
  27. }
  28. }

运行结果
[a, b, c, d]
[a, b, c]

二、函数式编程

  1. package Guava;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Collection;
  4. import java.util.List;
  5. import java.util.Set;
  6. import com.google.common.base.Function;
  7. import com.google.common.base.Functions;
  8. import com.google.common.base.Predicate;
  9. import com.google.common.collect.Collections2;
  10. import com.google.common.collect.Lists;
  11. import com.google.common.collect.Sets;
  12. /**
  13. * 函数式编程:解耦
  14. * 1、Predicate 断言
  15. * 2、Function
  16. * 函数的组合式编程
  17. * Functions.compose(f1, f2);
  18. * 工具: Collections2.filter 过滤器
  19. * Collections2.transform 转换
  20. */
  21. public class Demo02 {
  22. public static void main(String[] args) {
  23. test1();//过滤器
  24. System.out.println("----------------");
  25. test2();
  26. System.out.println("----------------");
  27. test3();
  28. }
  29. //过滤器
  30. public static void test1()
  31. {
  32. //创建List 静态初始化
  33. List<String> list = Lists.newArrayList("SDF","SDAF","FASD","MOOM","ESDSE");
  34. //找出回文
  35. //匿名内部类对象:匿名内部类,同时创建类对象
  36. Collection<String> palindroomList = Collections2.filter(list, new Predicate<String>() {
  37. public boolean apply(String input)
  38. {
  39. //业务逻辑
  40. return new StringBuilder(input).reverse().toString().equals(input);
  41. }
  42. });
  43. for(String temp:palindroomList)
  44. {
  45. System.out.println(temp);
  46. }
  47. }
  48. //转换
  49. public static void test2()
  50. {
  51. //类型转换
  52. Set<Long> timeSet = Sets.newHashSet();
  53. timeSet.add(1000000L);
  54. timeSet.add(999999999999L);
  55. timeSet.add(20000000L);
  56. Collection<String> timeStrCol = Collections2.transform(timeSet, new Function<Long, String>() {
  57. @Override
  58. public String apply(Long input) {
  59. return new SimpleDateFormat("yyyy-MM-dd").format(input);
  60. }
  61. });
  62. for(String temp:timeStrCol)
  63. {
  64. System.out.println(temp);
  65. }
  66. }
  67. //组合式函数编程
  68. public static void test3(){
  69. //确保容器中的字符串长度不超过5,超过进行截取,后全部大写
  70. List<String> list = Lists.newArrayList("lovebaby","good","happiness");
  71. //确保容器中的字符串长度不超过5,超过进行截取
  72. Function<String, String> f1 = new Function<String, String>() {
  73. @Override
  74. public String apply(String input) {
  75. return input.length()>5?input.substring(0,5):input;
  76. }
  77. };
  78. //全部大写
  79. Function<String, String> f2 = new Function<String, String>() {
  80. @Override
  81. public String apply(String input) {
  82. return input.toUpperCase();
  83. }
  84. };
  85. //组合使用
  86. //String = f2(f1(String))
  87. Function<String, String> f = Functions.compose(f1, f2);
  88. Collection<String> resultCol = Collections2.transform(list,f);
  89. for(String temp:resultCol)
  90. {
  91. System.out.println(temp);
  92. }
  93. }
  94. }

运行结果:
MOOM
ESDSE

1970-01-01
1970-01-01
2001-09-09

LOVEB
GOOD
HAPPI

三、约束条件

  1. package Guava;
  2. import static com.google.common.base.Preconditions.checkNotNull;
  3. import java.util.Collection;
  4. import java.util.Set;
  5. import com.google.common.collect.ForwardingSet;
  6. import com.google.common.collect.Lists;
  7. /**
  8. * 解决guava-18.0.jar不能使用
  9. * com.google.common.collect.Constraints、
  10. * com.google.common.collect.Constraint 的问题。
  11. * @author liguodong
  12. * @param <E>
  13. */
  14. interface Constraint<E>{
  15. //public String checkElement(String element);
  16. E checkElement(E element);
  17. }
  18. class Constraints<E>{
  19. public static <E> Set<E> constrainedSet(
  20. Set<E> set, Constraint<? super E> constraint) {
  21. return new ConstrainedSet<E>(set, constraint);
  22. }
  23. private static <E> Collection<E> checkElements(
  24. Collection<E> elements, Constraint<? super E> constraint) {
  25. Collection<E> copy = Lists.newArrayList(elements);
  26. for (E element : copy) {
  27. constraint.checkElement(element);
  28. }
  29. return copy;
  30. }
  31. /** @see Constraints#constrainedSet */
  32. static class ConstrainedSet<E> extends ForwardingSet<E> {
  33. private final Set<E> delegate;
  34. private final Constraint<? super E> constraint;
  35. public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
  36. this.delegate = checkNotNull(delegate);
  37. this.constraint = checkNotNull(constraint);
  38. }
  39. @Override protected Set<E> delegate() {
  40. return delegate;
  41. }
  42. @Override public boolean add(E element) {
  43. constraint.checkElement(element);
  44. return delegate.add(element);
  45. }
  46. @Override public boolean addAll(Collection<? extends E> elements) {
  47. return delegate.addAll(checkElements(elements, constraint));
  48. }
  49. }
  50. }
  1. package Guava;
  2. import java.util.Set;
  3. import com.google.common.base.Preconditions;
  4. //import com.google.common.collect.Constraint;
  5. //import com.google.common.collect.Constraints;
  6. import com.google.common.collect.Sets;
  7. /**
  8. * 加入约束条件:非空,长度验证
  9. * Constraint
  10. * Precondiotions
  11. * Constrains
  12. */
  13. public class Demo03 {
  14. public static void main(String[] args) {
  15. Set<String> sets = Sets.newHashSet();
  16. //创建约束
  17. Constraint<String> constraint = new Constraint<String>() {
  18. @Override
  19. public String checkElement(String element) {
  20. //非空验证
  21. Preconditions.checkNotNull(element);
  22. //长度验证5-20
  23. Preconditions.checkArgument(element.length()>=5&&element.length()<=20);
  24. return element;
  25. }
  26. };
  27. Set<String> cs = Constraints.constrainedSet(sets, constraint);
  28. //cs.add(null);// java.lang.NullPointerException
  29. //cs.add("doog");//java.lang.IllegalArgumentException
  30. cs.add("liguodong");
  31. for(String temp:cs)
  32. {
  33. System.out.println(temp);
  34. }
  35. }
  36. }

运行结果
liguodong

四、集合的操作

  1. package Guava;
  2. import java.util.Set;
  3. import com.google.common.collect.Sets;
  4. import com.google.common.collect.Sets.SetView;
  5. /**
  6. * 集合的操作:交集,差集,并集
  7. * Sets.intersection()
  8. * Sets.difference()
  9. * Sets.union()
  10. */
  11. public class Demo04 {
  12. public static void main(String[] args) {
  13. Set<Integer> sets = Sets.newHashSet(1,2,3,4,5,6);
  14. Set<Integer> sets2 = Sets.newHashSet(3,4,5,6,7,8,9);
  15. //交集
  16. System.out.println("交集为:");
  17. SetView<Integer> intersection = Sets.intersection(sets, sets2);
  18. for(Integer temp:intersection)
  19. {
  20. System.out.print(temp+" ");
  21. }
  22. System.out.println();
  23. //差集
  24. System.out.println("差集为:");
  25. SetView<Integer> diff = Sets.difference(sets, sets2);
  26. for(Integer temp:diff)
  27. {
  28. System.out.print(temp+" ");
  29. }
  30. System.out.println();
  31. //并集
  32. System.out.println("并集为:");
  33. SetView<Integer> union = Sets.union(sets, sets2);
  34. for(Integer temp:union)
  35. {
  36. System.out.print(temp+" ");
  37. }
  38. System.out.println();
  39. }
  40. }

运行结果
交集为:
3 4 5 6
差集为:
1 2
并集为:
1 2 3 4 5 6 7 8 9

五、MultiSet

  1. package Guava;
  2. import java.util.Set;
  3. import com.google.common.collect.HashMultiset;
  4. import com.google.common.collect.Multiset;
  5. /**
  6. * 统计单词出现的次数
  7. * 1.HashMap 分拣存储+面向对象思维-->判断
  8. * 2.MultiSet:无序+可重复 count()方法获取单词的次数 增强了可读性+操作简单
  9. */
  10. public class Demo05 {
  11. public static void main(String[] args) {
  12. String str = "this is a cat that is a mice where is the food";
  13. //分割字符串
  14. String[] strArray = str.split(" ");
  15. //存储到Multiset中
  16. Multiset<String> set = HashMultiset.create();
  17. for(String temp :strArray)
  18. {
  19. set.add(temp);
  20. }
  21. //获取所有的单词Set
  22. Set<String> letters = set.elementSet();
  23. for(String temp:letters)
  24. {
  25. System.out.println(temp+"-->"+set.count(temp));
  26. }
  27. }
  28. }

运行结果
mice—>1
that—>1
cat—>1
is—>3
food—>1
a—>2
the—>1
where—>1
this—>1

六、Multimap

  1. package Guava;
  2. import java.util.Collection;
  3. import java.util.HashMap;
  4. import java.util.Iterator;
  5. import java.util.Map;
  6. import java.util.Set;
  7. import com.google.common.collect.ArrayListMultimap;
  8. import com.google.common.collect.Multimap;
  9. /**
  10. * 分析查看 教师 教授 的每门课程
  11. * Multimap:key-value key可以重复
  12. */
  13. public class Demo06 {
  14. public static void main(String[] args) {
  15. Map<String,String> cours = new HashMap<>();
  16. //加入测试数据
  17. cours.put("改革开放","邓小平");
  18. cours.put("三个代表","江泽民");
  19. cours.put("和谐社会","胡锦涛");
  20. cours.put("八荣八耻","胡锦涛");
  21. cours.put("互联网+","李克强");
  22. //Multimap
  23. Multimap<String, String> teachers = ArrayListMultimap.create();
  24. //迭代器
  25. Iterator<Map.Entry<String, String>> it = cours.entrySet().iterator();
  26. while(it.hasNext())
  27. {
  28. Map.Entry<String, String> entry = it.next();
  29. String key = entry.getKey();//课程
  30. String value = entry.getValue();//教师
  31. //教师-->课程
  32. teachers.put(value,key);
  33. }
  34. //查看Multimap
  35. Set<String> keyset = teachers.keySet();
  36. for(String key:keyset)
  37. {
  38. Collection<String> col = teachers.get(key);
  39. System.out.println(key+"-->"+col);
  40. }
  41. }
  42. }

运行结果
邓小平—>[改革开放]
江泽民—>[三个代表]
胡锦涛—>[八荣八耻, 和谐社会]
李克强—>[互联网+]

七、BiMap

  1. package Guava;
  2. import com.google.common.collect.BiMap;
  3. import com.google.common.collect.HashBiMap;
  4. /**
  5. * HashMap 键唯一,值可以重复
  6. * BiMap:双向Map(Bidirectional Map) 键与值都不能重复(unique -valued map)
  7. */
  8. public class Demo07 {
  9. public static void main(String[] args) {
  10. BiMap<String, String> biMap = HashBiMap.create();
  11. biMap.put("liguodong", "liguodong@sina.com");
  12. biMap.put("good","good@qq.com");
  13. //通过邮箱找用户
  14. String user = biMap.inverse().get("good@qq.com");
  15. System.out.println(user);
  16. System.out.println( biMap.inverse().inverse()==biMap );
  17. }
  18. }

运行结果
good
true

八、双键的Map

  1. package Guava;
  2. import java.util.Map;
  3. import java.util.Set;
  4. import com.google.common.collect.HashBasedTable;
  5. import com.google.common.collect.Table;
  6. import com.google.common.collect.Table.Cell;
  7. import com.google.common.collect.Tables;
  8. /**
  9. * 双键的Map--> Table-->rowKey+columnKey+value
  10. * 1.方法
  11. * 所有的行数据:cellSet()
  12. * 所有的学生:rowKeySet()
  13. * 所有的课程:columnKeySet()
  14. * 所有的成绩:values()
  15. * 学生对应的课程:rowMap()+get(学生)
  16. * row(学生)
  17. *
  18. * 课程对应的学生:columnMap()+get(课程)
  19. * column(课程)
  20. */
  21. public class Demo08 {
  22. public static void main(String[] args) {
  23. Table<String, String, Integer> tables = HashBasedTable.create();
  24. //测试数据
  25. tables.put("a", "javase", 80);
  26. tables.put("b", "javase", 90);
  27. tables.put("a", "oracle", 100);
  28. tables.put("c", "javase", 95);
  29. //所有的行数据
  30. Set<Cell<String, String, Integer>> cells = tables.cellSet();
  31. for(Cell<String, String, Integer> temp:cells)
  32. {
  33. System.out.println(temp.getRowKey()+"-->"+temp.getColumnKey()+"-->"+temp.getValue());
  34. }
  35. System.out.println("=======学生查看成绩============");
  36. System.out.print("学生\t");
  37. //所有的课程
  38. Set<String> cours = tables.columnKeySet();
  39. for(String t:cours)
  40. {
  41. System.out.print(t+"\t");
  42. }
  43. System.out.println();
  44. //所有的学生
  45. Set<String> stus = tables.rowKeySet();
  46. for(String stu:stus)
  47. {
  48. System.out.print(stu+"\t");//输出学生
  49. //以下是输出学生的每一门课程
  50. Map<String,Integer> scores = tables.row(stu);//<课程,分数>
  51. for(String c:cours)//课程
  52. {
  53. System.out.print(scores.get(c)+"\t");
  54. }
  55. System.out.println();
  56. }
  57. System.out.println("=======课程查看成绩============");
  58. System.out.print("课程\t");
  59. //所有的学生
  60. Set<String> stus1 = tables.rowKeySet();
  61. for(String t:stus1)
  62. {
  63. System.out.print(t+"\t");
  64. }
  65. System.out.println();
  66. //所有的课程
  67. Set<String> cours1 = tables.columnKeySet();
  68. for(String c:cours1)
  69. {
  70. System.out.print(c+"\t");//课程
  71. Map<String,Integer> scores = tables.column(c);//<学生,分数>
  72. for(String s:stus1)
  73. {
  74. System.out.print(scores.get(s)+"\t");
  75. }
  76. System.out.println();
  77. }
  78. System.out.println("=======转换===========");
  79. Table<String, String, Integer> tables2 = Tables.transpose(tables);
  80. //所有的行数据
  81. Set<Cell<String, String, Integer>> cells2 = tables2.cellSet();
  82. for(Cell<String, String, Integer> temp:cells2)
  83. {
  84. System.out.println(temp.getRowKey()+"-->"+temp.getColumnKey()+"-->"+temp.getValue());
  85. }
  86. }
  87. }

运行结果
b—>javase—>90
c—>javase—>95
a—>oracle—>100
a—>javase—>80
=学生查看成绩======
学生 javase oracle
b 90 null
c 95 null
a 80 100
=课程查看成绩======
课程 b c a
javase 90 95 80
oracle null null 100
=转换=====
javase—>b—>90
javase—>c—>95
oracle—>a—>100
javase—>a—>80