The open source class library of star standard 39.9k + on GitHub can't help sharing

Hello, I'm Guava.

I'm open source by Google. At present, there are 39.9k iron powder on GitHub, which can prove my popularity.

My body mainly contains these common modules: collection [collections], caching [caching], native type support [primitives support], concurrency libraries [concurrency libraries], common annotations [common annotations], string processing [string processing], I/O, etc. The new version of JDK has directly introduced me. You can imagine how excellent I am and can't help being proud.

Let's say that learning how to use me well can make you happier in programming and write more elegant code!

PS: in order to help more Java enthusiasts, the advanced path of Java programmers has been open source to GitHub (this article has been included). At present, 754 stars have been harvested in this column. If you like this column and find it helpful, you can click star, which is also convenient for more systematic learning in the future:

https://github.com/itwanger/toBeBetterJavaer

02. Introduction of Guava

If you want to use me in Maven project, you need to first introduce my dependency in pom.xml file.

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

This requires that the JDK version should be above 8.

03. Basic tools

Doug Lea, the author of the java.util.concurrent package, once said, "null is terrible.". Tony Hoare, the Turing prize winner, the author of the quick sort algorithm, and of course the creator of null, once said something similar: "the use of null cost me a billion dollars." in view of this, I use Optional to represent objects that may be null.

The code example is shown below.

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

My big brother Java added in JDK 8 Optional class Obviously, he borrowed from me, but his is a little different from mine.

  • My Optional is abstract, which means I can have subclass objects; My eldest brother's is final, which means there are no subclass objects.

  • My Optional implements the Serializable interface, which can be serialized; My eldest brother doesn't.

  • Some of my methods are different from my big brother's.

In addition to giving null semantics and increasing readability, the biggest advantage of using Optional is that it is a fool's protection. Option forces you to think positively about missing references because you have to explicitly get references from option.

In addition to Optional, I also provide:

  • Parameter verification
  • Common Object methods, such as Objects.equals and Objects.hashCode, are provided by the Objects class introduced in JDK 7. Of course, they are also inspired by me.
  • More powerful comparator

04. Collection

First, let me talk about why we need immutable sets.

  • Ensure thread safety. In concurrent programs, the use of immutable sets not only ensures the safety of threads, but also greatly enhances the efficiency of concurrency (compared with concurrent locking).

  • If an object does not need to support modification operations, immutable collections will save space and time.

  • It can be treated as a constant, and the objects in the collection will not be changed in the future.

Compared with the Immutable set provided in JDK, the Immutable provided by me is truly Immutable. Why do I say so? Take a look at the following example.

The following code uses the JDK Collections.unmodifiableList(list) to get an unmodifiable collection unmodifiableList.

List list = new ArrayList();
list.add("Lei Jun");
list.add("Steve Jobs");

List unmodifiableList = Collections.unmodifiableList(list);
unmodifiableList.add("Jack Ma");

The following exceptions will occur when running the code:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.base/java.util.Collections$UnmodifiableCollection.add(Collections.java:1060)
    at com.itwanger.guava.NullTest.main(NullTest.java:29)

Good. When executing unmodifiableList.add(), an unsupported operationexception is thrown, indicating that Collections.unmodifiableList() returns an immutable collection. But is that true?

You can replace unmodifiableList.add() with list.add().

List list = new ArrayList();
list.add("Lei Jun");
list.add("Steve Jobs");

List unmodifiableList = Collections.unmodifiableList(list);
list.add("Jack Ma");

If you execute it again, the program does not report an error, and you will find that there is really one more element in the unmodifiableList. What does that mean?

Collections.unmodifiableList(...) does not implement a real immutable set. When the original set is modified, the elements in the immutable set also change.

I wouldn't make such a mistake. Let's look at the code below.

List<String> stringArrayList = Lists.newArrayList("Lei Jun","Steve Jobs");
ImmutableList<String> immutableList = ImmutableList.copyOf(stringArrayList);
immutableList.add("Jack Ma");

UnsupportedOperationException will be thrown when trying immutableList.add(). I have abandoned the add () method in the source code.

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */

  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean add(E e) {
    throw new UnsupportedOperationException();
  }

immutableList does not change when you try to modify the original set with stringArrayList.add().

In addition to immutable sets, I also provide new set types, such as:

  • Multiset, you can add equal elements multiple times. When multiset is regarded as an ordinary Collection, it behaves like an unordered ArrayList; When multiset is regarded as map < e, integer >, it also provides query operations that meet performance expectations.

  • Multimap, you can easily map a key to multiple values.

  • BiMap, a special Map, can be inverted with inverse()
    Bimap, > key value mapping; The guaranteed values are unique, so values() returns a Set instead of a normal Collection.

05. String processing

A string represents an immutable sequence of characters that cannot be changed after creation. In our daily work, strings are used very frequently. Skilled operation can greatly improve our work efficiency.

I provided a connector, Joiner, which can connect string sequences with separators. The following code will return "Lei Jun; jobs". You can use the useForNull(String) method to replace null with a string instead of ignoring null directly like the skippnulls () method.

Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("Lei Jun"null"Steve Jobs");

I also provided a Splitter, which can split the string sequence according to the specified separator.

Splitter.on(',')
        .trimResults()
        .omitEmptyStrings()
        .split("Lei Jun,Steve Jobs,,   Silent King II");

06. Cache

Caching is useful in many scenarios. You should know that retrieving a value is expensive, especially when you need to get the value more than once, you should consider using cache.

The Cache I provided is very similar to the ConcurrentMap, but not exactly the same. The most basic difference is that the ConcurrentMap keeps all added elements until they are explicitly removed. In contrast, the Cache I provide is usually set to automatically recycle elements in order to limit memory consumption.

If you are willing to consume some memory space to improve the speed, you can expect that some keys will be queried more than once, and the total amount of data stored in the Cache will not exceed the memory capacity, you can use Cache.

Let's give you an example.

@Test
public void testCache() throws ExecutionException, InterruptedException {

    CacheLoader cacheLoader = new CacheLoader<String, Animal>() {
        //  If the element is not found, it will be called here
        @Override
        public Animal load(String s) {
            return null;
        }
    };
    LoadingCache<String, Animal> loadingCache = CacheBuilder.newBuilder()
        .maximumSize(1000//  capacity
        .expireAfterWrite(3, TimeUnit.SECONDS) //  Expiration time
        .removalListener(new MyRemovalListener()) //  Failure listener
        .build(cacheLoader); //
    loadingCache.put("dog"new Animal("Wangcai"1));
    loadingCache.put("cat"new Animal("Tom"3));
    loadingCache.put("wolf"new Animal("Grey Wolf"4));

    loadingCache.invalidate("cat"); //  Manual failure

    Animal animal = loadingCache.get("wolf");
    System.out.println(animal);
    Thread.sleep(4 * 1000);
    //  The wolf has passed by automatically. Get as   null   Value error
    System.out.println(loadingCache.get("wolf"));
}

/**
 * Cache remove listener
 */

class MyRemovalListener implements RemovalListener<StringAnimal{

    @Override
    public void onRemoval(RemovalNotification<String, Animal> notification) {
        String reason = String.format("key=%s,value=%s,reason=%s", notification.getKey(), notification.getValue(), notification.getCause());
        System.out.println(reason);
    }
}

class Animal {
    private String name;
    private Integer age;

    public Animal(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

The load method is rewritten in the CacheLoader. This method will be called when the query cache misses. I directly return null here. In fact, this will throw the CacheLoader returned null for key exception message when the cache misses.

MyRemovalListener, as a listening class when the cache element fails, will automatically call the onRemoval method when the cache element fails. Note that this method is a synchronous method. If it takes a long time, it will block until the processing is completed.

LoadingCache is the main operation object of cache, and the put and get methods are commonly used.

07. Ending

The above describes the most commonly used functions. As the open source Java development core library of Google, I think it is very practical (otherwise? Hehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehehe). After being introduced into your project, it can not only quickly realize some common functions in development, but also make the code more elegant and concise.

I think it is applicable to every Java project. As for other functions, such as hashing, event bus, mathematical operation and reflection, it is waiting for you to explore.

This is the 70th column of the advanced path of Java programmers (remember to order a star). The column is humorous, easy to understand, and extremely friendly and comfortable for java lovers 😄, The content includes but is not limited to core knowledge points such as Java foundation, Java collection framework, Java IO, Java Concurrent Programming, Java virtual machine, Java enterprise development (Maven, Git, SSM, Spring Boot).

https://github.com/itwanger/toBeBetterJavaer

Let's become better Java engineers together!

Tags: Java

Posted on Mon, 29 Nov 2021 20:34:54 -0500 by Eclectic