泛型方法和類允許程式員編寫進階化的單個方法或類,以用于不同的類型。
我們每天都在使用它們,例如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結束該示例。
總結
是以,我們對泛型進行了一些小小的更新,并看到了如何編寫更少的代碼來使多個類之間的通用操作更加溫和。