2014-12-08 2 views
2

Мне нужно положить массив в объект JSON с помощью Google Guava.Array to JSON с Guava

JSONObject jsonObject = new JSONObject(); 
State[] states = getStates(); 
for(State currentState: states) { 
    jsonObject.put(String.valueOf(currentState.getId()), currentState.getName()); 
} 

Я пробовал использовать Iterables.transform, но это не работает.

Iterables.transform(states, new Function<State, JSONObject>() { 
    @Override 
    public JSONObject apply(State currentState) { 
    return jsonObject.put(String.valueOf(currentState.getId()), currentState.getName()); 
    } 
}); 

Что случилось?

+1

Является ли возвращаемое значение 'jsonObject.put'' 'JSONObject', как требуется функцией? Кроме того, что случилось с циклом? 'Iterables.transform' создает' Iterable', а не 'Map' (или' JSONObject'), поэтому, вероятно, это неправильный инструмент для задания. –

+0

Укажите сообщение об ошибке. –

ответ

1

Вам действительно нужно, чтобы это было реализовано таким образом? Это не то, для чего предназначен Iterables.transform().

Во-первых, Iterables.transform() не принимает массивы в качестве своего первого параметра. Вы должны обернуть свой states в любой номер Iterable. Самый простой и лучший способ - Arrays.asList(states). Во-вторых, идея метода Iterables.transform() заключается в создании преобразованной последовательности с использованием функции отображения, а не только для повторения. Я бы не рекомендовал следующее, но вы можете сделать свой Function параметризированным как <State, Void> и вернуть null для имитации простой для каждой семантики. В-третьих, вы должны перебирать результат Iterables.transform, потому что эта функция ленива и ничего не делает, пока вы не начнете итерацию с нетерпением for или чего-то еще нетерпеливого. В-четвертых, до тех пор, пока ваш вновь созданный итерабель не будет скопирован в какую-либо коллекцию (по семантике, т.е. скопирован в экземпляр List<T>), любая повторная итерация по этому итерабельному вызовет еще одно преобразование каждый раз, когда вы неявно вызываете iterator.next() для этого итерабельного от каждого для каждого). Таким образом:

final JSONObject jsonObject = ... 
// ... 
final Iterable<Void> voids = Iterables.transform(Arrays.asList(states), new Function<State, Void>() { 
    @Override 
    public Void apply(State currentState) { 
     jsonObject.put(String.valueOf(currentState.getId()), currentState.getName()); 
     return null; 
    } 
}); 
for (final Void v : voids) { 
    // do nothing 
} 

Это действительно плохая и уродливая идея. Вам действительно нужна функция агрегирования, которая создает/поставляет ваш объект JSON, последовательность нужных элементов State и бифункцию, которая принимает накопленный объект JSON и один объект state и возвращает обновленный объект JSON. Нечто подобное в своей общей форме (ваш может создавать свои собственные функции и декоратор):

public static <T, R> R reduce(Supplier<R> init, Iterable<T> sequence, BiFunction<R, T, R> function) { 
    R accumulator = init.get(); 
    for (final T item : sequence) { 
     accumulator = function.apply(accumulator, item); 
    } 
    return accumulator; 
} 

гуава не предоставляет никакой агрегатных функции инфраструктуры и выше Arity функции (см idea graveyard, Aggregator Functions в системе отслеживания проблем).

+0

Хорошее объяснение. Конечно, просто использование цикла 'for', так как в первой части вопроса все еще в десять раз лучше, чем метод' reduce' helper ... –