Guava源码学习笔记

来源:互联网 发布:手机版打字软件 编辑:程序博客网 时间:2024/05/16 17:51

Why Guava?

学习和使用Guava可以使自己的代码变得更加优雅、简洁。
Guava is the open-sourced version of Google's core Java libraries: the core utilities that Googlers use every day in their code.
The Guava utilities have been carefully designed, tested, optimized and used in production at Google.
Know and use the libraries, don’t reinvent the wheel.

Objects类

Objects类有几个比较不错的方法,toString、hashCode和equals方法测试类@Dataclass Person{  private String name;  private int sex;  private int age;  public Person(String name,int sex,int age) {    this.name = name;    this.sex = sex;    this.age = age;  }  @Override  public String toString() {    return MoreObjects.toStringHelper(this)            .omitNullValues()            .add("name", this.getName())            .add("sex", this.getSex())            .add("age", this.getAge())            .toString();  }} 1.重写toString方法,减少if else判空逻辑public void testToString() {   Person zhangsan = new Person(null, 1, 28);   String nameStr = MoreObjects.toStringHelper(zhangsan).omitNullValues()         .add("name", zhangsan.getName()).add("sex", zhangsan.getSex())         .add("age", zhangsan.getAge()).toString();   assetTrue(nameStr.equals("Person{sex=1, age=28}"));}2.获取hash值,null也可以当成数据项public void testObjectsHashCode() {   int hashCode1 = Objects.hashCode("sting", "tony", null, "vincent");   int hashCode2 = Objects.hashCode("sting", "tony", "vincent", null);   assertTrue(hashCode1 != hashCode2);}3.比较对象,可以为空,减少判空逻辑public void testObjectsEquals() {  assertTrue(Objects.equal(null, null));  assertTrue(Objects.equal("sting", "sting"));  assertTrue(!Objects.equal(null, "test"));  //assertTrue(Objects.equal("stings", "sting"));}


排序的实现和改进

Person person1 = new Person("zhangsan", 1, 25);Person person2 = new Person("lisi", 0, 30);Person person3 = new Person(null, 1, 25);Person person4 = null;List<Person> persons = Lists      .newArrayList(person1, person2, person3, person4);public void testOrderingWithComparisonChain() {   assertTrue(persons.toString().equals("[Person{name=zhangsan, sex=1, age=25}, Person{name=lisi, sex=0, age=30}, Person{sex=1, age=25}, null]"));   System.out.println(persons.toString());   Ordering<Person> personOrdering = new Ordering<Person>() {      @Override      public int compare(Person p1, Person p2) {         return ComparisonChain.start().compare(p1.getAge(), p2.getAge())               .compare(p1.getName(), p2.getName())               .compare(p1.getSex(), p2.getSex()).result();      }   }.nullsFirst();   Collections.sort(persons, personOrdering);   System.out.println(persons.toString());   //Collections.sort(persons, personOrdering.reverse());}public void testOrderingWithComparator() {   System.out.println(persons.toString());   Collections.sort(persons, new Comparator<Person>() {      public int compare(Person p1, Person p2) {         return ComparisonChain.start().compare(p1.getAge(), p2.getAge())               .compare(p1.getName(), p2.getName())               .compare(p1.getSex(), p2.getSex()).result();      }   });   System.out.println(persons.toString());}

CharMatcher

CharMatcher内部的大量实现BREAKING_WHITESPACE:用于匹配所有的可换行的空白符,如\t,\n,\f,\rWHITESPACE:用于匹配所有空白字符ASCII:用于匹配ASCII字符DIGIT:匹配ASCII数字JAVA_DIGIT:匹配unicode数字JAVA_LETTER:匹配字母(含中文)JAVA_LETTER_OR_DIGIT:匹配字母(含中文)或数字JAVA_UPPER_CASE:匹配所有大写字符JAVA_LOWER_CASE:匹配所有小写字符ANY:用于匹配任意字符NONE:不匹配所有字符CharMatcher提供的工厂方法is(final char match):返回匹配指定字符的MatcherisNot(final char match):返回不匹配指定字符的MatcheranyOf(final CharSequence sequence):返回能够匹配sequence中任一字符的MatchernoneOf(CharSequence sequence):返回能够过滤sequence中任一字符的MatcherinRange(final char startInclusive, final char endInclusive):返回匹配范围内任意字符的MatcherforPredicate(final Predicate<? super Character> predicate):返回使用Predicate的apply()判断匹配的Matchernegate():返回与当前Matcher判断规则相反的Matcherand(CharMatcher other):返回与other匹配条件组合进行与运算的Matcheror(CharMatcher other):返回与other匹配条件组合进行或运算的Matcher对匹配字符的操作获取的符合规则的Matcher后,有以下常用方法来处理字符串并返回结果removeFrom(CharSequence sequence):去除匹配到的字符retainFrom(CharSequence sequence):筛选匹配到的字符replaceFrom(CharSequence sequence, char replacement):使用指定字符替换匹配到的字符replaceFrom(CharSequence sequence, CharSequence replacement):使用指定字符替换匹配到的字符trimFrom(CharSequence sequence):去除首尾匹配到的字符trimLeadingFrom(CharSequence sequence):去除首部匹配到的字符trimTrailingFrom(CharSequence sequence):去除尾部匹配到的字符collapseFrom(CharSequence sequence, char replacement):将匹配到的字符组(多个字符)替换成指定字符trimAndCollapseFrom(CharSequence sequence, char replacement):去除首尾空格后进行字符替换判定型方法matchesAnyOf(CharSequence sequence):如果sequence中任一字符匹配,返回truematchesAllOf(CharSequence sequence):如果sequence中所有字符都匹配,返回truematchesNoneOf(CharSequence sequence):如果sequence中所有字符都不匹配,返回true获取字符索引的方法indexIn(CharSequence sequence):返回匹配到的第一个字符的索引indexIn(CharSequence sequence, int start):返回从指定索引开始,匹配到的第一个字符的索引lastIndexIn(CharSequence sequence):返回匹配到的最后一个字符的索引countIn(CharSequence sequence):返回匹配到的字符数量 @Testpublic void testAnyOf() {   assertTrue(CharMatcher.anyOf("gZ").matchesAnyOf("anything"));}@Testpublic void testNoneOf() {   assertTrue(CharMatcher.noneOf("xZ").matchesAnyOf("anything"));}@Testpublic void testMatchAny() {   assertTrue(CharMatcher.ANY.matchesAllOf("anything"));}@Testpublic void testMatchAllOf() {   assertTrue(CharMatcher.BREAKING_WHITESPACE.matchesAllOf("\r\n\r\n"));}@Testpublic void testMatchDigits() {   assertTrue(CharMatcher.JAVA_DIGIT.matchesAllOf("1231212"));}@Testpublic void testRetainFrom() {   assertTrue(CharMatcher.DIGIT.retainFrom("Hello 1234 567").equals("1234567"));}@Testpublic void testRetailFrom() {   System.out.println(CharMatcher.DIGIT.or(CharMatcher.WHITESPACE).retainFrom("Hel**lo 1234 567"));   assertTrue(CharMatcher.DIGIT.or(CharMatcher.WHITESPACE).retainFrom("Hel**lo 1234 567").equals(" 1234 567"));}@Testpublic void testCollapseFrom() {   assertTrue(CharMatcher.DIGIT.collapseFrom("Hello 1234 567", 'x').equals("Hello x x"));}@Testpublic void testReplaceFrom() {   assertTrue(CharMatcher.DIGIT.replaceFrom("Hello 1234 567", 'x').equals("Hello xxxx xxx"));}@Testpublic void testCountIn() {   assertTrue(CharMatcher.DIGIT.countIn("Hello 1234 567") == 7);}@Testpublic void testIndexIn() {   assertTrue(CharMatcher.WHITESPACE.indexIn("Hello 1234 567") == 5);}@Testpublic void testLastIndexIn() {   assertTrue(CharMatcher.WHITESPACE.lastIndexIn("Hello 1234 567") == 10);}@Testpublic void testRemoveFrom() {   assertTrue(CharMatcher.inRange('3', '6').removeFrom("Hello 1234 567").equals("Hello 12 7"));}@Testpublic void testInRangeNegate() {   assertTrue(CharMatcher.inRange('3', '6').negate().removeFrom("Hello 1234 567").equals("3456"));}b.部分源码public static CharMatcher anyOf(final CharSequence sequence) {  switch (sequence.length()) {    case 0:      return NONE;    case 1:      return is(sequence.charAt(0));    case 2:      final char match1 = sequence.charAt(0);      final char match2 = sequence.charAt(1);      return new CharMatcher() {        @Override public boolean matches(char c) {          return c == match1 || c == match2;        }        @Override public CharMatcher precomputed() {          return this;        }      };  }  final char[] chars = sequence.toString().toCharArray();  Arrays.sort(chars); // not worth collapsing duplicates  return new CharMatcher() {    @Override public boolean matches(char c) {      return Arrays.binarySearch(chars, c) >= 0;    }  };}public static final CharMatcher JAVA_DIGIT = new CharMatcher() {  @Override public boolean matches(char c) {    return Character.isDigit(c);  }};public static final CharMatcher JAVA_ISO_CONTROL =    inRange('\u0000', '\u001f').or(inRange('\u007f', '\u009f'));

使用Predicate实现集合过滤功能

//用来过滤符合条件的元素Person person1 = new Person("zhangsan", 1, 25);Person person2 = new Person("lisi", 0, 30);Person person3 = new Person(null, 1, 25);Person person4 = null;List<Person> persons = Lists      .newArrayList(person1, person2, person3, person4);public void testPredicte() {   Iterable<Person> personsIter = Iterables         .filter(persons, new Predicate<Person>() {            public boolean apply(Person input) {               return input != null && input.getAge() > 18;            }         });   System.out.println(personsIter.toString());   Collection<Person> filterCollection = Collections2         .filter(persons, new Predicate<Person>() {            public boolean apply(Person input) {               return input != null && input.getAge() > 18;            }         });   System.out.println(filterCollection.toString());}public void testPredicates() {   List<String> colors = Lists         .newArrayList("red", "blue", "green", "purple", "yellow",               "pink", "", null);   Iterable<String> colorIter = Iterables.filter(colors, Predicates         .and(Predicates.<String>notNull(),               Predicates.containsPattern("pu")));   System.out.println(colorIter.toString());}

使用Function实现集合转换功能

//将对象集合转换为字符串集合。public void testFunction() {   Collection<String> filterCollection = Collections2         .transform(persons, new Function<Person, String>() {            public String apply(Person person) {               return null == person ?                     "" :                     null == person.getName() ?                           "" :                           person.getName();            }         });   List<String> names = Lists.newArrayList(filterCollection);   System.out.println(names.toString());}//过滤空对象和空的对象字段,实现复函数类似的功能public void testFunctions() {   Function<Person, String> getNameFunction = new Function<Person, String>() {      public String apply(Person person) {         return null == person.getName() ? "" : person.getName();      }   };   Predicate<CharSequence> strFilter = Predicates.containsPattern("li");   ImmutableList<String> names = FluentIterable.from(persons)         .filter(Predicates.<Person>notNull()).transform(getNameFunction)         .filter(strFilter).toList();   System.out.println(names.toString());} 像Lists和Maps这类的Collection工具类给我们提供了转换的方法:topMap = Maps.transformValues(fromMap, function);toList = Lists.transform(fromList, function);public void testMapsTransformFromValues() {    Map<String, Integer> rmbNameMoneyMapper = ImmutableMap.of("zhangsan", 100, "lisi", 80, "wangwu", 40);    System.out.println(Joiner.on('|').withKeyValueSeparator(':').join(rmbNameMoneyMapper));    Map<String, Double> dolorNameMoneyMapper = Maps.transformValues(rmbNameMoneyMapper, new Function<Integer, Double>() {        public Double apply(Integer input) {            if(input == null) {                return -1.0;            }            return input / 6.67;        }    });    System.out.println(Joiner.on('|').withKeyValueSeparator(':').join(dolorNameMoneyMapper));}结果://zhangsan:100|lisi:80|wangwu:40//zhangsan:14.992503748125937|lisi:11.99400299850075|wangwu:5.997001499250375 public void testListsTransformFrom() {    List<Double> rmbMoneyList = Lists.newArrayList(100.9, 80.0, 40.0, 20.9);    System.out.println(Joiner.on(',').skipNulls().join(rmbMoneyList));    List<Double> dollarMoneyList = Lists.transform(rmbMoneyList, new Function<Double, Double>() {        public Double apply(Double input) {            return input / 6.67;        }    });    System.out.println(Joiner.on(',').skipNulls().join(dollarMoneyList));}结果://100.9,80.0,40.0,20.9//15.12743628185907,11.99400299850075,5.997001499250375,3.1334332833583205

使用Joinner拼接字符串

//测试Joinner类  public void testJoinner() {    List<String> colors = Lists.newArrayList("red", "blue", "green", "purple", "yellow", "pink", "", null);//    String colorStr = Joiner.on(',').useForNull("no color").skipNulls().join(colors);    String colorStr = Joiner.on(',').useForNull("no color").join(colors);    System.out.println(colorStr);  }  public void testMapJoinner() {    Map<String,String> cityDistMapper = ImmutableMap.of("海淀区", "北京", "朝阳区", "北京", "昌平区", "北京");    String cityDistMapperStr = Joiner.on("|").withKeyValueSeparator("-").join(cityDistMapper);    System.out.println(cityDistMapperStr);  }//Joinner部分源码  public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {    checkNotNull(appendable);    if (parts.hasNext()) {      appendable.append(toString(parts.next()));      while (parts.hasNext()) {        appendable.append(separator);        appendable.append(toString(parts.next()));      }    }    return appendable;  }//优雅避免,用自有的toString方法可方便进行useForNull,否则会出现s异常  @CheckReturnValue  public Joiner useForNull(final String nullText) {    checkNotNull(nullText);    return new Joiner(this) {      @Override      CharSequence toString(@Nullable Object part) {        return (part == null) ? nullText : Joiner.this.toString(part);      }      @Override      public Joiner useForNull(String nullText) {        throw new UnsupportedOperationException("already specified useForNull");      }      @Override      public Joiner skipNulls() {        throw new UnsupportedOperationException("already specified useForNull");      }    };  }  @CheckReturnValue  public Joiner skipNulls() {    return new Joiner(this) {      @Override      public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {        checkNotNull(appendable, "appendable");        checkNotNull(parts, "parts");        while (parts.hasNext()) {          Object part = parts.next();          if (part != null) {            appendable.append(Joiner.this.toString(part));            break;          }        }        while (parts.hasNext()) {          Object part = parts.next();          if (part != null) {            appendable.append(separator);            appendable.append(Joiner.this.toString(part));          }        }        return appendable;      }      @Override      public Joiner useForNull(String nullText) {        throw new UnsupportedOperationException("already specified skipNulls");      }      @Override      public MapJoiner withKeyValueSeparator(String kvs) {        throw new UnsupportedOperationException("can't use .skipNulls() with maps");      }    };  }

使用Splitter拆分字符串

//Splitter类测试代码public void testMapSppliter() {  Map<String,String> cityDistMapper = Maps.newHashMap();  String beijingDistricts = " 海淀区:北京|   朝阳区:北京| 东城区:北京 ||西城区:北京|昌平区:北京  |   |";  cityDistMapper.putAll(Splitter.on("|").omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(beijingDistricts));  System.out.println(cityDistMapper.entrySet().toString());}public void testSppliter() {  String colorStrs = "red,blue  ,green, purple, yellow ,pink,  ,   ,";  List<String> colors = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().trimResults().split(colorStrs));  System.out.println(colors.toString());//Splitter部分源码  @CheckReturnValue  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));    }    return new Splitter(        new Strategy() {          @Override          public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {            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();              }            };          }        });  }    @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();    }

MultiSet和MultiMap的使用场景

a.MultiMap的使用,主要用来统计public void testHashMultiMap() {   Multimap<String, String> multimap = HashMultimap.create();   String beijingDistricts = "海淀区| 海淀区 | 朝阳区|东城区 ||西城区|昌平区";   String shanghaiDistricts = "静安区 |徐汇区|   | 浦东区|普陀区|  |崇明区";   multimap.putAll("北京", Splitter.on('|').omitEmptyStrings().trimResults().split(beijingDistricts));   multimap.putAll("上海", Splitter.on('|').omitEmptyStrings().trimResults().split(shanghaiDistricts));   System.out.println(multimap.toString());   assertTrue(multimap.get("北京").toString().equals("[朝阳区, 西城区, 东城区, 海淀区, 昌平区]"));   multimap.remove("北京", "东城区");   assertTrue(multimap.get("北京").toString().equals("[朝阳区, 西城区, 海淀区, 昌平区]"));}public void testArrayListMultimap() {   Multimap<String, String> multimap = ArrayListMultimap.create();   String beijingDistricts = "海淀区| 海淀区 | 朝阳区|东城区 ||西城区|昌平区";   String shanghaiDistricts = "静安区 |徐汇区|   | 浦东区|普陀区|  |崇明区";   multimap.putAll("北京", Splitter.on('|').omitEmptyStrings().trimResults().split(beijingDistricts));   multimap.putAll("上海", Splitter.on('|').omitEmptyStrings().trimResults().split(shanghaiDistricts));   Map<String, Collection<String>> cityDistMapper = multimap.asMap();   System.out.println(multimap.toString());   assertTrue(multimap.get("北京").toString().equals("[海淀区, 海淀区, 朝阳区, 东城区, 西城区, 昌平区]"));   multimap.remove("北京", "东城区");   assertTrue(multimap.get("北京").toString().equals("[海淀区, 海淀区, 朝阳区, 西城区, 昌平区]"));}b.MultiSet的使用,主要用来计数public void testHashMultiSet() {   String colorStr = "red|blue|yellow |green| red|purple|red|yellow|blue |blue|blue|green||blue";   List<String> colorStrs = Lists.newArrayList(Splitter.on('|').omitEmptyStrings().trimResults().split(colorStr));   Multiset<String> countStrs = HashMultiset.create();   countStrs.addAll(colorStrs);   StringBuilder stringBuilder = new StringBuilder("");   for (String color : countStrs.elementSet()) {      stringBuilder.append(color + ":" + countStrs.count(color) + "|");   }   assertTrue(stringBuilder.toString().equals("red:3|purple:1|blue:5|green:2|yellow:2|"));}

几个常用工具类

1.lists和maps操作ImmutableList<String> of = ImmutableList.of("a", "b", "c", "d");ImmutableMap<String,String> map = ImmutableMap.of("key1", "value1", "key2", "value2");Lists.newArrayList(),Maps.newHashMap();2.比较数字int compare = Ints.compare(a, b);int compare = Doubles.compare(a,b);3.数组操作Ints.toArray();Ints.asList(numbers);boolean contains = Ints.contains(array, a);int indexOf = Ints.indexOf(array, a);int max = Ints.max(array);int min = Ints.min(array);int[] concat = Ints.concat(array, array2); 4.Iterables,Collections2Collections2的filter、transform方法Iterables的filter、transform等方法Iterables.all(list,predicateObject)5.使用Guava的选择和预判断使得代码更简洁,过多的if else return使代码看起来很不美观。public void doSomething( List<Object> list ) {  if( list == null ) {    throw new IllegalArgumentException( "List must not be null" );  }  if( list.isEmpty() ) {    throw new IllegalArgumentException( "List must not be empty" );  }  doSomethingMore( list );}使用Guava的预判断后的代码,参数有问题尽快失败。public void doSomething( List<Object> list ) {  checkArgument( list != null, "List must not be null" );  checkArgument( !list.isEmpty(), "List must not be empty" );  doSomethingMore( list );} 1).checkArgument(boolean) :功能描述:检查boolean是否为真。 用作方法中检查参数失败时抛出的异常类型: IllegalArgumentException2).checkNotNull(T):功能描述:检查value不为null, 直接返回value;失败时抛出的异常类型:NullPointerException3).checkState(boolean):功能描述:检查对象的一些状态,不依赖方法参数。 例如, Iterator可以用来next是否在remove之前被调用。失败时抛出的异常类型:IllegalStateException public void testCheckArgument() {   Preconditions.checkArgument(false);}public void testCheckArgumentWithMessage() {   Preconditions.checkArgument(false, "hello");}public void testCheckState_simple_success() {   Preconditions.checkState(true);}public void testCheckStateWithMessage() {   Preconditions.checkState(false, "checkState false");}private static final String NON_NULL_STRING = "hello world";public void testCheckNotNull_simple_success() {   String result = Preconditions.checkNotNull(NON_NULL_STRING);   assertSame(NON_NULL_STRING, result);}public void testCheckNotNull() {   Preconditions.checkNotNull(null);}public void testCheckNotNullWithMessage() {   String nullNameStr = "I'm null";   String result = Preconditions.checkNotNull(null, nullNameStr);}6.Strings nulltoEmpty(),emptyToNull(),isNullOrEmpty(),commonPrefix(),commonSuffix(),paddingStart(),paddingEnd(),repeat()这几个方法。public void testPadStart() {   assertEquals("-", Strings.padStart("", 1, '-'));   assertEquals("--", Strings.padStart("", 2, '-'));   assertEquals("-x", Strings.padStart("x", 2, '-'));   assertEquals("--x", Strings.padStart("x", 3, '-'));   assertEquals("-xx", Strings.padStart("xx", 3, '-'));}public void testRepeat() {   String input = "20";   assertEquals("", Strings.repeat(input, 0));   assertEquals("20", Strings.repeat(input, 1));   assertEquals("2020", Strings.repeat(input, 2));   assertEquals("202020", Strings.repeat(input, 3));} public void testCommonPrefix() {   assertEquals("", Strings.commonPrefix("", "abc"));   assertEquals("", Strings.commonPrefix("xyz", "abcxyz"));   assertEquals("a", Strings.commonPrefix("abc", "aaaaa"));   assertEquals("aa", Strings.commonPrefix("aa", "aaaaa"));} public static String repeat(String string, int count) {  checkNotNull(string); // eager for GWT.  if (count <= 1) {    checkArgument(count >= 0, "invalid count: %s", count);    return (count == 0) ? "" : string;  }  // IF YOU MODIFY THE CODE HERE, you must update StringsRepeatBenchmark  final int len = string.length();  final long longSize = (long) len * (long) count;  final int size = (int) longSize;  if (size != longSize) {    throw new ArrayIndexOutOfBoundsException("Required array size too large: " + longSize);  }  final char[] array = new char[size];  string.getChars(0, len, array, 0);  int n;  for (n = len; n < size - n; n <<= 1) {    System.arraycopy(array, 0, array, n, n);  }  System.arraycopy(array, 0, array, n, size - n);  return new String(array);}


0 0