泛型方法和类允许程序员编写高级化的单个方法或类,以用于不同的类型。
泛型方法和类允许程序员编写高级化的单个方法或类,以用于不同的类型。
我们每天都在使用它们,例如List ,Stream ,Map …
泛型类是普通类,其类名后跟一个类型参数部分。这些类称为参数化类或参数化类型,因为它们接受一个或多个参数。
特征:
- 类型安全:泛型中只能容纳一种类型的对象。
- 不需要类型转换:无需类型转换对象。
- 编译时检查:在编译时进行检查,因此在运行时不会发生此问题。好的编程策略表明,在编译时处理问题比运行时要好得多。
类型参数命名约定:
- T type
- E element
- K Key
- N Number
- V value
泛型通配符:
我们知道 ? 是通配符,它表示任何类型。如果我们写<? extends Number>,我们接受Number的任何子类,例如Integer,Float和double。
我们可以使用通配符作为参数,字段,返回类型或局部变量的类型。但是,不允许将通配符用作泛型方法调用,泛型类实例创建或超类型的类型参数。
通用类示例:
public class Response<T> {
private List<T> data;
private Integer page;
private Integer elements;
}
在第一个简单示例中,我们创建了一个通用类Response,将用于返回分页的结果。我们不需要做魔术,也不必创建其他类。
如何写更少的代码?
尽管泛型在库中使用非常广泛,但是我看到很少有程序员使用泛型来泛化代码,例如,您有多少次看到控制器,服务和存储库几乎在做同样的事情?
在介绍完之后,我希望您展示一个简单的示例,说明如何编写一次性代码并在多个类中使用它。
一个简单的项目
在此示例中,我想向您展示如何定义BaseService和GeneralRepository来处理Java服务中的常见操作。
BaseEntity.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseEntity {
@Id
protected String id;
protected String tenantId;
protected Date creationDate;
protected Date updateDate;
}
我们正在创建一个简单的类,该类在我们的类中包含commons属性,下一个代码段将很有必要。
BaseRepository
@Repository
public interface GenericRepository<E extends BaseEntity> extends ReactiveCrudRepository<E, String> {
Mono<Void> deleteByIdAndTenantId(String id, String tenantId);
Mono<E> findFirstByIdAndTenantId(String id, String tenantId);
}
这是基本存储库,其中包含对我们的BaseEntity类的子类的常见查询。
BaseService
@Service
@Slf4j
public class BaseService<E extends BaseEntity> {
@Autowired
protected GenericRepository<E> generalRepo;
public Mono<E> findEnitity(String entityId, String tenantId) {
return generalRepo.findFirstByIdAndTenantId(entityId,tenantId);
}
public Mono<Void> delete(String entityId, String tenantId) {
return findEnitity(entityId, tenantId)
.switchIfEmpty(Mono.error(new NotFoundException(ITEM_NOT_FOUND)))
.flatMap(e -> generalRepo.deleteByIdAndTenantId(e.getId(),e.getTenantId()));
}
public Mono<E> saveEntity(String tenantId, E entity) {
entity.setTenantId(tenantId);
return generalRepo.save(entity);
}
public Mono<E> updateEntity(String entityId, String tenantId,E entity) {
return findEnitity(entityId,tenantId)
.map(u -> saveEntity(tenantId,entity))
.switchIfEmpty(Mono.error(new Exception(ITEM_NOT_FOUND)))
.flatMap(m -> m);
}
}
所有服务将继承BaseService继承继承的保存,更新,查找和删除方法,这些方法执行通用操作以将我们的数据持久保存在数据库中。显然,这段代码非常简单,您可以编写一种处理分页请求的方法,在执行插入/更新之前添加检查。
BaseController
public class BaseController<E extends BaseEntity> {
@Autowired
private BaseService<E> baseService;
@PostMapping("/save")
public Mono<E> save(Authentication auth,
@RequestBody E entity) {
return baseService.save(getTenant(auth),entity);
}
}
让我们以允许在多个控制器之间共享公共端点的BaseController结束该示例。
总结
因此,我们对泛型进行了一些小小的更新,并看到了如何编写更少的代码来使多个类之间的通用操作更加温和。