Guava 中文是石榴的意思,该项目是 Google 的一个开源项目,包含许多 Google 核心的 Java 常用库。

目前主要包含:

  • com.google.common.annotations
  • com.google.common.base
  • com.google.common.collect
  • com.google.common.io
  • com.google.common.net
  • com.google.common.primitives
  • com.google.common.util.concurrent

guava是 google 几个java核心类库的集合,包括集合、缓存、原生类型、并发、常用注解、基本字符串操作和I/O等等。 
   
   大家平时经常遇到某些相同的问题,自己写代码也都能解决。但是久而久之会感觉到很痛苦,因为我们一而再,再而三的重复发明轮子。为了不再忍受痛苦,也许我们可以总结自己的类库,但是新的问题来了。自己总结的类库很难与大家分享,不能帮助到更多人。同时自己的类库要不断的进行维护。guava 正是出于这样的目的而来的。

只说不练不行啊,让我们举上一两个例子 
判断 String不为null,且不为空

Java代码  
  1. String str=...;
  2. //use java
  3. if(str !=null && !str.isEmpty()){
  4. //do something
  5. }
  6. //use guava
  7. if(!Strings.isNullOrEmpty(str)){
  8. //do something
  9. }

上而的例子还不是很给力,让我们举一个更给力的例子。复制文件

Java代码  
  1. File from=...;
  2. File to=...;
  3. //use java
  4. FileInputStream in=new FileInputStream(from);
  5. FileOutputStream out=new FileOutputStream(to);
  6. byte[] buff=new byte[1024];
  7. int readLength=-1;
  8. while((readLength = in.read(buff)) > 0){
  9. out.write(buff, 0, readLength);
  10. }
  11. in.close();
  12. out.close();
  13. //use guava
  14. Files.copy(from,to); //注意,只用了一行代码噢

通过上面的例子,已经能感觉到guava的强大。接下来,让我们更深入看看guava的其他功能。guava(r09-api)分为这几个包

  • base              基本的工具类与接口
  • io                 io流相关的工具类与方法
  • net               网络地址相关的工具类与方法
  • primitives        原始类型的工具类
  • collect           通用集合接口与实现,与其集合相关工具类
  • util.concurrent 并发相关工具类

base

字符串相关工具类 
Strings

Java代码  
  1. public class StringsTest {
  2. @Test
  3. public void test() {
  4. //将空字符串转换为null
  5. Assert.assertEquals(null, Strings.emptyToNull(""));
  6. //将null转换为空字符串
  7. Assert.assertEquals("", Strings.nullToEmpty(null));
  8. //判断字符串为null或者为空
  9. Assert.assertTrue(Strings.isNullOrEmpty("") && Strings.isNullOrEmpty(null));
  10. //将字符串重复
  11. Assert.assertEquals("javajavajava", Strings.repeat("java", 3));
  12. }
  13. }

CharMatcher

Java代码  
  1. public class CharMatcherTest {
  2. @Test
  3. public void test() {
  4. String source = "a1b2c3";
  5. CharMatcher matcher = CharMatcher.DIGIT; //预定义的 DIGIT 类型
  6. Assert.assertTrue(mathcer.match('8'));
  7. Assert.assertEquals("123", matcher.retainFrom(source));
  8. Assert.assertEquals(3, matcher.countIn(source));
  9. Assert.assertEquals("abc", matcher.removeFrom(source));
  10. Assert.assertEquals("a2b3c", matcher.trimFrom("1a2b3c4"));
  11. }
  12. }

Jioner

Java代码  
  1. public class JoinerTest {
  2. @Test
  3. public void test() {
  4. Assert.assertEquals("2011-08-04", Joiner.on("-").join("2011", "08", "04"));
  5. }
  6. }

Splitter

Java代码  
  1. public class SplitterTest {
  2. @Test
  3. public void test() {
  4. Splitter.on(',').split("a,b"); //结果返回Iterable<String>,包含 "a" and "b"
  5. //将结果中的元素trim
  6. //结果依然包含  "a" 和 "b" ,而不是 "a " 和 " b"
  7. Splitter.on(',').trimResults().split("a , b");
  8. //忽略空字符串
  9. //结果必须是"a" 和 "b",而不是 "a" ,"" 和 "b"
  10. Splitter.on(',').omitEmptyStrings().split("a,,b");
  11. }
  12. }

