我有一个方法params是一个列表,该列表大于50000个项目; 限于业务逻辑,该列表必须少于30000,这样我就可以在逻辑之前将数组拆分为2d数组。
public static final <T> Collection<List<T>> partitionBasedOnSize(List<T> inputList, int size) {
AtomicInteger counter = new AtomicInteger(0);
return inputList.stream().collect(Collectors.groupingBy(s -> counter.getAndIncrement() / size)).values();
}
这是我当前的解决方案:
public List<Account> getChildrenList(List<Long> ids) {
List<Account> childrenList = new ArrayList<>();
Collection<List<Long>> childrenId2dList = PartitionArray.partitionBasedOnSize(childrenIdsList, 30000);
for (List<Long> list : childrenId2dList) {
//this is my business logic: start
childrenList.addAll(accountRepository.getAccounts(list));
//this is my business logic: end
}
return childrenAccountsList;
}
我想在该方法的顶部创建一个注释,而不是许多重复的代码(每次检查并反复执行...)
答案 0 :(得分:2)
在我看来,在这种情况下,使用注释会有些过度设计(您必须编写注释处理器)。您可以轻松地使用泛型和 lambdas 和/或方法引用来实现您的目标。例如:
以这种方式更新PartitionArray
:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
public class PartitionArray {
private static <T> Collection<List<T>> partitionBasedOnSize(List<T> inputList, int partitionSize) {
Collection<List<T>> collection = new ArrayList<>();
int remainingSize = inputList.size();
int index = 0;
while (remainingSize > partitionSize) {
collection.add(inputList.subList(index, index + partitionSize));
remainingSize -= partitionSize;
index += partitionSize;
}
collection.add(inputList.subList(index, index + remainingSize));
return collection;
}
public static <D, T> List<D> partitionAndDoBusinessFunction(List<T> ids, Function<List<T>, List<D>> businessFunction, int partitionSize) {
List<D> dataList = new ArrayList<>();
Collection<List<T>> idListCollection = partitionBasedOnSize(ids, partitionSize);
for (List<T> idList : idListCollection) {
dataList.addAll(businessFunction.apply(idList));
}
return dataList;
}
}
然后只需从您的AccountService
(使用方法参考)中使用它即可:
import java.util.List;
public class AccountService {
private AccountRepository accountRepository;
public List<Account> getAccounts(List<Long> ids) {
return PartitionArray.partitionAndDoBusinessFunction(ids, accountRepository::getAccounts, 30000);
}
}
或使用lambdas:
import java.util.List;
public class AccountService {
private AccountRepository accountRepository;
public List<Account> getAccounts(List<Long> ids) {
return PartitionArray.partitionAndDoBusinessFunction(ids, idList -> {
List<Account> accounts = accountRepository.getAccounts(idList);
// do more business on accounts
return accounts;
}, 30000);
}
}
答案 1 :(得分:1)
以下是使用注释和AspectJ的解决方案:
首先,定义所需的注释:
package partition;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Partitioned {
/**
* The size of the partition, for instance 30000
*/
int size();
}
因此您的服务将如下所示:
package partition;
import java.util.List;
public class AccountService {
private AccountRepository accountRepository;
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
@Partitioned(size = 30000)
public List<Account> getAccounts(List<Long> ids) {
return accountRepository.getAccounts(ids);
}
}
到目前为止,这很容易。接下来是注释的处理,AspectJ在其中进入游戏。定义链接到注释的方面:
package partition;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Aspect
public class PartitionedAspect {
@Pointcut("@annotation(partitioned)")
public void callAt(Partitioned partitioned) {
}
@Around("callAt(partitioned)")
public <T, D> Object around(ProceedingJoinPoint pjp, Partitioned partitioned) throws Throwable {
List<T> inputIds = (List) pjp.getArgs()[0];
if (inputIds.size() > partitioned.size()) {
List<D> dataList = new ArrayList<>();
Collection<List<T>> partitionedIds = PartitionArray.partitionBasedOnSize(inputIds, partitioned.size());
for (List<T> idList : partitionedIds) {
List<D> data = (List) pjp.proceed(new Object[]{idList});
dataList.addAll(data);
}
return dataList;
}
return pjp.proceed();
}
}
当然,您必须导入 AspectJ,并在编译时进行一些其他操作。假设您正在使用Maven,请将这些行添加到pom.xml
(插件和依赖项)中:
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
...
</dependencies>