Утилиты для массива


Не смотря на свою полезность, класс Arrays с недоделанной функциональностью. Например, было бы прекрасно иметь возможность легкой распечатки элементов массива без дополнительного регулярного ручного кодирования циклов loop. И как вы увидите, метод fill( ) просто принимает единственное значение и помещает его в массив, так что если вы хотите, например, заполнить массив случайно сгенерированными числами, метод filд( ) не поможет.

Таким образом, имеет смысл дополнить класс Arrays некоторыми дополнительными утилитами, которые будут помещены в пакет com.bruceeckel.util для удобства. В ней распечатывается массив любого типа и заполняется массив значениями или объектами, которые создаются генератором, который вы определяете.

Поскольку код должен быть создан для каждого примитивного типа так же как и для Object, то здесь будет много дублирующего кода. [14] Например, интерфейс "генератора" требуется для каждого типа, поскольку возвращаемый тип метода next( ) должен отличатся в каждом случае:

package com.bruceeckel.util;

//: com:bruceeckel:util:Generator.java
public interface Generator { Object next(); } // /:~

// : com:bruceeckel:util:BooleanGenerator.java
public interface BooleanGenerator { boolean next(); } // /:~

// : com:bruceeckel:util:ByteGenerator.java
public interface ByteGenerator { byte next(); } // /:~

// : com:bruceeckel:util:CharGenerator.java
public interface CharGenerator { char next(); } // /:~

// : com:bruceeckel:util:ShortGenerator.java
public interface ShortGenerator { short next(); } // /:~

// : com:bruceeckel:util:IntGenerator.java
public interface IntGenerator { int next(); } // /:~

// : com:bruceeckel:util:LongGenerator.java
public interface LongGenerator { long next(); } // /:~

// : com:bruceeckel:util:FloatGenerator.java
public interface FloatGenerator { float next(); } // /:~

// : com:bruceeckel:util:DoubleGenerator.java
public interface DoubleGenerator { double next(); } // /:~

Arrays2 содержит вариант метода toString( ), перегруженный для каждого типа. Эти методы позволяют вам легко распечатать массыв. Код toString( ) вводит использование объекта StringBuffer вместо String. Это уклон в сторону эффективности. Когда вы собираете строку в методе, которая может вызываться очень много раз, благоразумнее использовать более эффективный класс StringBuffer вместо более последовательных операций класса String. В этом примере StringBuffer создается с начальным значением, а String используются для добавления. В итоге, result приводится к типу String, так как это возвращаемое значение:

//: com:bruceeckel:util:Arrays2.java
// A supplement to java.util.Arrays, to provide additional
// useful functionality when working with arrays. Allows
// any array to be converted to a String, and to be filled
// via a user-defined "generator" object.
package com.bruceeckel.util;

import java.util.*;

