1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 2496字,需瀏覽 5分鐘

         ·

        2022-02-20 06:21

        往期熱門文章:

        1、2021年互聯(lián)網(wǎng)公司“死亡”名單!2022 年跳槽一定要謹(jǐn)慎些!2、京東程序員離職怒刪代碼被判10個(gè)月,京東到家請(qǐng)人花三萬恢復(fù)!3、AlphaCode 驚世登場(chǎng)!編程版“阿法狗”悄悄參賽,擊敗一半程序員4、被阿里P8面了兩個(gè)小時(shí),技術(shù)、業(yè)務(wù)有來有回......5、再見丑陋的 SwaggerUI,這款A(yù)PI文檔生成神器界面更炫酷,逼格更高!文章來源:http://33h.co/kntu3

        前幾天空閑時(shí)間寫了一遍關(guān)于平時(shí)自己寫代碼的一些習(xí)慣,這里跟大家分享一下。


        定義配置文件信息?


        有時(shí)候我們?yōu)榱私y(tǒng)一管理會(huì)把一些變量放到 yml 配置文件中。


        例如:

        f7f61ae605cdfa93d0f34c2b1b65789d.webp

        用 @ConfigurationProperties 代替 @Value。


        使用方法:


        定義對(duì)應(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。


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

        RequiredArgsConstructor:lombok 提供。


        代碼模塊化?


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


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

        86d482c665f72dbb17af449eb008880b.webp

        拋異常而不是返回?


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


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

        減少不必要的db?


        盡可能的減少對(duì)數(shù)據(jù)庫的查詢。


        舉例子:刪除一個(gè)服務(wù)(已下架或未上架的才能刪除),之前有看別人寫的代碼,會(huì)先根據(jù) id 查詢?cè)撚涗?,然后做一些判斷?/span>


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

        不要返回null?


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

        別處調(diào)用方法時(shí),避免不必要的空指針。


        if else?


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


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


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


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

        利用好Idea?


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


        舉一個(gè)小例子:idea 會(huì)對(duì)我們的代碼進(jìn)行判斷,提出合理的建議。


        例如:04079fa20775d91980498f9926e91f6d.webp

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


        點(diǎn)擊 replace:aad3d04e4b92af25da7881fb1c65780c.webp

        閱讀源碼?


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


        設(shè)計(jì)模式?


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


        擁抱新知識(shí)?


        像我們這種工作年限少的程序員,我覺得要多學(xué)習(xí)自己認(rèn)知之外的知識(shí),不能每天 crud,有機(jī)會(huì)就多用用有點(diǎn)難度的知識(shí),沒有機(jī)會(huì)(項(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 對(duì)象,可以試試把對(duì)象當(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)行存儲(chǔ),元素都放到 map 的 key(即鏈表中)
        HashSet<String>?set?=?new?HashSet<>();

        //?判斷a是否在set中

        int?index?=?hash(a);

        return?getNode(index)?!=?null


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


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


        有的會(huì)在用到多線程的地方就創(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í)(常用多線程方式:如果表里有唯一索引或者對(duì)表進(jìn)行 update 操作那么就會(huì)經(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í)測(cè):比對(duì)一張表做處理會(huì)快很多而且不會(huì)出問題。


        接口入?yún)?/strong>?


        定義接口的方法時(shí),如接受一個(gè)集合類型,盡可能的用 Collection,因?yàn)槠渌麡I(yè)務(wù)場(chǎng)景可能會(huì)穿一個(gè) list 有的會(huì)傳一個(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ā)能力。


        緩存名稱?


        簡(jiǎn)短,精練,以文件夾形式保存,xxx:xxx:xxx,以:隔開。

        a3e06dcb03579c15782e90d272de620b.webp

        方便查看緩存信息。


        @Cacheable?


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


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

        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<>();
        ????????//?自定義緩存名稱對(duì)應(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)速度,我們會(huì)把比較耗時(shí)的操作異步處理。例如異步任務(wù),消息隊(duì)列等。


        往期熱門文章:

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

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

        瀏覽 65
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

          <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            奇米影视7777 | 丝袜草逼 | 大逼逼影院 | AAA黄色大片 | 女子口述高潮全过程 | 偷拍乱码在线一区二区 | 女女又爽又黄免费动画 | 一级卖婬片A片AAAA鲁大师 | 成人福利视频在线 | 久久理论电影 |