Как конвертировать обычные для l oop в java 8 потоков - PullRequest
0 голосов
/ 17 марта 2020

У меня есть классы Product и RegionAllocation

class Product{

int id;
String region;
int price;

Product(int I'd, int price,String region){
this.id = id;
this.price = price;
this.region = region;
}
 //getters for id and price
}

List<Product> list = new ArrayList();
list.add(1, 30, "LDN")
list.add(2, 25, "NYK")

И

class RegionAllocation{
int price;
int alloQty;

RegionAllocation(Product p)
this.price = p.getPrice();
}

RegionAllocation allocate(int a){
this.alloQty+=a;
return this;
}

}

Я хочу написать функцию, используя потоки, потоки которых через продукты и для каждого продукта создает объект RegionAllocation и устанавливает функцию выделения на основе значений цены

List<RegionAllocation> reg = new ArrayList();
for(Product p : products) {
    RegionAllocation r = new RegionAllocation(p); 

    if(p.getRegion().equals("LDN") {
        r.allocate(0);
    } else{          
        r.allocate(p.getPrice()*5)
    }
    reg.add(r);
    }

return reg;

Я хочу написать выше, используя поток java 8.

Ответы [ 2 ]

2 голосов
/ 17 марта 2020

Вы можете использовать map и собрать поток в список:

List<RegionAllocation> reg = products.stream()
    .map(p -> new RegionAllocation(p).allocate(p.getRegion().equals("LDN") ? 0 : p.getPrice() * 5))
    .collect(Collectors.toList());
0 голосов
/ 20 марта 2020

При преобразовании обычных циклов в Stream s рекомендуется сначала определить, что делает каждый фрагмент кода.

Если мы посмотрим на ваше значение l oop, мы можем вывести следующее функциональность:

// Creation of an empty list
List<RegionAllocation> reg = new ArrayList();
// Loop over the products
for(Product p : products) {
    // Create a new RegionAllocation
    RegionAllocation r = new RegionAllocation(p); 

    // Allocate the RegionAllocation
    if(p.getRegion().equals("LDN") {
        r.allocate(0);
    } else{          
        r.allocate(p.getPrice()*5)
    }
    // Add the RegionAllocation to the list
    reg.add(r);
}

return reg;

Из этого мы уже видим, что код внутри вашего для l oop состоит из двух отдельных частей; создание и выделение нового RegionAllocation из Product и добавление этого нового RegionAllocation в список.

Первым шагом в этом случае будет извлечение создания и выделения RegionAllocation в отдельный метод, подобный этому (я обернул ваш оригинальный код в метод и назвал его createRegionAllocations)

public List<RegionAllocation> createRegionAllocations(List<Product> products) {
    List<RegionAllocation> reg = new ArrayList();
    for(Product p : products) {
        RegionAllocation r = createRegionAllocation(p);
        reg.add(r);
    }

    return reg;
}

private RegionAllocation createRegionAllocation(Product p) {
    RegionAllocation r = new RegionAllocation(p); 

    if(p.getRegion().equals("LDN") {
        r.allocate(0);
    } else{          
        r.allocate(p.getPrice()*5)
    }

    return r;
}

Теперь мы можем преобразовать l oop в поток. Часть 'for' l oop

for (Product p : products)

становится

products.stream() // Stream<Product>

, то есть Stream<Product> aka, потоком продуктов.

Метод createRegionAllocation создает RegionAllocation из Product, поэтому он преобразует один тип (Product) в другой тип (RegionAllocation). Это то, что метод map делает для потоков. Его подпись

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

, где T - это тип потока, для которого вызывается map, а R - новый тип. Итак, в вашем случае мы можем теперь сделать

products.stream() // Stream<Product>
    .map(p -> createRegionAllocation(p)) // Stream<RegionAllocation>

Последний шаг - создать список потока. Вот для чего нужен метод collect. Существует множество способов сбора потока, но для этого случая, когда мы собираем, мы делаем

products.stream() // Stream<Product>
    .map(p -> createRegionAllocation(p)) // Stream<RegionAllocation>
    .collect(Collectors.toList()) // List<RegionAllocation>

Помимо Collectors.toList() (который собирает до List), вы также можете сделать, например, Collectors.toSet() (который собирает до Set) или целый ряд других пользовательских сборщиков, если они вам нужны. Но для List s вам нужно запомнить только .collect(Collectors.toList()).

. Наконец, мы можем использовать ссылку на метод для createRegionAllocation:

products.stream() // Stream<Product>
    .map(this::createRegionAllocation) // Stream<RegionAllocation>
    .collect(Collectors.toList()) // List<RegionAllocation>

Так что, когда мы все сложим вместе мы получаем

public List<RegionAllocation> createRegionAllocations(List<Product> products) {
    return products.stream()
        .map(this::createRegionAllocation)
        .collect(Collectors.toList());
}

private RegionAllocation createRegionAllocation(Product p) {
    RegionAllocation r = new RegionAllocation(p); 

    if(p.getRegion().equals("LDN") {
        r.allocate(0);
    } else{          
        r.allocate(p.getPrice()*5)
    }

    return r;
}
...