CaseFormat

Java代码  
  1. public class CaseFormatTest {
  2. @Test
  3. public void test() throws IOException {
  4. // helloGuava => HELLO_GUAVA
  5. Assert.assertEquals("HELLO_GUAVA", CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, "helloGuava"));
  6. // hello-guava => HelloGuava
  7. Assert.assertEquals("HelloGuava", CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, "hello-guava"));
  8. }
  9. }

其他 
Preconditions 
有些方法在执行前,先要检查传入的参数是否正确,或者类的状态是否正确。通常会这样做

Java代码  
  1. if (count <= 0) {
  2. throw new IllegalArgumentException("must be positive: " + count);
  3. }

guava就可以这样,达到相同的效果

Java代码  
  1. Preconditions.checkArgument(count > 0, "must be positive: %s", count);

I/O 
ByteStreams提供了针对字节流的工具方法

Java代码  
  1. InputStream from=...;
  2. OutputStream to=...;
  3. ByteStreams.copy(from,to); //复制

CharStreams提供了针对字符流的工具方法

Java代码  
  1. Reader from =...;
  2. Writer to =...;
  3. CharStreams.copy(from, to); //复制

Files提供了针对文件的工具方法

Java代码  
  1. File from=...;
  2. File to=...;
  3. Files.copy(from, to); //复制
Java代码  
  1. Files.deleteDirectoryContents(File directory); //删除文件夹下的内容(包括文件与子文件夹)
  2. Files.deleteRecursively(File file); //删除文件或者文件夹
  3. Files.move(File from, File to); //移动文件

Resources提供了针对classpath下资源操作的工具方法

Java代码  
  1. URL url = Resources.getResource("config.xml"); //获取classpath根下的config.xml文件url
 
 

Google Guava Collections 使用介绍

Google Guava Collections(以下都简称为 Guava Collections)是 Java Collections Framework 的增强和扩展。每个 Java 开发者都会在工作中使用各种数据结构,很多情况下 Java Collections Framework 可以帮助你完成这类工作。但是在有些场合你使用了 Java Collections Framework 的 API,但还是需要写很多代码来实现一些复杂逻辑,这个时候就可以尝试使用 Guava Collections 来帮助你完成这些工作。这些高质量的 API 使你的代码更短,更易于阅读和修改,工作更加轻松。

目标读者

对于理解 Java 开源工具来说,本文读者至少应具备基础的 Java 知识,特别是 JDK5 的特性。因为 Guava Collections 充分使用了范型,循环增强这样的特性。作为 Java Collections Framework 的增强,读者必须对 Java Collections Framework 有清晰的理解,包括主要的接口约定和常用的实现类。并且 Guava Collections 很大程度上是帮助开发者完成比较复杂的数据结构的操作,因此基础的数据结构和算法的知识也是清晰理解 Guava Collections 的必要条件。

项目背景

Guava Collections 是 Google 的工程师 Kevin Bourrillion 和 Jared Levy 在著名"20%"时间写的代码。当然作为开源项目还有其他的开发者贡献了代码。在编写的过程中,Java Collections Framework 的作者 Joshua Bloch 也参与了代码审核和提出建议。目前它已经移到另外一个叫 guava-libraries 的开源项目下面来维护。

因为功能相似而且又同是开源项目,人们很很自然会把它和 Apache Commons Collections 来做比较。其区别归结起来有以下几点:

Guava Collections 充分利用了 JDK5 的范型和枚举这样的特性,而 Apache Commons Collections 则是基于 JDK1.2。其次 Guava Collections 更加严格遵守 Java Collections Framework 定义的接口契约,而在 Apache Commons Collections 你会发现不少违反这些 JDK 接口契约的地方。这些不遵守标准的地方就是出 bug 的风险很高。最后 Guava Collections 处于积极的维护状态,本文介绍的特性都基于目前最新 2011 年 4 月的 Guava r09 版本,而 Apache Commons Collections 最新一次发布也已经是 2008 年了。

功能列举

