Guava源码阅读计划:base.Splitter

策略模式(Strategy)

定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。在Splitter中就主要使用了这种模式.

主要方法

基础写法为:

Splitter.on('.').split("a,b,c");

第一部分构建

Splitter.on( )

有很多Splitter.on()方法 每个参数不同,但他们都在其中构造了Spliter对象.

WIKI 这里就体现了策略模式,不同的Splitter.on()可以相互替换

例如:

public static Splitter on(final String separator) {
    checkArgument(separator.length() != 0, "The separator may not be the empty string.");
    if (separator.length() == 1) {
      return Splitter.on(separator.charAt(0));
    }
    //返回Splitter对象
    return new Splitter(
        //构建Strategy接口,并进行实现
        new Strategy() {
          @Override
          public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {
            //接口方法的实现中又构建了SplittingIterator类
            return new SplittingIterator(splitter, toSplit) {
              @Override
              public int separatorStart(int start) {
                int separatorLength = separator.length();

                positions:
                for (int p = start, last = toSplit.length() - separatorLength; p <= last; p++) {
                  for (int i = 0; i < separatorLength; i++) {
                    if (toSplit.charAt(i + p) != separator.charAt(i)) {
                      continue positions;
                    }
                  }
                  return p;
                }
                return -1;
              }

              @Override
              public int separatorEnd(int separatorPosition) {
                return separatorPosition + separator.length();
              }
            };
          }
        });
  }

Splitter构造方法

//默认构造方法,传入的基本参数是Strategy接口
private Splitter(Strategy strategy) {
    this(strategy, false, CharMatcher.none(), Integer.MAX_VALUE);
}
//构造方法,包含Strategy,是否忽略空字符,是否引入CharMatcher作为分割符,分割结果集最大长度
private Splitter(Strategy strategy, boolean omitEmptyStrings, CharMatcher trimmer, int limit) {
    this.strategy = strategy;
    this.omitEmptyStrings = omitEmptyStrings;
    this.trimmer = trimmer;
    this.limit = limit;
}

Strategy 接口

private interface Strategy {
    //在接口中定义了一个方法 返回值是一个Iterator<String>
    Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
}

SplittingIterator类

在Strategy接口方法的实现中都是构建了SplittingIterator类

private abstract static class SplittingIterator extends AbstractIterator<String> {
    final CharSequence toSplit;
    final CharMatcher trimmer;
    final boolean omitEmptyStrings;

    /**
     * Returns the first index in {@code toSplit} at or after {@code start} that contains the
     * separator.
     */
    abstract int separatorStart(int start);

    /**
     * Returns the first index in {@code toSplit} after {@code separatorPosition} that does not
     * contain a separator. This method is only invoked after a call to {@code separatorStart}.
     */
    abstract int separatorEnd(int separatorPosition);

    int offset = 0;
    int limit;

    protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
      this.trimmer = splitter.trimmer;
      this.omitEmptyStrings = splitter.omitEmptyStrings;
      this.limit = splitter.limit;
      this.toSplit = toSplit;
    }
}

第二部分调用

split( )

调用split()方法进行切分

  public Iterable<String> split(final CharSequence sequence) {
    checkNotNull(sequence);

    return new Iterable<String>() {
      @Override
      public Iterator<String> iterator() {
        return splittingIterator(sequence);
      }

      @Override
      public String toString() {
        return Joiner.on(", ")
            .appendTo(new StringBuilder().append('['), this)
            .append(']')
            .toString();
      }
    };
  }

  private Iterator<String> splittingIterator(CharSequence sequence) {
    //调用第一部分构建好的接口方法
    return strategy.iterator(this, sequence);
  }

WIKI 接口方法返回了一个SplittingIterator对象 继承于 AbstractIterator<String>

到此为止没有进行任何拆分操作,最终得到的就是一个对于AbstractIterator类的实现

但怎样拆分呢?

