<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          同事說,我寫Java代碼像寫詩

          共 2496字,需瀏覽 5分鐘

           ·

          2022-02-20 06:21

          往期熱門文章:

          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 配置文件中。


          例如:

          f7f61ae605cdfa93d0f34c2b1b65789d.webp

          用 @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。


          我們來看看上段代碼編譯完之后的樣子:409367dcc51873199c9d4ef5c68fe618.webp

          RequiredArgsConstructor:lombok 提供。


          代碼模塊化?


          阿里巴巴 Java 開發(fā)手冊中說到每個方法的代碼不要超過 50 行(我沒記錯的話)。


          在實際的開發(fā)中我們要善于拆分自己的接口或方法,做到一個方法只處理一種邏輯,說不定以后某個功能就用到了,拿來即用。

          86d482c665f72dbb17af449eb008880b.webp

          拋異常而不是返回?


          在寫業(yè)務代碼的時候,經常會根據不同的結果返回不同的信息,盡量減少返回,會顯得代碼比較亂。


          反例:e93803d916b14a0f45e96dadf286be38.webp正例:8f2ff5e75273c44afb3a3d978bb8fd6b.webp

          減少不必要的db?


          盡可能的減少對數據庫的查詢。


          舉例子:刪除一個服務(已下架或未上架的才能刪除),之前有看別人寫的代碼,會先根據 id 查詢該記錄,然后做一些判斷。


          反例:a8895bd5350c5a8ca1d807c3bac97ef1.webp正例:686214ce67a5eca7e5ba36d41899cdd7.webp

          不要返回null?


          反例:677ac1bd718e6afc738d154b4bbecb64.webp正例:468b839e8a6e51ede4a4428035539ba1.webp

          別處調用方法時,避免不必要的空指針。


          if else?


          不要太多了 if else if,可以試試策略模式代替。


          減少controller業(yè)務代碼?


          業(yè)務代碼盡量放到 service 層進行處理,后期維護起來也好操作而且美觀。


          反例:e65c9b89887fb3301218166aadccd843.webp正例:ec39288877c4c7e19e8b811d73ea1a68.webp

          利用好Idea?


          目前為止市面上的企業(yè)基本都用 idea 作為開發(fā)工具了吧。


          舉一個小例子:idea 會對我們的代碼進行判斷,提出合理的建議。


          例如:04079fa20775d91980498f9926e91f6d.webp

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


          點擊 replace:aad3d04e4b92af25da7881fb1c65780c.webp

          閱讀源碼?


          一定要養(yǎng)成閱讀源碼的好習慣包括優(yōu)秀的開源項目 GitHub上stars:>1000,會從中學好好多知識包括其對代碼的設計思想以及高級 API,面試加分(好多面試官習慣問源碼相關的知識)。


          設計模式?


          23 種設計模式,要嘗試代碼中運用設計模式思想,寫出的代碼即規(guī)范又美觀還高大上,哈哈。


          擁抱新知識?


          像我們這種工作年限少的程序員,我覺得要多學習自己認知之外的知識,不能每天 crud,有機會就多用用有點難度的知識,沒有機會(項目較傳統(tǒng)),可以自己下班多些相關 demo 練習。


          基礎問題?


          map 遍歷:
          ????????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())?{

          ????????}


          optional 判空:
          ????//獲取子目錄列表
          ????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


          list 判斷一個元素是否存在的代碼:
          ArrayList?list?=?new?ArrayList<>();

          //?判斷a是否在list中

          for?(int?i?=?0;?i?list.size();?i++)
          ???????if?("a".equals(elementData[i]))
          ??????????return?i;


          由此可見其復雜度為 On


          而 hashSet 底層采用 hashMap 作為數據結構進行存儲,元素都放到 map 的 key(即鏈表中)
          HashSet<String>?set?=?new?HashSet<>();

          //?判斷a是否在set中

          int?index?=?hash(a);

          return?getNode(index)?!=?null


          由此可見其復雜度為 O1。


          統(tǒng)一管理線程池?


          有的會在用到多線程的地方就創(chuàng)建一個線程池,為了統(tǒng)一管理,建議建立一個線程池,統(tǒng)一管理,統(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;
          ????}


          大量數據同步?


          在同步大數據量的信息時(常用多線程方式:如果表里有唯一索引或者對表進行 update 操作那么就會經常鎖表),優(yōu)先考慮添加臨時表的方式。
          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,因為其他業(yè)務場景可能會穿一個 list 有的會傳一個 hashSet,用起來還要改,Map 也是。


          正例:
          Collection<String>?getNodeIds(Collection<String>?ids);


          鎖的顆粒度?


          同步方法直接在方法上加 synchronized 實現加鎖,同步代碼塊則在方法內部加鎖,很明顯,同步方法鎖的范圍比較大,而同步代碼塊范圍要小點,一般同步的范圍越大,性能就越差,一般需要加鎖進行同步的時候,肯定是范圍越小越好,這樣性能更好


          我一般使用 lock:ReentrantLock,ReentrantReadWriteLock,減少鎖的顆粒度,提高系統(tǒng)的并發(fā)能力。


          緩存名稱?


          簡短,精練,以文件夾形式保存,xxx:xxx:xxx,以:隔開。

          a3e06dcb03579c15782e90d272de620b.webp

          方便查看緩存信息。


          @Cacheable?


          使用 Cacheable 做緩存時,也要加上緩存失效時間。


          之前提出疑問怎么有的緩存沒有失效時間,看代碼使用 Cacheable 緩存的,不會添加就沒加(???)。

          7487dbbf4f3ec14e7abe7da5ab68e2e2.webp


          @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;
          ????}


          異步任務?


          為了提高接口的響應速度,我們會把比較耗時的操作異步處理。例如異步任務,消息隊列等。


          往期熱門文章:

          1、滴滴程序員被親戚鄙視:年薪八十萬還不如二本教書的...2、IT界驚現文豪!華為領導及阿里P10遭吐槽

          3、上海地鐵乘車碼“變紅”,嚇倒一眾乘客,官方:為營造節(jié)日氣氛……4、Spring Boot 項目打成 .exe 程序?實戰(zhàn)來了!5、Spring Boot太重,Vert.x真香!6、中美程序員不完全對比7、Spring Boot 3.0 M1 發(fā)布,正式棄用 Java 8,最低要求 Java 17。。。8、一個“扛住100億次請求”的春晚紅包系統(tǒng)9、你覺得HTTPS能防止重放攻擊嗎?10、數據一致性,為什么不推薦雙寫?

          瀏覽 65
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲高清免费在线 | 五一黄片视频 | 亚洲激情四射婷婷 | 午夜视频黄色 | 青青草狠狠干 |