可以说 Java Collections Framework 满足了我们大多数情况下使用集合的要求,但是当遇到一些特殊的情况我们的代码会比较冗长,比较容易出错。Guava Collections 可以帮助你的代码更简短精炼,更重要是它增强了代码的可读性。看看 Guava Collections 为我们做了哪些很酷的事情。

  • Immutable Collections: 还在使用 Collections.unmodifiableXXX() ? Immutable Collections 这才是真正的不可修改的集合
  • Multiset: 看看如何把重复的元素放入一个集合
  • Multimaps: 需要在一个 key 对应多个 value 的时候 , 自己写一个实现比较繁琐 - 让 Multimaps 来帮忙
  • BiMap: java.util.Map 只能保证 key 的不重复,BiMap 保证 value 也不重复
  • MapMaker: 超级强大的 Map 构造类
  • Ordering class: 大家知道用 Comparator 作为比较器来对集合排序,但是对于多关键字排序 Ordering class 可以简化很多的代码
  • 其他特性

当然,如果没有 Guava Collections 你也可以用 Java Collections Framework 完成上面的功能。但是 Guava Collections 提供的这些 API 经过精心设计,而且还有 25000 个单元测试来保障它的质量。所以我们没必要重新发明轮子。接下来我们来详细看看 Guava Collections 的一些具体功能。

 

回页首

Immutable Collections: 真正的不可修改的集合

大家都用过 Collections.unmodifiableXXX() 来做一个不可修改的集合。例如你要构造存储常量的 Set,你可以这样来做 :

 Set<String> set = new HashSet<String>(Arrays.asList(new String[]{"RED", "GREEN"}));   Set<String> unmodifiableSet = Collections.unmodifiableSet(set);  

这看上去似乎不错,因为每次调 unmodifiableSet.add() 都会抛出一个 UnsupportedOperationException。感觉安全了?慢!如果有人在原来的 set 上 add 或者 remove 元素会怎么样?结果 unmodifiableSet 也是被 add 或者 remove 元素了。而且构造这样一个简单的 set 写了两句长的代码。下面看看 ImmutableSet 是怎么来做地更安全和简洁 :

 ImmutableSet<String> immutableSet = ImmutableSet.of("RED", "GREEN");  

就这样一句就够了,而且试图调 add 方法的时候,它一样会抛出 UnsupportedOperationException。重要的是代码的可读性增强了不少,非常直观地展现了代码的用意。如果像之前这个代码保护一个 set 怎么做呢?你可以 :

 ImmutableSet<String> immutableSet = ImmutableSet.copyOf(set);  

从构造的方式来说,ImmutableSet 集合还提供了 Builder 模式来构造一个集合 :

 Builder<String>  builder = ImmutableSet.builder();   ImmutableSet<String> immutableSet = builder.add("RED").addAll(set).build();  

在这个例子里面 Builder 不但能加入单个元素还能加入既有的集合。

除此之外,Guava Collections 还提供了各种 Immutable 集合的实现:ImmutableList,ImmutableMap,ImmutableSortedSet,ImmutableSortedMap。

 

回页首

Multiset: 把重复的元素放入集合

你可能会说这和 Set 接口的契约冲突,因为 Set 接口的 JavaDoc 里面规定不能放入重复元素。事实上,Multiset 并没有实现 java.util.Set 接口,它更像是一个 Bag。普通的 Set 就像这样 :[car, ship, bike],而 Multiset 会是这样 : [car x 2, ship x 6, bike x 3]。

譬如一个 List 里面有各种字符串,然后你要统计每个字符串在 List 里面出现的次数 :

 Map<String, Integer> map = new HashMap<String, Integer>();   for(String word : wordList){      Integer count = map.get(word);      map.put(word, (count == null) ? 1 : count + 1);   }   //count word “the”  Integer count = map.get(“the”);  

如果用 Multiset 就可以这样 :

 HashMultiset<String> multiSet = HashMultiset.create();   multiSet.addAll(wordList);   //count word “the”  Integer count = multiSet.count(“the”);  

这样连循环都不用了,而且 Multiset 用的方法叫 count,显然比在 Map 里面调 get 有更好的可读性。Multiset 还提供了 setCount 这样设定元素重复次数的方法,虽然你可以通过使用 Map 来实现类似的功能,但是程序的可读性比 Multiset 差了很多。

常用实现 Multiset 接口的类有:

  • HashMultiset: 元素存放于 HashMap
  • LinkedHashMultiset: 元素存放于 LinkedHashMap,即元素的排列顺序由第一次放入的顺序决定
  • TreeMultiset:元素被排序存放于TreeMap
  • EnumMultiset: 元素必须是 enum 类型
  • ImmutableMultiset: 不可修改的 Mutiset