//重写了AbstractIterator类的computeNext()方法
@Override
    protected String computeNext() {
      /*
       * The returned string will be from the end of the last match to the beginning of the next
       * one. nextStart is the start position of the returned substring, while offset is the place
       * to start looking for a separator.
       */
      int nextStart = offset;
      while (offset != -1) {
        int start = nextStart;
        int end;

        int separatorPosition = separatorStart(offset);
        if (separatorPosition == -1) {
          end = toSplit.length();
          offset = -1;
        } else {
          end = separatorPosition;
          offset = separatorEnd(separatorPosition);
        }
        if (offset == nextStart) {
          /*
           * This occurs when some pattern has an empty match, even if it doesn't match the empty
           * string -- for example, if it requires lookahead or the like. The offset must be
           * increased to look for separators beyond this point, without changing the start position
           * of the next returned substring -- so nextStart stays the same.
           */
          offset++;
          if (offset > toSplit.length()) {
            offset = -1;
          }
          continue;
        }

        while (start < end && trimmer.matches(toSplit.charAt(start))) {
          start++;
        }
        while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
          end--;
        }

        if (omitEmptyStrings && start == end) {
          // Don't include the (unused) separator in next split string.
          nextStart = offset;
          continue;
        }

        if (limit == 1) {
          // The limit has been reached, return the rest of the string as the
          // final item. This is tested after empty string removal so that
          // empty strings do not count towards the limit.
          end = toSplit.length();
          offset = -1;
          // Since we may have changed the end, we need to trim it again.
          while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
            end--;
          }
        } else {
          limit--;
        }

        return toSplit.subSequence(start, end).toString();
      }
      return endOfData();
    }
  }

WIKI 之后在进行遍历时调用computeNext()方法才真正进行拆分

splitToList()

这是其另一个实现 返回的是List

public List<String> splitToList(CharSequence sequence) {
    checkNotNull(sequence);

    Iterator<String> iterator = splittingIterator(sequence);
    List<String> result = new ArrayList<>();

    while (iterator.hasNext()) {
      result.add(iterator.next());
    }
    //返回的是只读类
    return Collections.unmodifiableList(result);
}

Map<String, String> split()

返回值为Map的方法

public Map<String, String> split(CharSequence sequence) {
      Map<String, String> map = new LinkedHashMap<>();
      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);
    }
}

第三部分额外的设定

还有很多条件可以选择 这些条件的返回值和on方法一样都是Splitter对象 等于对Splitter的值进行了设置 

 // 设置omitEmptyString属性而不是想象中的直接忽略,体现懒加载思想
 public Splitter omitEmptyStrings() {
     return new Splitter(strategy, true, trimmer, limit);
 }


 //限制拆分器返回的最大项数或者列表的最大长度
 public Splitter limit(int limit) {
     checkArgument(limit > 0, "must be greater than zero: %s", limit);
     return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
 } 


 //返回结果不带前缀和后缀空格
 public Splitter trimResults() {
     return trimResults(CharMatcher.whitespace());
 }


 // TODO(kevinb): throw if a trimmer was already specified!
 public Splitter trimResults(CharMatcher trimmer) {
     checkNotNull(trimmer);
     return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
 }

当然也有切分成map的情况 返回的是MapSplitter类对象,但其中属性还是两个Splitter对象 通过构成map的两个条件进行两次拆分

public static final class MapSplitter {
    private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";
    //两个Splitter
    private final Splitter outerSplitter;
    private final Splitter entrySplitter;

    private MapSplitter(Splitter outerSplitter, Splitter entrySplitter) {
      this.outerSplitter = outerSplitter; // only "this" is passed
      this.entrySplitter = checkNotNull(entrySplitter);
    }

  
    public Map<String, String> split(CharSequence sequence) {
      Map<String, String> map = new LinkedHashMap<>();
      //通过第一个Splitter进行第一次拆分
      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);
    }
  }

扩展

AbstractIterator类

这里的AbstractIterator类是com.google.common.base包下的 , 是com.google.common.collect.AbstractIterator的一个简写

/**
 * Note this class is a copy of {@link com.google.common.collect.AbstractIterator} (for dependency
 * reasons).
 */
@GwtCompatible
abstract class AbstractIterator<T> implements Iterator<T> {
  private State state = State.NOT_READY;

  protected AbstractIterator() {}

  private enum State {
    READY,
    NOT_READY,
    DONE,
    FAILED,
  }

  private @Nullable T next;

  //在splitter类中重写的方法
  protected abstract T computeNext();

  @CanIgnoreReturnValue
  protected final @Nullable T endOfData() {
    state = State.DONE;
    return null;
  }

  @Override
  public final boolean hasNext() {
    checkState(state != State.FAILED);
    switch (state) {
      case READY:
        return true;
      case DONE:
        return false;
      default:
    }
    return tryToComputeNext();
  }

  private boolean tryToComputeNext() {
    state = State.FAILED; // temporary pessimism
    next = computeNext();
    if (state != State.DONE) {
      state = State.READY;
      return true;
    }
    return false;
  }

  @Override
  public final T next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    state = State.NOT_READY;
    T result = next;
    next = null;
    return result;
  }

  @Override
  public final void remove() {
    throw new UnsupportedOperationException();
  }
}

猜你喜欢

转载自blog.csdn.net/qq_30054997/article/details/81276842