Guava: Joiner & Splitter

1. Joiner

    Comparasion between traditional approach and Guava approach:

    @Test
    public void buildStringTest() {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	String str = buildString(data, ",");
	assertEquals("A,B,C,D,E,F", str);
    }

    public String buildString(List<String> data, String delimeter) {
	StringBuilder sb = new StringBuilder();
	for (String s : data) {
	    if (null != s) {
		sb.append(s).append(delimeter);
	    }
	}
	sb.setLength(sb.length() - delimeter.length());
	return sb.toString();
    }
    @Test
    public void joinTest() throws IOException {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	String str = Joiner.on(",").skipNulls().join(data);
	assertEquals("A,B,C,D,E,F", str);
    } 

   Note the need to remove the last delimeter that was appended to the very end of the string.

   Not very complicated, but it's still some boilerplate code that can be more easily handled by using the Joiner class.

 

2. Joiner usage

   1> Simple Usage

    @Test
    public void joinTest() throws IOException {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	String str = Joiner.on(",").skipNulls().join(data);
	logger.info(str);
	assertEquals("A,B,C,D,E,F", str);

	str = Joiner.on("|").useForNull("NULL").join(data);
	logger.info(str);
	assertEquals("A|B|C|NULL|D|E|F", str);

	StringBuilder sb = new StringBuilder("X|M|U|");
	Joiner.on("|").skipNulls().appendTo(sb, data);
	logger.info(sb.toString());
	assertEquals("X|M|U|A|B|C|D|E|F", sb.toString());

	FileWriter fw = new FileWriter(new File("src/test/resources/test.csv"));
	Joiner.on(",").useForNull(" ").appendTo(fw, data);
	fw.close();
    }
public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts);
appendTo can be used for any class that implements Appendable interface.

    2> Attention:

        1) Joiner instances are always immutable. The joiner configuration methods will always return a new Joiner, which you must use to get the desired semantics.

             This makes any Joiner thread safe, and usable as a static final constant.

    @Test
    public void joinTest() throws IOException {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	Joiner joiner = Joiner.on(",");
	joiner.skipNulls();
	String str = joiner.join(data);
	logger.info(str);
    }
    // NullPointerException will be thrown.

    @Test
    public void joinTest() throws IOException {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	Joiner joiner = Joiner.on(",");
	joiner = joiner.skipNulls();
	String str = joiner.join(data);
	logger.info(str);
    }
    // A,B,C,D,E,F
  public static Joiner on(String separator) {
    return new Joiner(separator);
  }

  public Joiner useForNull(final String nullText) {
    checkNotNull(nullText);
    return new Joiner(this) {...}
  }

  public Joiner skipNulls() {
    return new Joiner(this) {...}
  }

        2) The returned Joiner is slightly different from traditional Joiner.

    @Test
    public void joinTest() throws IOException {
	List<String> data = Lists.newArrayList("A", "B", "C", null, "D", "E",
		"F");
	Joiner joiner = Joiner.on(",");
	joiner = joiner.skipNulls().useForNull("NULL");
	String str = joiner.join(data);
	logger.info(str);
    }

    // UnsupportedOperationException will be thrown indicates that "already specified skipNulls"

          How to achieve that?

  public Joiner skipNulls() {
    return new Joiner(this) {
      @Override public Joiner useForNull(String nullText) {
        throw new UnsupportedOperationException("already specified skipNulls");
      }
    };
  }

  public Joiner useForNull(final String nullText) {
    return new Joiner(this) {
      @Override public Joiner useForNull(String nullText) {
        throw new UnsupportedOperationException("already specified useForNull");
      }

      @Override public Joiner skipNulls() {
        throw new UnsupportedOperationException("already specified useForNull");
      }
    };
  }

 

3. MapJoiner usage

    @Test
    public void joinTest() throws IOException {
	Map<String, String> data = Maps.newHashMap();
	data.put("Name", "Davy");
	data.put("Gender", "Male");
	data.put("Age", "24");
	Joiner joiner = Joiner.on(",");
	MapJoiner mapJoiner = joiner.withKeyValueSeparator("=");
	String str = mapJoiner.join(data);
	logger.info(str);
	assertEquals("Name=Davy,Age=24,Gender=Male", str);
        // Use "," as separator for entry, and  "=" as separator for key and value
    }

    Source code: 

    public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
        throws IOException {
      checkNotNull(appendable);
      if (parts.hasNext()) {
        Entry<?, ?> entry = parts.next();
        appendable.append(joiner.toString(entry.getKey()));
        appendable.append(keyValueSeparator);
        appendable.append(joiner.toString(entry.getValue()));
        while (parts.hasNext()) {
          appendable.append(joiner.separator);
          Entry<?, ?> e = parts.next();
          appendable.append(joiner.toString(e.getKey()));
          appendable.append(keyValueSeparator);
          appendable.append(joiner.toString(e.getValue()));
        }
      }
      return appendable;
    }

 

