同事說,我寫Java代碼像寫詩
點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)??

文章來源:http://33h.co/kntu3
前幾天空閑時(shí)間寫了一遍關(guān)于平時(shí)自己寫代碼的一些習(xí)慣,這里跟大家分享一下。
定義配置文件信息?
有時(shí)候我們?yōu)榱私y(tǒng)一管理會把一些變量放到 yml 配置文件中。
例如:

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

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

拋異常而不是返回?
在寫業(yè)務(wù)代碼的時(shí)候,經(jīng)常會根據(jù)不同的結(jié)果返回不同的信息,盡量減少返回,會顯得代碼比較亂。


減少不必要的db?
盡可能的減少對數(shù)據(jù)庫的查詢。
舉例子:刪除一個(gè)服務(wù)(已下架或未上架的才能刪除),之前有看別人寫的代碼,會先根據(jù) id 查詢該記錄,然后做一些判斷。


不要返回null?


別處調(diào)用方法時(shí),避免不必要的空指針。
if else?
不要太多了 if else if,可以試試策略模式代替。
減少controller業(yè)務(wù)代碼?
業(yè)務(wù)代碼盡量放到 service 層進(jìn)行處理,后期維護(hù)起來也好操作而且美觀。


利用好Idea?
目前為止市面上的企業(yè)基本都用 idea 作為開發(fā)工具了吧。
舉一個(gè)小例子:idea 會對我們的代碼進(jìn)行判斷,提出合理的建議。

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

閱讀源碼?
一定要養(yǎng)成閱讀源碼的好習(xí)慣包括優(yōu)秀的開源項(xiàng)目 GitHub上stars:>1000,會從中學(xué)好好多知識包括其對代碼的設(shè)計(jì)思想以及高級 API,面試加分(好多面試官習(xí)慣問源碼相關(guān)的知識)。
設(shè)計(jì)模式?
23 種設(shè)計(jì)模式,要嘗試代碼中運(yùn)用設(shè)計(jì)模式思想,寫出的代碼即規(guī)范又美觀還高大上,哈哈。
擁抱新知識?
像我們這種工作年限少的程序員,我覺得要多學(xué)習(xí)自己認(rèn)知之外的知識,不能每天 crud,有機(jī)會就多用用有點(diǎn)難度的知識,沒有機(jī)會(項(xiàng)目較傳統(tǒng)),可以自己下班多些相關(guān) demo 練習(xí)。
基礎(chǔ)問題?
????????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());
????}
遞歸
大數(shù)據(jù)量的遞歸時(shí),避免在遞歸方法里 new 對象,可以試試把對象當(dāng)作方法參數(shù)進(jìn)行傳遞使用
注釋
類、接口方法、注解、較復(fù)雜的方法,注釋都要寫而且要寫清楚,有時(shí)候?qū)懽⑨尣皇墙o別人看的,而是給自己看的
判斷元素是否存在?
hashSet 而不是 list
ArrayList?list?=?new?ArrayList<>();
//?判斷a是否在list中
for?(int?i?=?0;?i?list.size();?i++)
???????if?("a".equals(elementData[i]))
??????????return?i;
由此可見其復(fù)雜度為 On
HashSet<String>?set?=?new?HashSet<>();
//?判斷a是否在set中
int?index?=?hash(a);
return?getNode(index)?!=?null
由此可見其復(fù)雜度為 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;
????}
大量數(shù)據(jù)同步?
String?realTabelName?=?....;
String?tempTableName?=?realTableName?+?"_temp";
createTable(tempTableName);?//?創(chuàng)建臨時(shí)表
boolean?flag?=?sync(tempTableName);?//?同步數(shù)據(jù)
//?根據(jù)結(jié)果
if(flag)?{
????dropTable(realTabelName);
????alterTabelName(realTableName,?tempTableName);?//?臨時(shí)表改名?實(shí)際表
}else?{
????//?同步失敗?刪除臨時(shí)表
????dropTabel(tempTableName)
}
實(shí)測:比對一張表做處理會快很多而且不會出問題。
接口入?yún)?/strong>?
定義接口的方法時(shí),如接受一個(gè)集合類型,盡可能的用 Collection
Collection<String>?getNodeIds(Collection<String>?ids);
鎖的顆粒度?
同步方法直接在方法上加 synchronized 實(shí)現(xiàn)加鎖,同步代碼塊則在方法內(nèi)部加鎖,很明顯,同步方法鎖的范圍比較大,而同步代碼塊范圍要小點(diǎn),一般同步的范圍越大,性能就越差,一般需要加鎖進(jìn)行同步的時(shí)候,肯定是范圍越小越好,這樣性能更好
我一般使用 lock:ReentrantLock,ReentrantReadWriteLock,減少鎖的顆粒度,提高系統(tǒng)的并發(fā)能力。
緩存名稱?
簡短,精練,以文件夾形式保存,xxx:xxx:xxx,以:隔開。

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

@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<>();
????????//?自定義緩存名稱對應(yīng)的配置
????????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;
????}
異步任務(wù)?
為了提高接口的響應(yīng)速度,我們會把比較耗時(shí)的操作異步處理。例如異步任務(wù),消息隊(duì)列等。
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
PS:因公眾號平臺更改了推送規(guī)則,如果不想錯(cuò)過內(nèi)容,記得讀完點(diǎn)一下“在看”,加個(gè)“星標(biāo)”,這樣每次新文章推送才會第一時(shí)間出現(xiàn)在你的訂閱列表里。
點(diǎn)“在看”支持小哈呀,謝謝啦??

