#java #stream
Вопрос:
Я хочу написать функцию, которая создаст поток случайных чисел:
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class fillRandom {
public static List<Integer> IntFill(){
return new Random().ints(10,0,100).boxed().collect(Collectors.toList());
}
}
А затем я хочу вернуть его в свой список ссылок:
public class Main {
public static void main(String[] args) throws Exception {
List linkedList = new LinkedList<Integer>();
Print printer = new printImpl();
linkedList = (LinkedList) fillRandom.IntFill();
printer.print(linkedList);
}
}
Но я получаю ошибку Exception in thread "main" java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.util.LinkedList
Можно ли сделать что-то, чтобы заставить его работать без collect(Collectors.toCollection(LinkedList::new))
этого ? Если я не хочу возвращать точно список ArrayList из Random
Комментарии:
1. Почему ты не хочешь использовать
toCollection
? Что в этом плохого?2. @Sweeper Ну, я просто думаю ,что было бы лучше не зависеть от одной реализации, а назначить ту, которая у меня есть (LinkedList или ArrayList)
3.
List<Integer> list = fillRandom.IntFill(); List<Integer> lL = new LinkedList<>(list);
4. Зачем тебе это нужно
LinkedList
? Это почти всегда неправильный выбор, как с точки зрения производительности, так и с точки зрения затрат памяти.5. Вы упоминаете «назначить тот, который у меня есть», однако вы назначаете его в список. Вы заявляете об этом как
List linkedlist
и не какLinkedList linkedlist
. первый список ссылок, с помощью которого вы создаете,new LinkedList<Integer>()
полностью отбрасывается и собирается мусор, как только вы назначаете ему новый вlinkedList = (LinkedList) fillRandom.IntFill()
Ответ №1:
Согласно документации toList
, нет никакой гарантии на тип возвращаемого списка, и он специально просит вас использовать toCollection
Нет никаких гарантий относительно типа, изменяемости, сериализуемости или потокобезопасности возвращаемого списка; если требуется больший контроль над возвращаемым списком, используйте
toCollection(Supplier)
.
Если ваша причина отказа от использования toCollection
заключается в том , чтобы просто избежать использования конкретной реализации intFill
, и вы хотите, чтобы вызывающий абонент мог указать, что List
он хочет, вы всегда можете предоставить пользователю эту опцию с Supplier
параметром, как toCollection
это делает.
public static <C extends Collection<Integer>> C intFill(Supplier<C> collectionSupplier){
return new Random().ints(10,0,100).boxed()
.collect(Collectors.toCollection(collectionSupplier));
}
Использование:
List<Integer> linkedList = fillRandom.intFill(LinkedList::new);
В качестве альтернативы, вместо приведения, используйте LinkedList
конструктор для создания LinkedList
из того, что List
возвращается toList
сборщиком.
List<Integer> linkedList = new LinkedList<>(fillRandom.intFill());
Обратите внимание, что недостатком этого является то, что он будет повторять цикл по всему списку снова, что может быть нежелательно.
Ответ №2:
Вы должны придерживаться использования интерфейса List
вместо использования реализующего класса как LinkedList
.
Сказав это, если вы действительно хотите собрать в класс объект, который у вас уже есть, вы можете сделать что-то подобное, сначала сообщив Сборщику, на каком объекте вы хотите основываться (хотя я не рекомендую этого делать).:
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class fillRandom {
public static List<Integer> IntFill(List base){
return (List<Integer>) new Random().ints(10,0,100).boxed().collect(Collectors.toCollection(() -> {
try {
return base.getClass().newInstance();
} catch (Exception ex) {
// Default
return new ArrayList<>();
}
}));
}
}
А затем назовите это так:
public class Main {
public static void main(String[] args) throws Exception {
List linkedList = new LinkedList<Integer>();
Print printer = new printImpl();
linkedList = fillRandom.IntFill(linkedList);
printer.print(linkedList);
}
}
Также обратите внимание, что при сборе данных вы создаете совершенно новый список, а не заполняете тот, который вы уже составили. Затем, когда вы назначаете его переменной, вы заменяете старую.
Ответ №3:
List linkedList = new LinkedList<Integer>();
List<Integer> list = (LinkedList)fillRandom.IntFill();
linkedList = new LinkedList<>(list);
System.out.println(linkedList);
Этот код должен работать для вас