Можно ли преобразовать возвращаемый тип collect (Коллекторы.ToList() в список ссылок?

#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);
 

Этот код должен работать для вас