2010-09-22 66 views
39

是否有一种将基元数组转换为相应容器对象数组的优雅方法 - 例如,将byte[]转换为Byte[]?或者我坚持循环并手动完成它?将原始数组转换为Java中的容器数组

是的,for循环并不完全困难。只是有点丑。

+0

和周围的其他方式:http://stackoverflow.com/questions/564392/converting-an-array-of-objects-to-an-array-of-their-primitive-types – 2015-03-13 07:38:36

回答

63

阿帕奇百科全书

Apache Commons/Lang具有类ArrayUtils定义这些方法。

  • 称为toObject(...) 所有方法从基本数组转换为包装器阵列
  • 所有称为toPrimitive(...)从包装对象数组转换 到 基本数组

实施例:

final int[]  original  = new int[] { 1, 2, 3 }; 
final Integer[] wrappers  = ArrayUtils.toObject(original); 
final int[]  primitivesAgain = ArrayUtils.toPrimitive(wrappers); 
assert Arrays.equals(original, primitivesAgain); 

番石榴

,然后我就会说,包裹元的阵列是不是很有用,所以你可能想看看Guava相反,它提供了所有的数字类型,由基本数组支持的列表:

List<Integer> intList = Ints.asList(1,2,3,4,5); 
List<Long> longList = Longs.asList(1L,2L,3L,4L,5L); 
// etc. 

的好处想想这些阵列支持的藏品是

  1. 他们生活意见(即对阵列的更新改变了列表,反之亦然)
  2. 仅在需要时才创建包装器对象(例如,迭代列表)

时看到:Guava Explained/Primitives


的Java 8

在另一方面,与Java 8 lambda表达式/流,可以使这些转换,而无需使用非常简单外部库:

int[] primitiveInts = {1, 2, 3}; 
Integer[] wrappedInts = Arrays.stream(primitiveInts) 
           .boxed() 
           .toArray(Integer[]::new); 
int[] unwrappedInts = Arrays.stream(wrappedInts) 
          .mapToInt(Integer::intValue) 
          .toArray(); 
assertArrayEquals(primitiveInts, unwrappedInts); 

double[] primitiveDoubles = {1.1d, 2.2d, 3.3d}; 
Double[] wrappedDoubles = Arrays.stream(primitiveDoubles) 
           .boxed() 
           .toArray(Double[]::new); 
double[] unwrappedDoubles = Arrays.stream(wrappedDoubles) 
            .mapToDouble(Double::doubleValue) 
            .toArray(); 

assertArrayEquals(primitiveDoubles, unwrappedDoubles, 0.0001d); 

请注意,Java 8版本适用intlongdouble,但不是byte,为Arrays.stream()只对int[]long[]double[]或通用对象T[]重载。

+1

Arrays.stream(Byte [])'是否有重载? – 3yanlis1bos 2017-05-24 20:27:15

+1

Java 8解决方案对发布的问题不起作用。 'Arrays.stream()'没有超出'byte []' – Peri461 2017-11-06 04:19:26

+0

@ Peri461的值。我今年只是添加了Java 8的东西,其余的答案比Java 8老几年 – 2017-11-06 19:48:20

7

你必须遍历你的数组。


@seanizer答案后更新:

基本上toObject(byte[] array)方法会为你做的循环:

public static Byte[] toObject(byte[] array) { 
    if (array == null) { 
     return null; 
    } else if (array.length == 0) { 
     return EMPTY_BYTE_OBJECT_ARRAY; 
    } 
    final Byte[] result = new Byte[array.length]; 
    for (int i = 0; i < array.length; i++) { 
     result[i] = new Byte(array[i]); 
    } 
    return result; 
} 

除非你真的会使用公共郎lib中,你应该简单地重用这种方法并避免无用的依赖(恕我直言)。

+4

我不认为依赖是无用的。该StringUtils。*方法是一个巨大的节省时间。ArrayUtils是一个奖金:-) – 2010-09-22 14:46:11

+4

@seanizer我完全同意,Commons lang真的很有用,我只是说只有一个静态方法对它有依赖关系。 – 2010-09-22 14:49:31

+0

@colin那么我同意 – 2010-09-22 14:54:23

7

只是为了提出一种替代,与Guava可以使用的原语类型实用程序,如BytesInts一个创建包装类型的List

byte[] bytes = ... 
List<Byte> byteList = Bytes.asList(bytes); 

而不是通过循环和将每个byte ,这些方法实际上创建了一个由给定数组支持的列表。如果你真的需要一个Byte[],这显然不直接给你你需要(尽管你可以得到它当然使用.toArray(new Byte[bytes.length]))什么。虽然集合远远优于数组,但是在可能的情况下应该首选。

+1

我同意。集合规则,数组吸引,番石榴规则(+1) – 2010-09-23 06:14:48

1

加入a good answer后,这里是一个可怕的答案,只是它的挫折感。关于Apache Commons ArrayUtils类的麻烦是,有8种版本的相同方法,仅适用于不同的输入类型。我找到了一种通用的方法来将任何原始数组转换为其包装等效物(因此将8个不同的版本减少为1)。这是代码:

public final class ArraysUtils { 

    private ArraysUtils() { } 