看到这里你可能已经发现 Guava Collections 都是以 create 或是 of 这样的静态方法来构造对象。这是因为这些集合类大多有多个参数的私有构造方法,由于参数数目很多,客户代码程序员使用起来就很不方便。而且以这种方式可以返回原类型的子类型对象。另外,对于创建范型对象来讲,这种方式更加简洁。

 

回页首

Multimap: 在 Map 的 value 里面放多个元素

Muitimap 就是一个 key 对应多个 value 的数据结构。看上去它很像 java.util.Map 的结构,但是 Muitimap 不是 Map,没有实现 Map 的接口。设想你对 Map 调了 2 次参数 key 一样的 put 方法,结果就是第 2 次的 value 覆盖了第 1 次的 value。但是对 Muitimap 来说这个 key 同时对应了 2 个 value。所以 Map 看上去是 : {k1=v1, k2=v2,...},而 Muitimap 是 :{k1=[v1, v2, v3], k2=[v7, v8],....}。

举个记名投票的例子。所有选票都放在一个 List<Ticket> 里面,List 的每个元素包括投票人和选举人的名字。我们可以这样写 :

 //Key is candidate name, its value is his voters   HashMap<String, HashSet<String>> hMap = new HashMap<String, HashSet<String>>();   for(Ticket ticket: tickets){      HashSet<String> set = hMap.get(ticket.getCandidate());      if(set == null){          set = new HashSet<String>();          hMap.put(ticket.getCandidate(), set);      }      set.add(ticket.getVoter());   }  

我们再来看看 Muitimap 能做些什么 :

 HashMultimap<String, String> map = HashMultimap.create();   for(Ticket ticket: tickets){      map.put(ticket.getCandidate(), ticket.getVoter());   }  

就这么简单!

Muitimap 接口的主要实现类有:

  • HashMultimap: key 放在 HashMap,而 value 放在 HashSet,即一个 key 对应的 value 不可重复
  • ArrayListMultimap: key 放在 HashMap,而 value 放在 ArrayList,即一个 key 对应的 value 有顺序可重复
  • LinkedHashMultimap: key 放在 LinkedHashMap,而 value 放在 LinkedHashSet,即一个 key 对应的 value 有顺序不可重复
  • TreeMultimap: key 放在 TreeMap,而 value 放在 TreeSet,即一个 key 对应的 value 有排列顺序
  • ImmutableMultimap: 不可修改的 Multimap
 

回页首

BiMap: 双向 Map

BiMap 实现了 java.util.Map 接口。它的特点是它的 value 和它 key 一样也是不可重复的,换句话说它的 key 和 value 是等价的。如果你往 BiMap 的 value 里面放了重复的元素,就会得到 IllegalArgumentException。

举个例子,你可能经常会碰到在 Map 里面根据 value 值来反推它的 key 值的逻辑:

 for(Map.Entry<User, Address> entry : map.entreSet()){      if(entry.getValue().equals(anAddess)){          return entry.getKey();      }   }   return null;  

如果把 User 和 Address 都放在 BiMap,那么一句代码就得到结果了:

 return biMap.inverse().get(anAddess);  

这里的 inverse 方法就是把 BiMap 的 key 集合 value 集合对调,因此 biMap == biMap.inverse().inverse()。

BiMap的常用实现有:

HashBiMap: key 集合与 value 集合都有 HashMap 实现

EnumBiMap: key 与 value 都必须是 enum 类型

ImmutableBiMap: 不可修改的 BiMap

 

回页首

MapMaker: 超级强大的 Map 构造工具

MapMaker 是用来构造 ConcurrentMap 的工具类。为什么可以把 MapMaker 叫做超级强大?看了下面的例子你就知道了。首先,它可以用来构造 ConcurrentHashMap:

 //ConcurrentHashMap with concurrency level 8   ConcurrentMap<String, Object> map1 = new MapMaker()      .concurrencyLevel(8)       .makeMap();  

或者构造用各种不同 reference 作为 key 和 value 的 Map:

 //ConcurrentMap with soft reference key and weak reference value   ConcurrentMap<String, Object> map2 = new MapMaker()      .softKeys()      .weakValues()      .makeMap();  

或者构造有自动移除时间过期项的 Map:

 //Automatically removed entries from map after 30 seconds since they are created   ConcurrentMap<String, Object> map3 = new MapMaker()      .expireAfterWrite(30, TimeUnit.SECONDS)      .makeMap();  