public class Arrays2 {
  
public static String toString(boolean[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(byte[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(char[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(short[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(int[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(long[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(float[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
public static String toString(double[] a) {
     
StringBuffer result = new StringBuffer("[");
     
for (int i = 0; i < a.length; i++) {
        
result.append(a[i]);
        
if (i < a.length - 1)
           
result.append(", ");
     
}
     
result.append("]");
     
return result.toString();
  
}
  
  
// Fill an array using a generator:
  
public static void fill(Object[] a, Generator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(Object[] a, int from, int to, Generator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(boolean[] a, BooleanGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(boolean[] a, int from, int to, BooleanGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(byte[] a, ByteGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(byte[] a, int from, int to, ByteGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(char[] a, CharGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(char[] a, int from, int to, CharGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(short[] a, ShortGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(short[] a, int from, int to, ShortGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(int[] a, IntGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(int[] a, int from, int to, IntGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(long[] a, LongGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(long[] a, int from, int to, LongGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(float[] a, FloatGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(float[] a, int from, int to, FloatGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
public static void fill(double[] a, DoubleGenerator gen) {
     
fill(a, 0, a.length, gen);
  
}
  
  
public static void fill(double[] a, int from, int to, DoubleGenerator gen) {
     
for (int i = from; i < to; i++)
        
a[i] = gen.next();
  
}
  
  
private static Random r = new Random();
  
  
public static class RandBooleanGenerator implements BooleanGenerator {
     
public boolean next() {
        
return r.nextBoolean();
     
}
   }
  
  
public static class RandByteGenerator implements ByteGenerator {
     
public byte next() {
        
return (byte) r.nextInt();
     
}
   }
  
  
private static String ssource = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  
private static char[] src = ssource.toCharArray();
  
  
public static class RandCharGenerator implements CharGenerator {
     
public char next() {
        
return src[r.nextInt(src.length)];
     
}
   }
  
  
public static class RandStringGenerator implements Generator {
     
private int len;
     
private RandCharGenerator cg = new RandCharGenerator();
     
     
public RandStringGenerator(int length) {
        
len = length;
     
}
     
     
public Object next() {
        
char[] buf = new char[len];
        
for (int i = 0; i < len; i++)
           
buf[i] = cg.next();
        
return new String(buf);
     
}
   }
  
  
public static class RandShortGenerator implements ShortGenerator {
     
public short next() {
        
return (short) r.nextInt();
     
}
   }
  
  
public static class RandIntGenerator implements IntGenerator {
     
private int mod = 10000;
     
     
public RandIntGenerator() {
      }
     
     
public RandIntGenerator(int modulo) {
        
mod = modulo;
     
}
     
     
public int next() {
        
return r.nextInt(mod);
     
}
   }
  
  
public static class RandLongGenerator implements LongGenerator {
     
public long next() {
        
return r.nextLong();
     
}
   }
  
  
public static class RandFloatGenerator implements FloatGenerator {
     
public float next() {
        
return r.nextFloat();
     
}
   }
  
  
public static class RandDoubleGenerator implements DoubleGenerator {
     
public double next() {
        
return r.nextDouble();
     
}
   }
}
// /:~

Для заполнения массива элементов с использованием генератора метод fill( ) принимает ссылку на соответствующий интерфейс генератора, в котором есть метод next( ), который каким-то образом воспроизводит объект правильного типа (в зависимости от того, какой интерфейс реализован). Метод fill( ) просто вызывает метод next( ) до тех пор, пока необходимый диапазон не будет заполнен. Теперь вы можете создать любой генератор путем реализации соответствующего интерфейса и использовать генератор в методе fill( ).

Генераторы случайных чисел полезны при тестировании, так что набор внутренних классов, созданных для реализации всех интерфейсов примитивных генераторов наряду с генератором для типа String, представляющего Object. Вы можете видеть, что RandStringGenerator использует RandCharGenerator для заполнения массива символов, которые затем превращаются в Striung. Размер массива определяется аргументом конструктора.

Для генерации чисел, которые не являются большими числами, RandIntGenerator берет остаток от деления на 10 000, но перегруженный конструктор позволяет вам выбирать меньшие значения.

[1] Эта издевательская ссылка связана с событиями в Китае после смерти Мао-Дзе Дуна, когда четыре человека, включая вдову Мао, сделали игру с властью и были демонизированы Китайской Коммунистической Партией под этим именем.

[2] От Mark Johnson.

[3] Предупреждаем: пример из C++.

[4] Бесплатная публикация по email. Смотрите www.BruceEckel.com, чтобы подписаться.

[5] Получено по email от Kevlin Henney.

[6] Shalloway, Design Patterns Explained, and Alexandrescu, Advanced C++ Design (??)

[7] В языке Python все функции уже являются объектами, поэтому шаблон Команды часто является избыточным.

[8] Страница 235.

[9] Оригинальная версия была названа JPython, но проект изменился и имя было изменено для явного указания отличия новой версии.

[10] Измените установку в регистре python.security.respectJavaAccessibility = true в false, чтобы сделать тестирование более мощным, поскольку это позволит вам тестировать скрипт с использованием *всех* методов, даже приватных и пакетного уровня доступа.

[11] Ни одна мышь не погибла при создании этого примера.

[12] Addison-Wesley, 1999.

[13] Это решения создано Jaroslav Tulach в дизайне проектирования, который я давал в Праге.

[14] Программисты на C++ заметят, как много кода может быть сжато при использовании аргументов по умолчанию и шаблонов. Программисты на Python заметят, что вся эта библиотека будет громоздкой и ненужной в этом языке.