<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代碼像寫詩

          共 2440字,需瀏覽 5分鐘

           ·

          2022-02-26 16:15

          點(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ò)的話)。


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

          拋異常而不是返回?


          在寫業(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 的形式代替。


          點(diǎn)擊 replace:

          閱讀源碼?


          一定要養(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ǔ)問題?


          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());
          ????}


          遞歸

          大數(shù)據(jù)量的遞歸時(shí),避免在遞歸方法里 new 對象,可以試試把對象當(dāng)作方法參數(shù)進(jìn)行傳遞使用

          注釋

          類、接口方法、注解、較復(fù)雜的方法,注釋都要寫而且要寫清楚,有時(shí)候?qū)懽⑨尣皇墙o別人看的,而是給自己看的

          判斷元素是否存在?


          hashSet 而不是 list


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

          //?判斷a是否在list中

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


          由此可見其復(fù)雜度為 On


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

          //?判斷a是否在set中

          int?index?=?hash(a);

          return?getNode(index)?!=?null


          由此可見其復(fù)雜度為 O1。


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


          有的會在用到多線程的地方就創(chuàng)建一個(gè)線程池,為了統(tǒng)一管理,建議建立一個(gè)線程池,統(tǒng)一管理,統(tǒng)一設(shè)置非核心線程數(shù),拒絕策略等等。
          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ù)同步?


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


          正例:
          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í)間。


          之前提出疑問怎么有的緩存沒有失效時(shí)間,看代碼使用 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<>();
          ????????//?自定義緩存名稱對應(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ì)列等。

          1.?5 道面試題,拿捏 String 底層原理!

          2.?JMH 和 Arthas 定位問題的案例分享 !

          3.?增加了一行代碼,讓我們提高了 3000% 的性能

          4.?private修飾的方法可以通過反射訪問,那么private的意義是什么?

          最近面試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)“在看”支持小哈呀,謝謝啦??

          瀏覽 32
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  日逼激情网| 国产精品AⅤ电影 | Japanese厨房tub高潮 | A在线视频免费观看 | 91久久久久无码精品国产麻豆 |