同事說,我寫Java代碼像寫詩
往期熱門文章:
1、2021年互聯(lián)網公司“死亡”名單!2022 年跳槽一定要謹慎些!2、京東程序員離職怒刪代碼被判10個月,京東到家請人花三萬恢復!3、AlphaCode 驚世登場!編程版“阿法狗”悄悄參賽,擊敗一半程序員4、被阿里P8面了兩個小時,技術、業(yè)務有來有回......5、再見丑陋的 SwaggerUI,這款API文檔生成神器界面更炫酷,逼格更高!文章來源:http://33h.co/kntu3
前幾天空閑時間寫了一遍關于平時自己寫代碼的一些習慣,這里跟大家分享一下。
定義配置文件信息?
有時候我們?yōu)榱私y(tǒng)一管理會把一些變量放到 yml 配置文件中。
例如:

用 @ConfigurationProperties 代替 @Value。
使用方法:
定義對應字段的實體:
@Data
//?指定前綴
@ConfigurationProperties(prefix?=?"developer")
@Component
public?class?DeveloperProperty?{
????private?String?name;
????private?String?website;
????private?String?qq;
????private?String?phoneNumber;
}
使用時注入這個 bean:
@RestController
@RequiredArgsConstructor
public?class?PropertyController?{
????final?DeveloperProperty?developerProperty;
????@GetMapping("/property")
????public?Object?index()?{
???????return?developerProperty.getName();
????}
}
用@RequiredArgsConstructor代替@Autowired?
我們都知道注入一個 bean 有三種方式哦(set 注入,構造器注入,注解注入),spring 推薦我們使用構造器的方式注入 Bean。

RequiredArgsConstructor:lombok 提供。
代碼模塊化?
阿里巴巴 Java 開發(fā)手冊中說到每個方法的代碼不要超過 50 行(我沒記錯的話)。

拋異常而不是返回?
在寫業(yè)務代碼的時候,經常會根據不同的結果返回不同的信息,盡量減少返回,會顯得代碼比較亂。
正例:
減少不必要的db?
盡可能的減少對數據庫的查詢。
舉例子:刪除一個服務(已下架或未上架的才能刪除),之前有看別人寫的代碼,會先根據 id 查詢該記錄,然后做一些判斷。
正例:
不要返回null?
正例:
別處調用方法時,避免不必要的空指針。
if else?
不要太多了 if else if,可以試試策略模式代替。
減少controller業(yè)務代碼?
業(yè)務代碼盡量放到 service 層進行處理,后期維護起來也好操作而且美觀。
正例:
利用好Idea?
目前為止市面上的企業(yè)基本都用 idea 作為開發(fā)工具了吧。
舉一個小例子:idea 會對我們的代碼進行判斷,提出合理的建議。

它推薦我們用 lanbda 的形式代替。

閱讀源碼?
一定要養(yǎng)成閱讀源碼的好習慣包括優(yōu)秀的開源項目 GitHub上stars:>1000,會從中學好好多知識包括其對代碼的設計思想以及高級 API,面試加分(好多面試官習慣問源碼相關的知識)。
設計模式?
23 種設計模式,要嘗試代碼中運用設計模式思想,寫出的代碼即規(guī)范又美觀還高大上,哈哈。
擁抱新知識?
像我們這種工作年限少的程序員,我覺得要多學習自己認知之外的知識,不能每天 crud,有機會就多用用有點難度的知識,沒有機會(項目較傳統(tǒng)),可以自己下班多些相關 demo 練習。
基礎問題?
????????HashMap<String,?String>?map?=?new?HashMap<>();
????????map.put("name",?"du");
????????for?(String?key?:?map.keySet())?{
????????????String?value?=?map.get(key);
????????}
????????map.forEach((k,?v)?->?{
????????});
????????//?推薦
????????for?(Map.Entry<String,?String>?entry?:?map.entrySet())?{
????????}
????//獲取子目錄列表
????public?List?getChild(String?pid)?{
????????????if?(V.isEmpty(pid))?{
????????????pid?=?BasicDic.TEMPORARY_DIRECTORY_ROOT;
????????}
????????CatalogueTreeNode?node?=?treeNodeMap.get(pid);
????????return?Optional.ofNullable(node)
????????????????.map(CatalogueTreeNode::getChild)
????????????????.orElse(Collections.emptyList());
????}
遞歸
大數據量的遞歸時,避免在遞歸方法里 new 對象,可以試試把對象當作方法參數進行傳遞使用
注釋
類、接口方法、注解、較復雜的方法,注釋都要寫而且要寫清楚,有時候寫注釋不是給別人看的,而是給自己看的
判斷元素是否存在?
hashSet 而不是 list
ArrayList?list?=?new?ArrayList<>();
//?判斷a是否在list中
for?(int?i?=?0;?i?list.size();?i++)
???????if?("a".equals(elementData[i]))
??????????return?i;
由此可見其復雜度為 On
HashSet<String>?set?=?new?HashSet<>();
//?判斷a是否在set中
int?index?=?hash(a);
return?getNode(index)?!=?null
由此可見其復雜度為 O1。
統(tǒng)一管理線程池?
private?static?volatile?ThreadPoolExecutor?threadPoolExecutor?=?null;
????private?static?final?int?CORE_POOL_SIZE?=?0;
????private?static?final?int?MAX_MUM_POOL_SIZE?=?1000;
????private?static?final?long?KEEP_ALIVE_TIME?=?2;
????private?static?final?TimeUnit?UNIT?=?TimeUnit.MINUTES;
????private?static?final?int?CAPACITY?=?1;
????private?static?final?RejectedExecutionHandler?HANDLER?=?new?ThreadPoolExecutor.CallerRunsPolicy();
????private?static?final?BasicThreadFactory?factory?=
????????????new?BasicThreadFactory.Builder().namingPattern("aiserviceplatform-util-thread-pool-%d").build();
????private?ThreadPoolFactory()?{
????}
????public?static?ThreadPoolExecutor?getInstance()?{
????????if?(threadPoolExecutor?==?null)?{
????????????synchronized?(ThreadPoolFactory.class)?{
????????????????if?(threadPoolExecutor?==?null)?{
????????????????????threadPoolExecutor?=?new?ThreadPoolExecutor(CORE_POOL_SIZE,?MAX_MUM_POOL_SIZE,?KEEP_ALIVE_TIME,?UNIT,?new?ArrayBlockingQueue<>(CAPACITY),?factory,?HANDLER);
????????????????}
????????????}
????????}
????????return?threadPoolExecutor;
????}
大量數據同步?
String?realTabelName?=?....;
String?tempTableName?=?realTableName?+?"_temp";
createTable(tempTableName);?//?創(chuàng)建臨時表
boolean?flag?=?sync(tempTableName);?//?同步數據
//?根據結果
if(flag)?{
????dropTable(realTabelName);
????alterTabelName(realTableName,?tempTableName);?//?臨時表改名?實際表
}else?{
????//?同步失敗?刪除臨時表
????dropTabel(tempTableName)
}
實測:比對一張表做處理會快很多而且不會出問題。
接口入參?
定義接口的方法時,如接受一個集合類型,盡可能的用 Collection
Collection<String>?getNodeIds(Collection<String>?ids);
鎖的顆粒度?
同步方法直接在方法上加 synchronized 實現加鎖,同步代碼塊則在方法內部加鎖,很明顯,同步方法鎖的范圍比較大,而同步代碼塊范圍要小點,一般同步的范圍越大,性能就越差,一般需要加鎖進行同步的時候,肯定是范圍越小越好,這樣性能更好
我一般使用 lock:ReentrantLock,ReentrantReadWriteLock,減少鎖的顆粒度,提高系統(tǒng)的并發(fā)能力。
緩存名稱?
簡短,精練,以文件夾形式保存,xxx:xxx:xxx,以:隔開。

