{"id":510,"date":"2010-10-31T14:31:00","date_gmt":"2010-10-31T12:31:00","guid":{"rendered":""},"modified":"2023-03-23T12:50:06","modified_gmt":"2023-03-23T11:50:06","slug":"google-guava-v07-examples","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2010\/10\/31\/google-guava-v07-examples\/","title":{"rendered":"Google Guava v07 examples"},"content":{"rendered":"<div style=\"text-align: left\" dir=\"ltr\">We have something called Weekly Technology Workshops at TouK, that is, every Friday at 16:00 somebody has a presentation for everyone willing to come. We present stuff we learn and work on at home, but we also have a bulletin board with topics that people would like to listen about. Last week Maciej Pr\u00f3chniak had a talk about <a href=\"http:\/\/clojure.org\/\">Clojure<\/a>, this time a few folks asked for an introduction to <a href=\"http:\/\/code.google.com\/p\/guava-libraries\/\">Google Guava libraries<\/a>.Since this was a dead simple task, I was happy to deliver.<\/p>\n<p><strong>WTF is Guava?<\/strong><\/p>\n<p>It&#8217;s a set of very simple, basic classes, that you end up writing yourself anyway. Think in terms of Apache commons, just by Google. Just to make your life a little bit easier.<\/p>\n<p>There is an early (v04) <a href=\"http:\/\/guava-libraries.googlecode.com\/files\/Guava_for_Netflix_.pdf\">presentation<\/a> and there was <a href=\"http:\/\/blog.mocna-kawa.com\/2010\/06\/javarsovia-lekcja-stylu-slajdy\/\">a different one<\/a> (in Polish) at Javarsowia 2010 by <a href=\"http:\/\/blog.mocna-kawa.com\/\">Wiktor Gworek<\/a>.<\/p>\n<p>At the time of writing this, the latest version is v07, it&#8217;s been mavenized and is available at a <a href=\"http:\/\/repo1.maven.org\/maven2\/com\/google\/guava\/guava\/\">public maven repo<\/a>.<\/p>\n<p>Here&#8217;s a quick review of a few interesting things. Don&#8217;t expect anything fancy though, Guava is very BASIC.<\/p>\n<p><strong><br \/>\n@VisibleForTesting <\/strong><\/p>\n<p>A simple annotation that tells you why a particular property access restriction has been relaxed.<\/p>\n<p>A common trick to use in testing is to relax access restrictions to default for a particular property, so that you can use it in a unit test, which resides in the same package (though in different catalog). Whether you thing it&#8217;s good or bad, remember to give a hint about that to the developer.<\/p>\n<p>Consider:<\/p>\n<pre class=\"brush:java\">public class User {\r\n    private Long id;\r\n    private String firstName;\r\n    private String lastName;\r\n    String login;<\/pre>\n<p>Why is login package scoped?<\/p>\n<pre class=\"brush:java\">public class User {\r\n    private Long id;\r\n    private String firstName;\r\n    private String lastName;\r\n    @VisibleForTesting String login;<\/pre>\n<p>Ah, that&#8217;s why.<\/p>\n<p><strong><br \/>\nPreconditions<\/strong><\/p>\n<p>Guava has a few preconditions for defensive programming (Design By Contract), but they are not quite as good as what Apache Commons \/ Spring framework has. One thing interesting is that Guava solution returns the object, so could be inlined. Consider:<\/p>\n<p>Using hand written preconditions:<\/p>\n<pre class=\"brush:java\">public User(Long id, String firstName, String lastName, String login) {\r\n        validateParameters(id, firstName, lastName, login);\r\n        this.id = id;\r\n        this.firstName = firstName;\r\n        this.lastName = lastName;\r\n        this.login = login.toLowerCase();\r\n    }\r\n\r\n    private void validateParameters(Long id, String firstName, String lastName, String login) {\r\n        if(id == null ) {\r\n            throw new IllegalArgumentException(\"id cannot be null\");\r\n        }\r\n\r\n        if(firstName == null || firstName.length() == 0) {\r\n            throw new IllegalArgumentException(\"firstName cannot be empty\");\r\n        }\r\n\r\n        if(lastName == null || lastName.length() == 0) {\r\n            throw new IllegalArgumentException(\"lastName cannot be empty\");\r\n        }\r\n\r\n        if(login == null || login.length() == 0) {\r\n            throw new IllegalArgumentException(\"login cannot be empty\");\r\n        }\r\n    }<\/pre>\n<p>Using guava preconditions:<\/p>\n<pre class=\"brush:java\">public void fullyImplementedGuavaConstructorWouldBe(Long id, String firstName, String lastName, String login) {\r\n        this.id = checkNotNull(id);\r\n        this.firstName = checkNotNull(firstName);\r\n        this.lastName = checkNotNull(lastName);\r\n        this.login = checkNotNull(login);\r\n\r\n        checkArgument(firstName.length() &gt; 0);\r\n        checkArgument(lastName.length() &gt; 0);\r\n        checkArgument(login.length() &gt; 0);\r\n    }<\/pre>\n<p>(Thanks Yom for noticing that checkNotNull must go before checkArgument, though it makes it a bit unintuitive)<\/p>\n<p>Using spring or apache commons preconditions (the use looks exactly the same for both libraries):<\/p>\n<pre class=\"brush:java\">public void springConstructorWouldBe(Long id, String firstName, String lastName, String login) {\r\n        notNull(id); hasText(firstName); hasText(lastName); hasText(login);\r\n        this.id = id;\r\n        this.firstName = firstName;\r\n        this.lastName = lastName;\r\n        this.login = login;\r\n    }<\/pre>\n<p><strong>CharMatcher<\/strong><\/p>\n<p>For people who hate regexp or just want a simple and good looking object style pattern matching solution.<\/p>\n<p>Examples:<\/p>\n<p>And\/or ease of use<\/p>\n<pre class=\"brush:java\">        String input = \"This invoice has an id of 192\/10\/10\";\r\n        CharMatcher charMatcher = CharMatcher.DIGIT.or(CharMatcher.is('\/'));\r\n        String output = charMatcher.retainFrom(input);<\/pre>\n<p>output is: 192\/10\/10<\/p>\n<p>Negation:<\/p>\n<pre class=\"brush:java\">        String input = \"DO NOT scream at me!\";\r\n        CharMatcher charMatcher = CharMatcher.JAVA_LOWER_CASE.or(CharMatcher.WHITESPACE).negate();\r\n        String output = charMatcher.retainFrom(input);<\/pre>\n<p>output is: DONOT!<\/p>\n<p>Ranges:<\/p>\n<pre class=\"brush:java\">        String input = \"DO NOT scream at me!\";\r\n        CharMatcher charMatcher = CharMatcher.inRange('m', 's').or(CharMatcher.is('a').or(CharMatcher.WHITESPACE));\r\n        String output = charMatcher.retainFrom(input);<\/pre>\n<p>output is: sram a m<\/p>\n<p><strong>Joiner \/ Splitter<\/strong><\/p>\n<p>As the names suggest, it&#8217;s string joining\/splitting done the right way, although I find the inversion of calls a bit&#8230; oh well, it&#8217;s java.<\/p>\n<pre class=\"brush:java\">        String[] fantasyGenres = {\"Space Opera\", \"Horror\", \"Magic realism\", \"Religion\"};\r\n        String joined = Joiner.on(\", \").join(fantasyGenres);<\/pre>\n<p>Output: Space Opera, Horror, Magic realism, Religion<\/p>\n<p>You can skip nulls:<\/p>\n<pre class=\"brush:java\">        String[] fantasyGenres = {\"Space Opera\", null, \"Horror\", \"Magic realism\", null, \"Religion\"};\r\n        String joined = Joiner.on(\", \").skipNulls().join(fantasyGenres);<\/pre>\n<p>Output: Space Opera, Horror, Magic realism, Religion<\/p>\n<p>You can fill nulls:<\/p>\n<pre class=\"brush:java\">        String[] fantasyGenres = {\"Space Opera\", null, \"Horror\", \"Magic realism\", null, \"Religion\"};\r\n        String joined = Joiner.on(\", \").useForNull(\"NULL!!!\").join(fantasyGenres);<\/pre>\n<p>Output: Space Opera, NULL!!!, Horror, Magic realism, NULL!!!, Religion<\/p>\n<p>You can join maps<\/p>\n<pre class=\"brush:java\">        Map map = newHashMap();\r\n        map.put(1, \"Space Opera\");\r\n        map.put(2, \"Horror\");\r\n        map.put(3, \"Magic realism\");\r\n        String joined = Joiner.on(\", \").withKeyValueSeparator(\" -&gt; \").join(map);<\/pre>\n<p>Output: 1 \u2192 Space Opera, 2 \u2192 Horror, 3 \u2192 Magic realism<\/p>\n<p>Split returns Iterable instead of JDK arrays:<\/p>\n<pre class=\"brush:java\">        String input = \"Some very stupid data with ids of invoces like 121432, 3436534 and 8989898 inside\";\r\n        Iterable splitted = Splitter.on(\" \").split(input);<\/pre>\n<p>Split does fixed length splitting, although you cannot give a different length for each \u201ccolumn\u201d which makes it&#8217;s use a bit limited while parsing some badly exported excels.<\/p>\n<pre class=\"brush:java\">        String input =\r\n                \"A  1  1  1  1\\n\" +\r\n                \"B  1  2  2  2\\n\" +\r\n                \"C  1  2  3  3\\n\" +\r\n                \"D  1  2  5  3\\n\" +\r\n                \"E  3  2  5  4\\n\" +\r\n                \"F  3  3  7  5\\n\" +\r\n                \"G  3  3  7  5\\n\" +\r\n                \"H  3  3  9  7\";\r\n        Iterable splitted = Splitter.fixedLength(3).trimResults().split(input);<\/pre>\n<p>You can use CharMatcher while splitting<\/p>\n<pre class=\"brush:java\">        String input = \"Some very stupid data with ids of invoces like 123231\/fv\/10\/2010, 123231\/fv\/10\/2010 and 123231\/fv\/10\/2010\";\r\n        Iterable splitted = Splitter.on(CharMatcher.DIGIT.negate())\r\n                                            .trimResults()\r\n                                            .omitEmptyStrings()\r\n                                            .split(input);<\/pre>\n<p><strong>Predicates \/ Functions<\/strong><\/p>\n<p>Predicates alone are not much, it&#8217;s just an interface with a method that returns true, but if you combine predicates with functions and Collections2 (a guava class that simplifies working on collections), you get a nice tool in your toolbox.<\/p>\n<p>But let&#8217;s start with basic predicate use. Imagine we want to find whether there are users who have logins with digits inside. The inocation would be (returns boolean):<\/p>\n<pre class=\"brush:java\">Predicates.in(users).apply(shouldNotHaveDigitsInLoginPredicate);<\/pre>\n<p>And the predicate looks like that<\/p>\n<pre class=\"brush:java\">public class ShouldNotHaveDigitsInLoginPredicate implements Predicate {\r\n    @Override\r\n    public boolean apply(User user) {\r\n        checkNotNull(user);\r\n        return CharMatcher.DIGIT.retainFrom(user.login).length() == 0;\r\n    }    \r\n}<\/pre>\n<p>Now lets add a function that will transform a user to his full name:<\/p>\n<pre class=\"brush:java\">public class FullNameFunction implements Function {\r\n    @Override\r\n    public String apply(User user) {\r\n        checkNotNull(user);\r\n        return user.getFirstName() + \" \" + user.getLastName();\r\n    }    \r\n}<\/pre>\n<p>You can invoke it using static method transform:<\/p>\n<pre class=\"brush:java\">List users = newArrayList(new User(1L, \"sylwek\", \"stall\", \"rambo\"),\r\n  new User(2L, \"arnold\", \"schwartz\", \"commando\"));\r\n\r\nList fullNames = transform(users, new FullNameFunction());<\/pre>\n<p>And now lets combine predicates with functions to print names of users that have logins which do not contain digits:<\/p>\n<pre class=\"brush:java\">List users = newArrayList(new User(1L, \"sylwek\", \"stall\", \"rambo\"), \r\n  new User(2L, \"arnold\", \"schwartz\", \"commando\"), \r\n  new User(3L, \"hans\", \"kloss\", \"jw23\"));\r\n\r\nCollection usersWithoutDigitsInLogin = filter(users, new ShouldNotHaveDigitsInLoginPredicate());\r\nString names = Joiner.on(\"\\n\").join( transform(usersWithoutDigitsInLogin, new FullNameFunction()) );<\/pre>\n<p>What we do not get: <a href=\"http:\/\/en.wikipedia.org\/wiki\/Fold_(higher-order_function)\">fold (reduce)<\/a> and <a href=\"http:\/\/en.wikipedia.org\/wiki\/Tuple\">tuples<\/a>. Oh well, you&#8217;d probably turn to <a href=\"http:\/\/functionaljava.org\/\">Java Functional Library<\/a> anyway, if you wanted functions in Java, right?<\/p>\n<p><strong>CaseFormat<\/strong><\/p>\n<p>Ever wanted to turn those ugly <a href=\"http:\/\/pear.php.net\/\">PHP Pear<\/a> names into nice java\/cpp style with one liner? No? Well, anyway, you can:<\/p>\n<pre class=\"brush:java\">String pearPhpName = \"Really_Fucked_Up_PHP_PearConvention_That_Looks_UGLY_because_of_no_NAMESPACES\";\r\nString javaAndCPPName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL , pearPhpName);<\/pre>\n<p>Output: ReallyFuckedUpPhpPearconventionThatLooksUglyBecauseOfNoNamespaces<\/p>\n<p>But since Oracle has taken over Sun, you may actually want to turn those into sql style, right?<\/p>\n<pre class=\"brush:java\">        String sqlName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, javaAndCPPName);<\/pre>\n<p>Output: really_fucked_up_php_pearconvention_that_looks_ugly_because_of_no_namespaces<\/p>\n<p><strong>Collections<\/strong><\/p>\n<p>Guava has a superset of <a href=\"http:\/\/code.google.com\/p\/google-collections\/\">Google collections library 1.0<\/a>, and this indeed is a very good reason to include this dependency in your poms. I won&#8217;t even try to describe all the features, but just to point out a few nice things:<\/p>\n<ul>\n<li>you have an Immutable version of pretty much everything<\/li>\n<li>you get a few nice static and statically typed methods on common types like Lists, Sets, Maps, ObjectArrays, which include:\n<ul>\n<li>easy way of creating based on return type: e.g. newArrayList<\/li>\n<li>transform (way to apply functions that returns Immutable version)<\/li>\n<li>partition (paging)<\/li>\n<li>reverse<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>And now for a few more interesting collections.<br \/>\n<strong>Mutlimaps<\/strong><\/p>\n<p>Mutlimap is basically a map that can have many values for a single key. Ever had to create a Map&gt; in your code? You don&#8217;t have to anymore.<\/p>\n<pre class=\"brush:java\">Multimap multimap = HashMultimap.create();\r\n        multimap.put(1, \"a\");\r\n        multimap.put(2, \"b\");\r\n        multimap.put(3, \"c\");\r\n        multimap.put(1, \"a2\");<\/pre>\n<p>There are of course immutable implementations as well: ImmutableListMultimap, ImmutableSetMultomap, etc.<\/p>\n<p>You can construct immutables either in line (up to 5 elements) or using a builder:<\/p>\n<pre class=\"brush:java\">Multimap multimap = ImmutableSetMultimap.of(1, \"a\", 2, \"b\", 3, \"c\", 1, \"a2\"); \r\nMultimap multimap = new ImmutableSetMultimap.Builder()\r\n        .put(1, \"a\")\r\n        .put(2, \"b\")\r\n        .put(3, \"c\")\r\n        .put(1, \"a2\")\r\n        .build();<\/pre>\n<p><strong>BiMap<\/strong><\/p>\n<p>BiMap is a map that have only unique values. Consider this:<\/p>\n<pre class=\"brush:java\">@Test(expected = IllegalArgumentException.class)\r\npublic void biMapShouldOnlyHaveUniqueValues() {\r\n BiMap biMap = HashBiMap.create();\r\n biMap.put(1, \"a\");\r\n biMap.put(2, \"b\");\r\n biMap.put(3, \"a\"); \/\/argh! an exception\r\n}<\/pre>\n<p>That allows you to inverse the map, so the values become key and the other way around:<\/p>\n<pre class=\"brush:java\">BiMap biMap = HashBiMap.create();\r\nbiMap.put(1, \"a\");\r\nbiMap.put(2, \"b\");\r\nbiMap.put(3, \"c\");\r\n\r\nBiMap invertedMap = biMap.inverse();<\/pre>\n<p>Not sure what I&#8217;d actually want to use it for.<\/p>\n<p><strong>Constraints<\/strong><\/p>\n<p>This allows you to add constraint checking on a collection, so that only values which pass the constraint may be added.<\/p>\n<p>Imagine we want a collections of users with first letter &#8216;r&#8217; in their logins.<\/p>\n<pre class=\"brush:java\">Constraint loginMustStartWithR = new Constraint() {\r\n    @Override\r\n    public User checkElement(User user) {\r\n        checkNotNull(user);\r\n\r\n        if(!user.login.startsWith(\"r\")) {\r\n            throw new IllegalArgumentException(\"GTFO, you are not Rrrrrrrrr\");\r\n        }\r\n\r\n        return user;\r\n    }\r\n};<\/pre>\n<p>And now for a test:<\/p>\n<pre class=\"brush:java\">@Test(expected = IllegalArgumentException.class)\r\npublic void shouldConstraintCollection() {\r\n \/\/given\r\n Collection users = newArrayList(new User(1L, \"john\", \"rambo\", \"rambo\"));\r\n Collection usersThatStartWithR = constrainedCollection(users, loginMustStartWithR);\r\n\r\n \/\/when\r\n usersThatStartWithR.add(new User(2L, \"arnold\", \"schwarz\", \"commando\"));\r\n}<\/pre>\n<p>You also get notNull constraint out of the box:<\/p>\n<pre class=\"brush:java\">\/\/notice it's not an IllegalArgumentException :( \r\n@Test(expected = NullPointerException.class)\r\npublic void notNullConstraintShouldWork() {\r\n \/\/given\r\n Collection users = newArrayList(1);\r\n Collection notNullCollection = constrainedCollection(users, notNull());\r\n\r\n \/\/when\r\n notNullCollection.add(null);\r\n}<\/pre>\n<p>Thing to remember: constraints are not checking the data already present in a collection.<\/p>\n<p><strong> Tables <\/strong><\/p>\n<p>Just as expected, a table is a collection with columns, rows and values. No more Map&gt; I guess. The usage is simple and you can transpose:<\/p>\n<pre class=\"brush:java\">Table table = HashBasedTable.create();\r\ntable.put(1, \"a\", \"1a\");\r\ntable.put(1, \"b\", \"1b\");\r\ntable.put(2, \"a\", \"2a\");\r\ntable.put(2, \"b\", \"2b\");\r\n\r\nTable transponedTable = Tables.transpose(table);<\/pre>\n<p>That&#8217;s all, folks. I didn&#8217;t present util.concurent, primitives, io and net packages, but you probably already know what to expect.<\/p>\n<\/div>\n<div class=\"blogger-post-footer\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blogger.googleusercontent.com\/tracker\/8795604888160975763-5491443573406127525?l=blog.solidcraft.eu\" alt=\"\" width=\"1\" height=\"1\" \/><\/div>\n","protected":false},"excerpt":{"rendered":"We have something called Weekly Technology Workshops at TouK, that is, every Friday at 16:00 somebody has a&hellip;\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[68],"class_list":{"0":"post-510","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-java"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/510","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=510"}],"version-history":[{"count":40,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/510\/revisions"}],"predecessor-version":[{"id":15606,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/510\/revisions\/15606"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=510"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=510"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=510"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}