2. Splitter: 

    1> Comparasion between traditional approach and Guava approach:

    @Test
    public void splitTest() {
	String str = "Monday,Tuesday,,Thursday,Friday,,";
	String[] strs = str.split(",");
	String[] exp = new String[] { "Monday", "Tuesday", "", "Thursday",
		"Friday" };
	assertArrayEquals(exp, strs);
    }
    @Test
    public void splitTest() {
	String str = "Monday,Tuesday,,Thursday,Friday,,";
	List<String> strs = Splitter.on(',').splitToList(str);
	List<String> exp = Lists.newArrayList("Monday", "Tuesday", "",
		"Thursday", "Friday", "", "");
	assertEquals(exp, strs);
    }
    @Test
    public void splitTest() {
	String str = "Monday,Tuesday,,Thursday,Friday,,";
	List<String> strs = Splitter.on(',').omitEmptyStrings()
		.splitToList(str);
	List<String> exp = Lists.newArrayList("Monday", "Tuesday", "Thursday",
		"Friday");
	assertEquals(exp, strs);
    }
    @Test
    public void splitTest() {
	String str = "Monday, Tuesday, , Thursday, Friday, , ";
	List<String> strs = Splitter.on(',').omitEmptyStrings().trimResults()
		.splitToList(str);
	List<String> exp = Lists.newArrayList("Monday", "Tuesday", "Thursday",
		"Friday");
	assertEquals(exp, strs);
    }
    @Test
    public void splitTest() {
	String str = "Monday, Tuesday, , Thursday, Friday, , ";
	List<String> strs = Splitter.on(',').trimResults().splitToList(str);
	List<String> exp = Lists.newArrayList("Monday", "Tuesday", "",
		"Thursday", "Friday", "", "");
	assertEquals(exp, strs);
    }

    We can see that using Guava Splitter, the result is more reasonable and comprehensive.

    2> MapSplitter

    @Test
    public void splitTest() {
	String str = "Name=Davy;Age=24;Gender=Male";
	Map<String, String> expectedMap = Maps.newLinkedHashMap();
	expectedMap.put("Name", "Davy");
	expectedMap.put("Age", "24");
	expectedMap.put("Gender", "Male");
	Map<String, String> generatedMap = Splitter.on(';')
		.withKeyValueSeparator("=").split(str);
	assertEquals(expectedMap, generatedMap);
    }
    public Map<String, String> split(CharSequence sequence) {
      Map<String, String> map = new LinkedHashMap<String, String>();
      for (String entry : outerSplitter.split(sequence)) {
        Iterator<String> entryFields = entrySplitter.splittingIterator(entry);

        checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
        String key = entryFields.next();
        checkArgument(!map.containsKey(key), "Duplicate key [%s] found.", key);

        checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
        String value = entryFields.next();
        map.put(key, value);

        checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
      }
      return Collections.unmodifiableMap(map);
    }
  }

    We can see from the source code that we are using ";" for outterSplitter and "=" for entrySplitter.

    @Test
    public void splitTest() {
	String str = "Name = Davy; Age = 24; Gender = Male";
	Map<String, String> expectedMap = Maps.newLinkedHashMap();
	expectedMap.put("Name", "Davy");
	expectedMap.put("Age", "24");
	expectedMap.put("Gender", "Male");
	Map<String, String> generatedMap = Splitter.on(';').trimResults()
		.withKeyValueSeparator(Splitter.on("=").trimResults())
		.split(str);
	assertEquals(expectedMap, generatedMap);
    }

    In the example above, we are using ";" as outterSplitter and thus trimResults to "Name = Davy", "Age = 24", "Gender = Male"

    And we are using "=" as entrySplitter and thus trimResults to "Name", "Davy"...

 

3. Preconditions

    The Preconditions class is a collection of static methods used to verify the state of our code.

    public void setName(String name) {
	if (null == name) {
	    throw new IllegalArgumentException("name cannot be null");
	}
    }
    public void setName(String name) {
        Preconditions.checkNotNull(name);
    }
    public void setName(String name) {
        Preconditions.checkArgument(null != name && !"".equals(name.trim()));
    }
    @Test
    public void conditionsTest() {
	String[] data = new String[] { "A", "B", "C", "D" };
	getValue(data, 4);
    }
    private void getValue(String[] data, int i) {
        Preconditions.checkElementIndex(data.length, i);
    }

 

Reference Links:

1> "Getting Started with Google Guava" -Bill Bejeck

你可能感兴趣的:(guava,Joiner,Splitter)