方便查看緩存信息。
@Cacheable?
使用 Cacheable 做緩存時,也要加上緩存失效時間。

@Bean
????public?CacheManager?cacheManager(RedisConnectionFactory?factory)?{
????????return?new?RedisCacheManager(
????????????????RedisCacheWriter.lockingRedisCacheWriter(factory),
????????????????this.getRedisCacheConfigurationWithTtl(1),
????????????????this.getRedisCacheConfigurationMap()
????????);
????}
????private?RedisCacheConfiguration?getRedisCacheConfigurationWithTtl(Integer?hour)?{
????????Jackson2JsonRedisSerializer<Object>?jackson2JsonRedisSerializer?=?new?Jackson2JsonRedisSerializer<>(Object.class);
????????ObjectMapper?om?=?new?ObjectMapper();
????????om.setVisibility(PropertyAccessor.ALL,?JsonAutoDetect.Visibility.ANY);
????????om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,?ObjectMapper.DefaultTyping.NON_FINAL);
????????jackson2JsonRedisSerializer.setObjectMapper(om);
????????return?RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
????????????????RedisSerializationContext
????????????????????????.SerializationPair
????????????????????????.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofHours(hour));
????}
????public?static?final?String?REGION_LIST_BY_CODE_CACHE_KEY?=?"region:list";
????public?static?final?String?REGION_NAME_BY_CODE_CACHE_KEY?=?"region:name";
????/**
?????*?已知緩存名稱的映射以及用于這些緩存的配置
?????*/
????private?Map<String,?RedisCacheConfiguration>?getRedisCacheConfigurationMap()?{
????????Map<String,?RedisCacheConfiguration>?redisCacheConfigurationMap?=?new?HashMap<>();
????????//?自定義緩存名稱對應的配置
????????redisCacheConfigurationMap.put(REGION_LIST_BY_CODE_CACHE_KEY,?this.getRedisCacheConfigurationWithTtl(24));
????????redisCacheConfigurationMap.put(REGION_NAME_BY_CODE_CACHE_KEY,?this.getRedisCacheConfigurationWithTtl(120));
????????redisCacheConfigurationMap.put(RedisKey.MARK_SERVICE_RENEW,?this.getRedisCacheConfigurationWithTtl(-1));
????????redisCacheConfigurationMap.put(RedisKey.MARK_ORGAN_RENEW,?this.getRedisCacheConfigurationWithTtl(-1));
????????redisCacheConfigurationMap.put(RedisKey.MARK_SERVICE_STREAM,?this.getRedisCacheConfigurationWithTtl(-1));
????????redisCacheConfigurationMap.put(RedisKey.MARK_ORGAN_STREAM,?this.getRedisCacheConfigurationWithTtl(-1));
????????return?redisCacheConfigurationMap;
????}
異步任務?
為了提高接口的響應速度,我們會把比較耗時的操作異步處理。例如異步任務,消息隊列等。
往期熱門文章:
