При преобразовании обычных циклов в 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;
}