    @SuppressWarnings("unchecked") 
    public static Object[] toWrapperArray(final Object primitiveArray) { 
     Objects.requireNonNull(primitiveArray, "Null values are not supported"); 
     final Class<?> cls = primitiveArray.getClass(); 
     if (!cls.isArray() || !cls.getComponentType().isPrimitive()) { 
      throw new IllegalArgumentException(
        "Only primitive arrays are supported"); 
     } 
     final int length = Array.getLength(primitiveArray); 
     if (length == 0) { 
      throw new IllegalArgumentException(
        "Only non-empty primitive arrays are supported"); 
     } 
     final Object first = Array.get(primitiveArray, 0); 
     Object[] arr = (Object[]) Array.newInstance(first.getClass(), length); 
     arr[0] = first; 
     for (int i = 1; i < length; i++) { 
      arr[i] = Array.get(primitiveArray, i); 
     } 
     return arr; 
    } 

} 

正如你可以看到,有相当多的错方法:

  • 有没有编译时的安全性,方法的参数可以是任何东西,只有方法本身将验证运行时参数,严格拒绝空值,空数组,非数组和非原始数组
  • 需要反射
  • 如果不在基本类和包装类之间保留某种查找表,就没有办法支持空数组秒。

不管怎么说,这是一个测试套件所有必要的情况下,使用JUnit的Parameterized亚军:

@RunWith(Parameterized.class) 
public class ArraysUtilsTest { 
    @Parameterized.Parameters(name = "{0}") 
    public static List<Object> parameters() { 
     return Arrays.asList(
       success(new int[]{1, 2, 3}, new Integer[]{1, 2, 3}), 
       success(new long[]{1L, 2L, 3L}, new Long[]{1L, 2L, 3L}), 
       success(new byte[]{1, 2, 3}, new Byte[]{1, 2, 3}), 
       success(new short[]{1, 2, 3}, new Short[]{1, 2, 3}), 
       success(new char[]{'a', 'b', 'c'}, new Character[]{'a', 'b', 'c'}), 
       success(new double[]{1.0, 2.0, 3.0}, new Double[]{1.0, 2.0, 3.0}), 
       success(new float[]{1.0f, 2.0f, 3.0f}, new Float[]{1.0f, 2.0f, 3.0f}), 
       success(new boolean[]{true, false, true}, new Boolean[]{true, false, true}), 
       failure(null, NullPointerException.class, "Null"), 
       failure("foo", IllegalArgumentException.class, "Non-array"), 
       failure(new String[]{"foo", "bar"}, IllegalArgumentException.class, "Non-primitive array"), 
       failure(new int[0], IllegalArgumentException.class, "Empty array") 


      ); 
    } 

    private static Object[] success(Object primitiveArray, Object[] wrapperArray) { 
     return new Object[]{ 
       primitiveArray.getClass().getCanonicalName(), 
       primitiveArray, null, wrapperArray}; 
    } 

    private static Object[] failure(Object input, 
            Class<? extends RuntimeException> exceptionClass, 
            String description) { 
     return new Object[]{description, input, exceptionClass, null}; 
    } 

    @Parameterized.Parameter(0) 
    // only used to generate the test name 
    public String scenarioName; 

    @Parameterized.Parameter(1) 
    public Object inputArray; 

    @Parameterized.Parameter(2) 
    public Class<? extends RuntimeException> expectedException; 

    @Parameterized.Parameter(3) 
    public Object[] expectedOutput; 


    @Test 
    public void runScenario() { 
     try { 
      Object[] wrapped = ArraysUtils.toWrapperArray(inputArray); 
      if (expectedException != null) { 
       fail(String.format("Expected %s to be thrown", 
            expectedException.getSimpleName())); 
      } 
      assertThat(wrapped, is(equalTo(expectedOutput))); 
     } catch (RuntimeException e) { 
      if (expectedException == null) { 
       fail(String.format("Expected no exception but got %swith message '%s'", 
            e.getClass().getSimpleName(), 
            e.getMessage())); 
      } 
      if(!expectedException.isInstance(e)){ 
       fail(String.format("Expected %s but got %s with message '%s'", 
            expectedException.getSimpleName(), 
            e.getClass().getSimpleName(), 
            e.getMessage())); 
      } 
     } 
    } 


} 
2

这里是做不使用任何外部库的简短通用的方法,它适用于所有原语:

import static java.lang.reflect.Array.*; 
import java.util.Arrays; 

public class DeepConverter { 

    public static void main(String args[]) {   
    long L1[][][] = {{{1,2},{3,4}}, {{5,6}}, {{7}},{{8,9,10,11}}}; 
    L1 = new long[2][0][7]; 
    Long L2[][] = (Long[][])box(L1); 
    System.out.println(Arrays.deepToString(L2));   
    } 

    public static Object box(Object src) {   
    try { 
     int length = src.getClass().isArray() ? getLength(src) : 0;   
     if(length == 0) 
      return src;   
     Object dest = newInstance(typeCastTo(wrap(get(src, 0))), length);   
     for(int i = 0; i < length; i++) 
      set(dest, i, wrap(get(src, i)));   
     return dest; 

    } catch(Exception e) { 
     throw new ClassCastException("Object to wrap must be an array of primitives with no 0 dimensions"); 
    } 
    } 

    private static Class<?> typeCastTo(Object obj) { 
    Class<?> type = obj.getClass(); 
    if(type.equals(boolean.class)) return Boolean.class; 
    if(type.equals(byte.class)) return Byte.class; 
    if(type.equals(char.class)) return Character.class; 
    if(type.equals(double.class)) return Double.class; 
    if(type.equals(float.class)) return Float.class; 
    if(type.equals(int.class)) return Integer.class; 
    if(type.equals(long.class)) return Long.class; 
    if(type.equals(short.class)) return Short.class; 
    if(type.equals(void.class)) return Void.class;   
    return type; 
    } 
}