或者构造有最大限制数目的 Map:

 //Map size grows close to the 100, the map will evict   //entries that are less likely to be used again   ConcurrentMap<String, Object> map4 = new MapMaker()      .maximumSize(100)      .makeMap();  

或者提供当 Map 里面不包含所 get 的项,而需要自动加入到 Map 的功能。这个功能当 Map 作为缓存的时候很有用 :

 //Create an Object to the map, when get() is missing in map   ConcurrentMap<String, Object> map5 = new MapMaker()      .makeComputingMap(        new Function<String, Object>() {          public Object apply(String key) {            return createObject(key);      }});  

这些还不是最强大的特性,最厉害的是 MapMaker 可以提供拥有以上所有特性的 Map:

 //Put all features together!   ConcurrentMap<String, Object> mapAll = new MapMaker()      .concurrencyLevel(8)      .softKeys()      .weakValues()      .expireAfterWrite(30, TimeUnit.SECONDS)      .maximumSize(100)      .makeComputingMap(        new Function<String, Object>() {          public Object apply(String key) {            return createObject(key);       }});  
 

回页首

Ordering class: 灵活的多字段排序比较器

要对集合排序或者求最大值最小值,首推 java.util.Collections 类,但关键是要提供 Comparator 接口的实现。假设有个待排序的 List<Foo>,而 Foo 里面有两个排序关键字 int a, int b 和 int c:

 Collections.sort(list, new Comparator<Foo>(){         @Override         public int compare(Foo f1, Foo f2) {             int resultA = f1.a – f2.a;          int resultB = f1.b – f2.b;          return  resultA == 0 ? (resultB == 0 ? f1.c – f2.c : resultB) : resultA;  

}});

这看上去有点眼晕,如果用一串 if-else 也好不到哪里去。看看 ComparisonChain 能做到什么 :

 Collections.sort(list, new Comparator<Foo>(){         @Override      return ComparisonChain.start()            .compare(f1.a, f2.a)            .compare(f1.b, f2.b)           .compare(f1.c, f2.c).result();           }}); 

如果排序关键字要用自定义比较器,compare 方法也有接受 Comparator 的重载版本。譬如 Foo 里面每个排序关键字都已经有了各自的 Comparator,那么利用 ComparisonChain 可以 :

 Collections.sort(list, new Comparator<Foo>(){         @Override      return ComparisonChain.start()            .compare(f1.a, f2.a, comparatorA)            .compare(f1.b, f2.b, comparatorB)           .compare(f1.c, f2.c, comparatorC).result();           }}); 

Ordring 类还提供了一个组合 Comparator 对象的方法。而且 Ordring 本身实现了 Comparator 接口所以它能直接作为 Comparator 使用:

 Ordering<Foo> ordering = Ordering.compound(\      Arrays.asList(comparatorA, comparatorB, comparatorc));   Collections.sort(list, ordering);  
 

回页首

其他特性 :

过滤器:利用 Collections2.filter() 方法过滤集合中不符合条件的元素。譬如过滤一个 List<Integer> 里面小于 10 的元素 :

 Collection<Integer>  filterCollection =          Collections2.filter(list, new Predicate<Integer>(){      @Override      public boolean apply(Integer input) {          return input >= 10;   }});  

当然,你可以自己写一个循环来实现这个功能,但是这样不能保证之后小于 10 的元素不被放入集合。filter 的强大之处在于返回的 filterCollection 仍然有排斥小于 10 的元素的特性,如果调 filterCollection.add(9) 就会得到一个 IllegalArgumentException。

转换器:利用 Collections2.transform() 方法来转换集合中的元素。譬如把一个 Set<Integer> 里面所有元素都转换成带格式的 String 来产生新的 Collection<String>:

 Collection<String>  formatCollection =        Collections2.transform(set, new Function<Integer, String>(){      @Override      public String apply(Integer input) {          return new DecimalFormat("#,###").format(input);   }} ); 

有关google的guava工具包详细说明的更多相关文章

  1. Google的Guava之IO升华

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/luo201227/article/details/36413279 程序员在开发过程中,使用文件的几 ...

  2. google guava工具包

    guava这个工具包里有好多有用的工具类 <dependency> <groupId>com.google.guava</groupId> <artifact ...

  3. 自己动手做AI:Google AIY开发工具包解析

    2018年国际消费性电子展(CES)上,最明显的一个趋势是Amazon与Google的语音技术进驻战,如AmazonAlexa进驻到Acer笔电内,Google Assist进驻到KIA汽车内,其他如 ...

  4. Google的Guava类库简介(转)

    说明:信息虽然有点旧,至少可以先了解个大概. Guava是一个Google的基于Java的类库集合的扩展项目,包括collections, caching, primitives support, c ...

  5. Google的Guava工具类splitter和apache stringutil对比 编辑

    一直用的是apache的stringutil工具类,其实google的工具类项目 guava中居然也有字符串的分隔类splitter的,在 http://code.google.com/p/guava ...

  6. Google的Guava它Collection升华

    至于Guava这是不是在这里说.一个已被提上一个非常特殊的! 这主要是为了分享Guava对于一些升华处理组.井,不多说了,直接在代码: package com.joyce.guava.bean; /* ...

  7. Guava 教程1-使用 Google Collections,Guava,static imports 编写漂亮代码

    原文出处: oschina (API:http://ifeve.com/category/framework/guava-2/ JAR DOC Source 链接:http://pan.baidu.c ...

  8. google中guava类库:AsyncEventBus

    1.guava事件总线(AsyncEventBus)使用 1.1引入依赖 <dependency> <groupId>com.google.guava</groupId& ...

  9. spring中添加google的guava缓存(demo)

    1.pom文件中配置 <dependencies> <dependency> <groupId>org.springframework</groupId> ...

随机推荐

  1. shiro框架总结

    一.概念 shiro是一个安全框架,主要可以帮助我们解决程序开发中认证和授权的问题.基于拦截器做的权限系统,权限控制的粒度有限,为了方便各种各样的常用的权限管理需求的实现,,我们有必要使用比较好的安全 ...

  2. nmon使用问题汇总(不定期更新)

    nmon使用问题汇总 1.nmon常用命令: ./nmon -s1 -c300 -f -m /root/nmon-test-result/项目-50并发/ 2.设置nmon参数为-s1 -c720,发 ...

  3. hackerone或PayPal转账到国内银行卡

    1.首先hackerone会提示有W9那么一说,这个是美国人纳税的,我们是中国人不需要纳税的,只要给美国税务局发邮件说你是中国人不需要纳税就OK了.具体操作百度. 2.如此就会成功转账到你的PayPa ...

  4. C++中decltype(*)作为模板实参时的隐藏问题

    在函数模板中使用智能指针时,可能会希望根据指针的类型推导出指针引用的对象类型作为模板参数,于是写出以下代码: shared_ptr<decltype(*objPtr)>(objPtr); ...

  5. IOS(苹果手机)使用video播放HLS流,实现在内部播放及全屏播放(即非全屏和全屏播放)。

    需求: 实现PC及移动端播放HLS流,并且可以自动播放,在页面内部播放及全屏播放功能. 初步:PC及安卓机使用hls.js实现hls流自动播放及全屏非全屏播放 首先使用了hls.js插件,可以实现在P ...

  6. mysql之日志

    我是李福春,我在准备面试,今天的题目是: mysql的redolog和binlog有什么区别? 答: 如下面的表格, redolog vs binlog 然后我们扩展一下,因为日志主要是记录的修改日志 ...

  7. 扩展KMP(记录学习过程)

    首先看了几篇博客,发现还得耐下心来理解,动手画图 ,才能理解俩字符串还有数组之间神奇的关系 这篇博客图不错:https://segmentfault.com/a/1190000008663857 /* ...

  8. 在MVC三层项目中如何使用Log4Net

    --前期准备(添加到队列中) 0-1在新建后的MVC项目中的[Models]中添加一个类,用于处理异常信息,并继承自HandleErrorAttribute public class MyExcept ...

  9. sql 模块 pymysql 数据库操作

    1. 添加一个部门. import pymysql def main(): no = int(input('编号: ')) name = input('名字: ') loc = input('所在地: ...

  10. cento升级openssl依旧显示老版本

    不久前拿到了一季度的服务器漏洞扫描报告,还是一些老生常谈的软件.按照报告上的漏洞一个个处理,开始升级openssl的时候一切都很顺利,上传源码包,解压,编译,安装,全部都没有报错.opessl --v ...