標籤: USB CONNECTOR

  • 荷蘭工黨提案於 2025 年禁售汽柴油車

    荷蘭工黨提案於 2025 年禁售汽柴油車

    汽柴油車開在路上,產生氮氧化物、未燃燒完全的碳氫化合物、一氧化碳,以及如今相當受重視的 PM2.5 微粒等等空氣污染,如今在全球減碳風潮下,產生的二氧化碳也遭嚴格檢視,尤其在大量能源已經來自可再生能源的數個歐洲國家,汽車排放成為減碳的最大目標之一,荷蘭執政聯盟中的工黨(Partij van de Arbeid,PvdA),提案要求 2025 年禁止所有汽柴油車,而此動議已經提交眾議院。   在這項動議中,至 2025 年荷蘭將禁用所有燃油車輛,不只是全汽柴油車,連同油電混合車也將禁止,也就是說只剩下車輛本身完全無二氧化碳的純電動車與燃料電池車。除此之外,動議還針對減輕荷蘭的交通阻塞狀況,而要求政府積極推動自動駕駛車輛。   在以燃煤為電力大宗來源的國家中,發展純電動車對減碳並不具效益,因為電動車的電力仍然來自燃煤發電,仍然是間接產生大量二氧化碳,但若是電力已經以可再生能源為主,那麼發展電動車可望減少交通方面的二氧化碳排放量。而氫燃料電池車輛是否減碳,則視氫來源而定,許多工業如石化、造紙等產業可回收產製大量氫,而氫也可以是生質能源,如許多技術能從有機廢棄物或排泄物中製氫,從這些方式得到的氫不僅成本較低,也確實能減少總碳排放量,但若以電力製氫,則也是要看電力來源為何。   以荷蘭來說,其實電力主要仍然來自火力發電,以 2015 年 9 月而言,燃煤發電佔總用電量約 49%,燃氣發電約 31%,而全數可再生能源含風力、太陽能、生質能為 9.7%,雖然較 2014 年的 7.2% 有所提升,但比率仍低,核能則為 3.9 %,此外進口電力 2.9%,大多是來自挪威的水力發電。因此,荷蘭目前若推動全電動車與燃料電池車輛,對減碳的實質助益並不大,須配合電力來源也同時全力轉換為可再生能源。   荷蘭執政聯盟中的另一大黨自由民主人民黨(Volkspartij voor Vrijheid en Democratie,VVD)就對此提案表達反對,表示完全禁止燃油車輛「野心太大、不切實際」,該黨經濟部長認為電動車市佔率最好是 15%,超過這個比率,電力管理可能會有問題,工黨的部分議員也抱怨「看報紙才知道」此項提案。不過,工黨提案議員則反駁批評,表示這項提案是讓人民思考未來如何擺脫汽車排氣管的排放污染的面向之一,一瞥國家未來無限可能的發展想像。   這項提案最終實際通過成為法案的可能性很低,不過出現這樣的提案也顯示,類似想法雖然暫時仍「不切實際」,卻已經有許多人開始考慮,未來在各國電力系統持續現代化,提升可再生能源比率,各種電網技術進步將強化電網調度能力,日後再出現類似提案,實際通過機率將逐漸提升,而汽柴油車到時就得真的開始緊張了。   (本文內容由授權使用;首圖來源:)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

    新北清潔公司,居家、辦公、裝潢細清專業服務

  • 電動車商機蓬勃,兩岸投資兩樣情

    全球電動車市場持續成長,直接刺激鋰電池與電動馬達等相關零組件的需求量。台灣、中國兩岸廠商積極針對電動車進行投資布局,但局勢因策略與市場的不同而有所差異。

    中國投資額高,但潛藏不穩定性

    中國是目前全球電動車市場成長速度最快的國家之一,但今年首季因補貼政策所造成的不確定性,使電動車銷量比去年同期暴跌九成。

    不少中國地方政府將電動車與新能源車列為新興產業投資鼓勵對象,也吸引了大筆投資。據統計,2015年至今,中國大陸各地規劃或已展開建設的新能源汽車建設專案超過30個,總投資額超過人民幣1,000億元,呈現遍地開花的局勢。

    但《經濟日報》引述中國媒體指出,上述專案多以「新能源汽車產業圈」的形式存在,看似投資新能源車,實際上是為了恢復原有的汽車產能。部分電動車生產企業甚至已進入停產狀態,未來若無法改善,可能會被強制退市。

    雖然中國電動車相關投資積極,但卻有泡沫化的隱憂。

    台電池廠投入國際電動車市場

    相較之下,台灣長泓能源科技、宏境科技對電動車產業的佈局較為穩健,且也更為注重其他海外市場。

    長泓能源科技與台灣車廠、客運業者合作,推動電動大巴專案,目標搶下台灣政府10年內投入1萬輛電動大巴的政策。同時,長泓已與特斯拉的移動式20kWh儲能系統、台塑汽車啟動電池等展開測試合作,積極步入電池組裝領域。

    長泓能源科技董事長陳明德表示,公司強化氧化鋰鐵電池的產品性能與應用整合,安全性高,且有機會搶攻中國大陸電動車市場。

    另一方面,宏境科技已取得美國電動沙灘巡邏車電池組的1,000輛訂單,同時與某汽車通路商合作,打入中國大陸NEXT EV油電混和車馬達控制器供應鏈,數量可望超過一萬輛。宏境科技也已取得中瑞電動車每年550輛的動力鋰電池組訂單,每年可貢獻約1億元新台幣營收。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

  • 工信部將調查新能源車騙補 違規或將取消資質

    日前,有媒體報導稱,部分電動車廠和租賃運營公司,以迴圈使用電池組裝配整車方式,以少充多,騙取政府對新能源汽車的大量補貼。高額補貼不僅令一些原本沒有新能源技術儲備的汽車生產企業爭先恐後投入“電動化”,還在銷售環節進行算計。目前工信部等部門已經啟動調查,針對騙取新能源汽車補貼的企業或將面臨吊銷生產資質的嚴厲處罰。

    對此,一位從事動力電池專家王敏(化名)在接受採訪時表示:“這種現象的確存在,靠不正當手法獲得補貼的企業多為小型企業或改裝廠。”
      
    王敏對此解釋稱,一些車企騙取新能源補貼的方式主要有兩種,一是整車企業全資或參股汽車租賃公司,通過“自產自銷”的方式,拿到國家和地方對電動車的補貼;租賃公司購買的車輛並沒有投入運營,但是這些車輛在上牌之後,補貼已經到手。在兩類細分行業,一類是用於共用、租賃的乘用車,一類是用於城市物流的運營類車輛,都有騙補的情況發生。

    另一種方式,則是由一家汽車租賃運營公司主導,一邊採購整車企業,一邊與電池企業合作,通過“多採購整車,少採購電池”的方式,從中獲取補貼。這種方式是通過協力廠商運營公司來暗箱操作,有些車輛運營公司,一手牽著產銷規模甚小的電動車生產企業,一手與動力電池生產企業合作,通過將兩類公司的產品捏合在一起組成電動車,獲得政府補貼,很多車輛“空有牌照”,並沒有真正上路運營。

    根據2015年12月財政部發佈的《關於2016~2020年新能源汽車推廣應用財政支持政策的通知》,純電動、插電式混合動力(含增程式)等專用車、貨車推廣應用補助標準:按電池容量每千瓦時補助1800元。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 工信部與重慶簽訂啟動智慧汽車與智慧交通合作協議

    1月27日,中國工業和資訊化部、重慶市人民政府在重慶簽訂“基於寬頻移動互聯網的智慧汽車與智慧交通應用示範合作框架協定”,將共同推動構建4.5G/5G、智慧汽車與智慧交通融合發展的產業生態。

    根據合作框架協定和建設方案,工業和資訊化部、重慶市人民政府將共同推動構建4.5G/5G、智慧汽車與智慧交通融合發展的產業生態,研發一批智慧汽車與智慧交通關鍵技術和產品,帶動電子資訊、寬頻移動通信、移動互聯網、物聯網、汽車製造等相關產業的發展。

    未來三年,重慶市將逐步由試驗場區封閉環境到城市交通開放環境,加強關於自動駕駛、交通安全、舒適及節能環保、資訊服務及娛樂、交通管理等領域的新技術、新產品研究開發和檢測認證。重慶將在智慧駕駛、智慧路網、綠色用車、防盜追蹤、便捷停車、車與車的資源分享、大範圍交通誘導、交通狀態智慧管理等多個方面進行應用示範。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

    新北清潔公司,居家、辦公、裝潢細清專業服務

  • F-立凱、五龍動力聯手搶攻中國電動車市場

    F-立凱公告將與五龍動力、香港上市公司五龍電動車集團簽訂三方交易契約,共同深化電動車產業的上、下游布局,著眼爭取中國乃至於全球的電動車市場。

    根據協議,三方將以策略聯盟、資本合作的方式取得股權轉換方案。契約載明,五龍動力將以每股新台幣35元的價格取得立凱電新發行的普通股,佔增資後股本21.8%;思慕完成後,五龍電動車集團在另外以1億港幣(約新台幣4.2億)現金取得立凱電旗下車電事業部門──立凱綠能(蓋曼)股權,以及台灣立凱綠能的部分資產。交易完成後,五龍動力與五龍電動車集團預計將投資凱電超過新台幣20億元。

    此外,立凱電同時將以每股0.5元港幣的價格認購五龍電動車集團新發行之430萬普通股與2.75億元港幣的無擔保可轉換公司債,總投資額預計將達港幣4.9億元,並成為五龍電動車集團股東。此舉將幫助立凱電正式邁入中國電動車市場。

    F-立凱由尹衍樑投資,為電動巴士系統與磷酸鐵鋰電池正極材料廠商。與五龍動力、五龍電動車集團的交易完成後,將在兩岸三地與國際市場進行明確產業分工,由立凱電繼續投入正極材料研發、製造與銷售,同時為五龍動力提供LFP-NCO奈米金屬氧化物共晶體化磷酸鋰鐵電池正極材料M系列產品的生產與技術顧問服務。三方也將合作於中國建立材料廠,以因應未來中國電動車龐大的材料需求。

    此外,台灣立凱綠能也將與五龍電動車在電池芯、電池模組以及電動車技術等領域合作,同時不忘繼續拓展台灣電動巴士業務。F-立凱表示,本次策略聯盟,將可幫助F-立凱、五龍動力、五龍電動車集團、立凱電整合技術、製造、市場、供應鏈與資金,全面進軍中國與全球的儲能市場和電動車市場。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

  • SpringBoot 源碼解析 (一)—– SpringBoot核心原理入門

    SpringBoot 源碼解析 (一)—– SpringBoot核心原理入門

    Spring Boot 概述

    Build Anything with Spring Boot:Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring.

    上面是引自官網的一段話,大概是說: Spring Boot 是所有基於 Spring 開發的項目的起點。Spring Boot 的設計是為了讓你盡可能快的跑起來 Spring 應用程序並且盡可能減少你的配置文件。

    什麼是 Spring Boot

    • 它使用 “習慣優於配置” (項目中存在大量的配置,此外還內置一個習慣性的配置,讓你無須手動配置)的理念讓你的項目快速運行起來。
    • 它並不是什麼新的框架,而是默認配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一樣,Spring Boot 整合了所有框架

    使用 Spring Boot 有什麼好處

    回顧我們之前的 SSM 項目,搭建過程還是比較繁瑣的,需要:

    • 1)配置 web.xml,加載 spring 和 spring mvc
    • 2)配置數據庫連接、配置日誌文件
    • 3)配置家在配置文件的讀取,開啟註解
    • 4)配置mapper文件
    • …..

    而使用 Spring Boot 來開發項目則只需要非常少的幾個配置就可以搭建起來一個 Web 項目,並且利用 IDEA 可以自動生成生成

    • 划重點:簡單、快速、方便地搭建項目;對主流開發框架的無配置集成;極大提高了開發、部署效率。

    Spring Boot HelloWorld

    導入依賴spring boot相關的依賴

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>cn.chenhao</groupId>
        <artifactId>springboot</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>springboot</name>
        <description>Demo project for Spring Boot</description>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.1.RELEASE</version>
            <relativePath/>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    編寫主程序

    /**
     * @SpringBootApplication來標註一個主程序類,說明這是一個SpringBoot應用
     */ @SpringBootApplication public class HelloWorldMainApplication {
    
        public static void main(String[] args) {
            //Spring應用啟動
            SpringApplication.run(HelloWorldMainApplication.class, args);
        }
    }

    編寫Controller、Service

    @RestController
    public class HelloController {
    
        @RequestMapping("/hello")
        public String hello(){
            return "Hello world";
        }
    }

    運行主程序測試

    使用maven打包命令將其打包成jar包后,直接使用命令:

    java -jar xxx.jar

    Hello World探究

    POM文件

    父項目

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/>
    </parent>

    其父項目是

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>

    該父項目是真正管理Spring Boot應用裏面的所有依賴的版本:Spring Boot的版本仲裁中心,所以以後導入的依賴默認是不需要版本號。如下

    還有很多版本號沒有截圖出來

    啟動器

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    spring-boot-starter : spring boot場景啟動器;幫助導入web模塊正常運行所依賴的組件;

    ​ Spring Boot將所有的功能場景抽取出來,做成一個個的starter(啟動器),只需要在項目中引入這些starter,那麼相關的場景的所有依賴都會導入進項目中。要用什麼功能就導入什麼場景的啟動器。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>

    添加了 spring-boot-starter-web 依賴,會自動添加 Tomcat 和 Spring MVC 的依賴

    spring-boot-starter-web中又引入了spring-boot-starter-tomcat

    主程序類(主入口類)

    @SpringBootApplication public class HelloWorldMainApplication {
    
        public static void main(String[] args) {
            //Spring應用啟動
            SpringApplication.run(HelloWorldMainApplication.class, args);
        }
    }

    @SpringBootApplication

    • Spring Boot應用標註在某個類上,說明這個類是SpringBoot的主配置類,SpringBoot就應該運行這個類的main方法來啟動SpringBoot應用。

    註解定義如下:

    @SpringBootConfiguration @EnableAutoConfiguration
    @ComponentScan(excludeFilters = {
            @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
            @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {}

    @SpringBootConfiguration

    • Spring Boot的配置類
    • 標註在某個類上,表示這是一個Spring Boot的配置類

    註解定義如下:

    @Configuration public @interface SpringBootConfiguration {}

    其實就是一個Configuration配置類,意思是HelloWorldMainApplication最終會被註冊到Spring容器中

    @EnableAutoConfiguration

    • 開啟自動配置功能
    • 以前使用Spring需要配置的信息,Spring Boot幫助自動配置;
    • @EnableAutoConfiguration通知SpringBoot開啟自動配置功能,這樣自動配置才能生效。

    註解定義如下:

    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}

    @AutoConfigurationPackage

    • 自動配置包註解
    @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage {}

    @Import(AutoConfigurationPackages.Registrar.class):默認將主配置類(
    @SpringBootApplication)所在的包及其子包裏面的所有組件掃描到Spring容器中。如下

    @Order(Ordered.HIGHEST_PRECEDENCE)
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata,
                BeanDefinitionRegistry registry) {
              //默認將會掃描@SpringBootApplication標註的主配置類所在的包及其子包下所有組件
            register(registry, new PackageImport(metadata).getPackageName());
        }
    
        @Override
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.<Object>singleton(new PackageImport(metadata));
        }
    }

    @Import(EnableAutoConfigurationImportSelector.class)

    EnableAutoConfigurationImportSelector: 導入哪些組件的選擇器,將所有需要導入的組件以全類名的方式返回,這些組件就會被添加到容器中。

     1 //EnableAutoConfigurationImportSelector的父類:AutoConfigurationImportSelector
     2 @Override
     3 public String[] selectImports(AnnotationMetadata annotationMetadata) {
     4     if (!isEnabled(annotationMetadata)) {
     5         return NO_IMPORTS;
     6     }
     7     try {
     8         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
     9             .loadMetadata(this.beanClassLoader);
    10         AnnotationAttributes attributes = getAttributes(annotationMetadata);
    11         List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); 12         configurations = removeDuplicates(configurations);
    13         configurations = sort(configurations, autoConfigurationMetadata);
    14         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    15         checkExcludedClasses(configurations, exclusions);
    16         configurations.removeAll(exclusions);
    17         configurations = filter(configurations, autoConfigurationMetadata);
    18         fireAutoConfigurationImportEvents(configurations, exclusions);
    19         return configurations.toArray(new String[configurations.size()]);
    20     }
    21     catch (IOException ex) {
    22         throw new IllegalStateException(ex);
    23     }
    24 }

    我們主要看第11行List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);會給容器中注入眾多的自動配置類(xxxAutoConfiguration),就是給容器中導入這個場景需要的所有組件,並配置好這些組件。我們跟進去看看

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        //...
        return configurations;
    }
    
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }
    
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
            //從類路徑的META-INF/spring.factories中加載所有默認的自動配置類
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                                     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                //獲取EnableAutoConfiguration指定的所有值,也就是EnableAutoConfiguration.class的值
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }

    SpringBoot啟動的時候從類路徑下的
    META-INF/spring.factories中獲取EnableAutoConfiguration指定的值,並將這些值作為自動配置類導入到容器中,自動配置類就會生效,最後完成自動配置工作。EnableAutoConfiguration默認在spring-boot-autoconfigure這個包中,如下圖

    最終有96個自動配置類被加載並註冊進Spring容器中

    J2EE的整體整合解決方案和自動配置都在spring-boot-autoconfigure-xxx.jar中。在這些自動配置類中會通過@ConditionalOnClass等條件註解判斷是否導入了某些依賴包,從而通過@Bean註冊相應的對象進行自動配置。後面我們會有單獨文章講自動配置的內容

     

     

     

     

     

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

  • Elastic Stack 開源的大數據解決方案

    Elastic Stack 開源的大數據解決方案

    目的

    本文主要介紹的內容有以下三點:
    一. Elastic Stack是什麼以及組成部分
    二. Elastic Stack前景以及業務應用
    三. Elasticsearch原理(索引方向)
    四. Elasticsearch相對薄弱的地方

    一、Elastic Stack是什麼以及組成部分

    介紹Elastic Stack是什麼,其實只要一句話就可以,就是: 一套完整的大數據處理堆棧,從攝入、轉換到存儲分析、可視化

    它是不同產品的集合,各司其職,形成完整的數據處理鏈,因此Elastic Stack也可以簡稱為BLEK。

    Beats 輕量型數據採集器

    Logstash 輸入、過濾器和輸出

    Elasticsearch 查詢和分析

    Kibana 可視化,可自由選擇如何呈現數據

    1. Beats – 全品類採集器,搞定所有數據類型

    Filebeat(日誌文件):對成百上千、甚至上萬的服務器生成的日誌匯總,可搜索。

    Metricbeat(指標): 收集系統和服務指標,CPU 使用率、內存、文件系統、磁盤 IO 和網絡 IO 統計數據。

    Packetbeat(網絡數據):網絡數據包分析器,了解應用程序動態。

    Heartbeat(運行時間監控):通過主動探測來監測服務的可用性
    ……
    Beats支持許許多多的beat,這裏列的都是比較的常用的beat,了解更多可以點擊鏈接:

    2. Logstash – 服務器端數據處理管道

    介紹Logstash之前,我們先來看下Linux下常用的幾個命令

    cat alldata.txt | awk ‘{print $1}’ | sort | uniq | tee filterdata.txt

    只要接觸過Linux同學,應該都知道這幾個命名意思

    cat alldata.txt #將alldata.txt的內容輸出到標準設備上
    awk ‘{print $1}’ #對上面的內容做截取,只取每一行第一列數據
    sort | uniq  #對截取后的內容,進行排序和唯一性操作
    tee filterdata.txt #將上面的內容寫到filterdata.txt

    上面的幾個簡單的命令就可以看出來,這是對數據進行了常規的處理,用名詞修飾的話就是:數據獲取/輸入數據清洗數據過濾數據寫入/輸出

    而Logstash做的也是相同的事(看下圖)。

    將系統的日誌文件、應用日誌文件、系統指標等數據,輸入到Input,再通過數據清洗以及過濾,輸入到存儲設備中,這裏當然是輸入到Elasticsearch

    3. Elasticsearch – 分佈式文檔存儲、RESTful風格的搜索和數據分析引擎

    Elasticsearch主要也是最原始的功能就是搜索和分析功能。這裏就簡單說一下,下面講原理的時候會着重講到Elasticsearch

    搜索:全文搜索,完整的信息源轉化為計算機可以識別、處理的信息單元形成的數據集合 。

    分析:相關度,搜索所有內容,找到所需的具體信息(詞頻或熱度等對結果排序)

    4. Kibana- 可視化

    可視化看下圖(來源官網)便知

    可以對日誌分析、業務分析等做可視化

    現在從總體上來了解下,在心中對Elastic Stack有個清楚的認知(下圖)。

    二、Elastic Stack前景以及業務應用

    1. DB-Engines 排名

    Elasticsearch是Elastic Stack核心,由圖可以看出在搜索領域Elasticsearch暫時沒有對手。

    2. ES社區

    ES中文社區也是相當活躍的,會定期做一下分享,都是大公司的寶貴經驗,值得參考。

    3. 2018年攜程的使用情況(讓我們看看能處理多大的數據)

    集群數量是94個,最小的集群一般是3個節點。全部節點數量大概700+。

    最大的一個集群是做日誌分析的,其中數據節點330個,最高峰一天產生1600億文檔,寫入值300w/s。

    現在有2.5萬億文檔,大概是幾個PB的量

    三、Elasticsearch(ES)原理

    因為篇目有限,本篇只介紹ES的索引原理。

    ES為什麼可以做全文搜索,主要就是用了倒排索引,先來看下面的一張圖

    看圖可以簡單的理解倒排索引就是:關鍵字 + 頁碼

    對倒排索引有個基本的認識后,下面來做個簡單的數據例子。

    現在對Name做到排索引,記住:關鍵字 + ID(頁碼)。

    對Age做到排索引。

    對Intersets做到排索引。

    現在搜索Age等於18的,通過倒排索引就可以快速得到1和3的id,再通過id就可以得到具體數據,看,這樣是不是快的狠。

    如果是用Mysql等關係數據庫,現在有十多億數據(大數據嘛),就要一條一條的掃描下去找id,效率可想而知。而用倒排索引,找到所有的id就輕輕鬆鬆了。

    在ES中,關鍵詞叫Term,頁碼叫Posting List。

    但這樣就行了嗎? 如果Name有上億個Term,要找最後一個Term,效率豈不是還是很低?

    再來看Name的倒排索引,你會發現,將Armani放在了第一個,Tyloo放在了第三個,可以看出來,對Term做了簡單的排序。雖然簡單,但很實用。這樣查找Term就可以用二分查找法來查找了,將複雜度由n變成了logn。

    在ES中,這叫Term Dictionary。

    到這裏,再來想想MySQL的b+tree, 你有沒有發現原理是差不多的,那為什麼說ES搜索比MySQL快很多,究竟快在哪裡? 接下來再看。

    有一種數據結構叫Trie樹,又稱前綴樹或字典樹,是一種有序樹。這種數據結構的好處就是可以壓縮前綴和提高查詢數據。

    現在有這麼一組Term: apps, apple, apply, appear, back, backup, base, bear,用Trie樹表示如下圖。

    通過線路路徑字符連接就可以得到完成的Term,並且合用了前綴,比如apps, apple, apply, appear合用了app路徑,節省了大量空間。

    這個時候再來找base單詞,立即就可以排除了a字符開頭的單詞,比Term Dictionary快了不知多少。

    在ES中,這叫Term Index

    現在我們再從整體看下ES的索引

    先通過Trie樹快速定位block(相當於頁碼), 再到Term Dictionary 做二分查找,得到Posting List。

    索引優化

    ES是為了大數據而生的,這意味着ES要處理大量的數據,它的Term數據量也是不可想象的。比如一篇文章,要做全文索引,就會對全篇的內容做分詞,會產生大量的Term,而ES查詢的時候,這些Term肯定要放在內存裏面的。

    雖然Trie樹對前綴做了壓縮,但在大量Term面前還是不夠,會佔用大量的內存使用,於是就有ES對Trie樹進一步演化。

    FST(Finite State Transducer )確定無環有限狀態轉移器 (看下圖)

    可以看appear、bear 對共同的後綴做了壓縮。

    Posting List磁盤壓縮

    假設有一億的用戶數據,現在對性別做搜索,而性別無非兩種,可能”男”就有五千萬之多,按int4個字節存儲,就要消耗50M左右的磁盤空間,而這僅僅是其中一個Term。

    那麼面對成千上萬的Term,ES究竟是怎麼存儲的呢?接下來,就來看看ES的壓縮方法。

    Frame Of Reference (FOR) 增量編碼壓縮,將大數變小數,按字節存儲

    只要能把握“增量,大數變小數,按字節存儲”這幾個關鍵詞,這個算法就很好理解,現在來具體看看。

    現在有一組Posting List:[60, 150, 300,310, 315, 340], 按正常的int型存儲,size = 6 * 4(24)個字節。

    1. 按增量存儲:60 + 90(150)+ 150(300) + 10(310) + 5(315)+ 25(340),也就是[60, 90, 150, 10, 5, 25],這樣就將大數變成了小數。

    2. 切分成不同的block:[60, 90, 150]、[10, 5, 25],為什麼要切分,下面講。

    3. 按字節存儲:對於[60, 90, 150]這組block,究竟怎麼按字節存儲,其實很簡單,就是找其中最大的一個值,看X個比特能表示這個最大的數,那麼剩下的數也用X個比特表示(切分,可以盡可能的壓縮空間)。

    [60, 90, 150]最大數150 < 2^8 = 256,也就是這組每個數都用8個比特表示,也就是 3*8 = 24個比特,再除以8,也就是3個字節存在,再加上一個8的標識位(說明每個數是8個比特存儲),佔用一個字節,一共4個字節。

    [10, 5, 25]最大數25 < 2^5 = 32,每個數用5個比特表示,3*5=15比特,除以8,大約2個字節,加上5的標識位,一共3個字節。

    那麼總體size = 4 + 3(7)個字節,相當於24個字節,大大壓縮了空間。

    再看下圖表示

    Posting List內存壓縮

    同學們應該都知道越複雜的算法消耗的CPU性能就越大,比如常見的https,第一次交互會用非對稱密碼來驗證,驗證通過後就轉變成了對稱密碼驗證,FOR同樣如此,那麼ES是用什麼算法壓縮內存中的Posting List呢?

    Roaring Bitmaps 壓縮位圖索引

    Roaring Bitmaps 涉及到兩種數據結構 short[] 、bitmap。

    short好理解就是2個字節的整型。

    bitmap就是用比特表示數據,看下面的例子。

    Posting List:[1, 2, 4, 7, 10] -> [1, 1, 0, 1, 0, 0, 1,0, 0, 1],取最大的值10,那麼就用10個比特表示這組Posting List,第1, 2, 4, 7, 10位存在,就將相對應的“位”置為1,其他的為0。

    但這種bitmap數據結構有缺陷,看這組Posting List: [1, 3, 100000000] -> [1, 0, 1, 0, 0, 0, …, 0, 0, 1 ],最大數是1億,就要1億的比特表示,這麼算下來,反而消耗了更多的內存。

    那如何解決這個問題,其實也很簡單,跟上面一樣,將大數變成小數

    看下圖:

    第一步:將每個數除以65536,得到(商,餘數)。

    第二步:按照商,分成不同的block,也就是相同的商,放在同一個block裏面,餘數就是這個值在這個block裏面的位置(永遠不會超過65536,餘數嘛)。

    第三步:判斷底層block用什麼數據結構存儲數據,如果block裏面的餘數的個數超過4096個,就用short存儲,反之bitmap。

    上面那個圖是官網的圖,看下我畫的圖,可能更好理解些。

    到這裏,ES的索引原理就講完了,希望大家都能理解。

    四、Elasticsearch(ES)相對薄弱的地方

    1. 多表關聯

    其實ES有一個很重要的特性這裏沒有介紹到,也就是分佈式,每一個節點的數據和,才是整體數據。

    這也導致了多表關聯問題,雖然ES裏面也提供了Nested& Join 方法解決這個問題,但這裏還是不建議用。

    那這個問題在實際應用中應該如何解決? 其實也很簡單,裝換思路,ES無法解決,就到其他層解決,比如:應用層,用面向對象的架構,拆分查詢。

    2. 深度分頁

    分佈式架構下,取數據便不是那麼簡單,比如取前1000條數據,如果是10個節點,那麼每個節點都要取1000條,10個節點就是10000條,排序后,返回前1000條,如果是深度分頁就會變的相當的慢。

    ES提供的是Scroll + Scroll_after,但這個採取的是緩存的方式,取出10000條后,緩存在內存里,再來翻頁的時候,直接從緩存中取,這就代表着存在實時性問題。

    來看看百度是怎麼解決這個問題的。

    一樣在應用層解決,翻頁到一定的深度后,禁止翻頁。

    3. 更新應用

    頻繁更新的應用,用ES會有瓶頸,比如一些遊戲應用,要不斷的更新數據,用ES不是太適合,這個看大家自己的應用情況。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • Java 8 Streams API 詳解

    Java 8 Streams API 詳解

    流式編程作為Java 8的亮點之一,是繼Java 5之後對集合的再一次升級,可以說Java 8幾大特性中,Streams API 是作為Java 函數式的主角來設計的,誇張的說,有了Streams API之後,萬物皆可一行代碼。

    什麼是Stream

    Stream被翻譯為流,它的工作過程像將一瓶水導入有很多過濾閥的管道一樣,水每經過一個過濾閥,便被操作一次,比如過濾,轉換等,最後管道的另外一頭有一個容器負責接收剩下的水。

    示意圖如下:

    首先通過source產生流,然後依次通過一些中間操作,比如過濾,轉換,限制等,最後結束對流的操作。

    Stream也可以理解為一個更加高級的迭代器,主要的作用便是遍歷其中每一個元素。

    為什麼需要Stream

    Stream作為Java 8的一大亮點,它專門針對集合的各種操作提供各種非常便利,簡單,高效的API,Stream API主要是通過Lambda表達式完成,極大的提高了程序的效率和可讀性,同時Stram API中自帶的并行流使得併發處理集合的門檻再次降低,使用Stream API編程無需多寫一行多線程的大門就可以非常方便的寫出高性能的併發程序。使用Stream API能夠使你的代碼更加優雅。

    流的另一特點是可無限性,使用Stream,你的數據源可以是無限大的。

    在沒有Stream之前,我們想提取出所有年齡大於18的學生,我們需要這樣做:

    List<Student> result=new ArrayList<>();
    for(Student student:students){
     
        if(student.getAge()>18){
            result.add(student);
        }
    }
    return result;

    使用Stream,我們可以參照上面的流程示意圖來做,首先產生Stream,然後filter過濾,最後歸併到容器中。

    轉換為代碼如下:

    return students.stream().filter(s->s.getAge()>18).collect(Collectors.toList());
    • 首先stream()獲得流
    • 然後filter(s->s.getAge()>18)過濾
    • 最後collect(Collectors.toList())歸併到容器中

    是不是很像在寫sql?

    如何使用Stream

    我們可以發現,當我們使用一個流的時候,主要包括三個步驟:

    • 獲取流
    • 對流進行操作
    • 結束對流的操作

    獲取流

    獲取流的方式有多種,對於常見的容器(Collection)可以直接.stream()獲取
    例如:

    • Collection.stream()
    • Collection.parallelStream()
    • Arrays.stream(T array) or Stream.of()

    對於IO,我們也可以通過lines()方法獲取流:

    • java.nio.file.Files.walk()
    • java.io.BufferedReader.lines()

    最後,我們還可以從無限大的數據源中產生流:

    • Random.ints()

    值得注意的是,JDK中針對基本數據類型的昂貴的裝箱和拆箱操作,提供了基本數據類型的流:

    • IntStream
    • LongStream
    • DoubleStream

    這三種基本數據類型和普通流差不多,不過他們流裏面的數據都是指定的基本數據類型。

    Intstream.of(new int[]{1,2,3});
    Intstream.rang(1,3);

    對流進行操作

    這是本章的重點,產生流比較容易,但是不同的業務系統的需求會涉及到很多不同的要求,明白我們能對流做什麼,怎麼做,才能更好的利用Stream API的特點。

    流的操作類型分為兩種:

    • Intermediate:中間操作,一個流可以後面跟隨零個或多個intermediate操作。其目的主要是打開流,做出某種程度的數據映射/過濾,然後會返回一個新的流,交給下一個操作使用。這類操作都是惰性化的(lazy),就是說,僅僅調用到這類方法,並沒有真正開始流的遍歷。

      map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

    • Terminal:終結操作,一個流只能有一個terminal操作,當這個操作執行后,流就被使用“光”了,無法再被操作。所以這必定是流的最後一個操作。Terminal操作的執行,才會真正開始流的遍歷,並且會生成一個結果,或者一個 side effect。

      forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

    IntermediateTerminal完全可以按照上圖的流程圖理解,Intermediate表示在管道中間的過濾器,水會流入過濾器,然後再流出去,而Terminal操作便是最後一個過濾器,它在管道的最後面,流入Terminal的水,最後便會流出管道。

    下面依次詳細的解讀下每一個操作所能產生的效果:

    中間操作

    對於中間操作,所有的API的返回值基本都是Stream<T>,因此以後看見一個陌生的API也能通過返回值判斷它的所屬類型。

    map/flatMap

    map顧名思義,就是映射,map操作能夠將流中的每一個元素映射為另外的元素。

     <R> Stream<R> map(Function<? super T, ? extends R> mapper);

    可以看到map接受的是一個Function,也就是接收參數,並返回一個值。

    比如:

    //提取 List<Student>  所有student 的名字 
    List<String> studentNames = students.stream().map(Student::getName)
                                                 .collect(Collectors.toList());

    上面的代碼等同於以前的:

    List<String> studentNames=new ArrayList<>();
    for(Student student:students){
        studentNames.add(student.getName());
    }

    再比如:將List中所有字母轉換為大寫:

    List<String> words=Arrays.asList("a","b","c");
    List<String> upperWords=words.stream().map(String::toUpperCase)
                                          .collect(Collectors.toList());

    flatMap顧名思義就是扁平化映射,它具體的操作是將多個stream連接成一個stream,這個操作是針對類似多維數組的,比如容器裡面包含容器等。

    List<List<Integer>> ints=new ArrayList<>(Arrays.asList(Arrays.asList(1,2),
                                              Arrays.asList(3,4,5)));
    List<Integer> flatInts=ints.stream().flatMap(Collection::stream).
                                           collect(Collectors.toList());

    可以看到,相當於降維。

    filter

    filter顧名思義,就是過濾,通過測試的元素會被留下來並生成一個新的Stream

    Stream<T> filter(Predicate<? super T> predicate);

    同理,我們可以filter接收的參數是Predicate,也就是推斷型函數式接口,接收參數,並返回boolean值。

    比如:

    //獲取所有大於18歲的學生
    List<Student> studentNames = students.stream().filter(s->s.getAge()>18)
                                                  .collect(Collectors.toList());

    distinct

    distinct是去重操作,它沒有參數

      Stream<T> distinct();

    sorted

    sorted排序操作,默認是從小到大排列,sorted方法包含一個重載,使用sorted方法,如果沒有傳遞參數,那麼流中的元素就需要實現Comparable<T>方法,也可以在使用sorted方法的時候傳入一個Comparator<T>

    Stream<T> sorted(Comparator<? super T> comparator);
    
    Stream<T> sorted();

    值得一說的是這個ComparatorJava 8之後被打上了@FunctionalInterface,其他方法都提供了default實現,因此我們可以在sort中使用Lambda表達式

    例如:

    //以年齡排序
    students.stream().sorted((s,o)->Integer.compare(s.getAge(),o.getAge()))
                                      .forEach(System.out::println);;

    然而還有更方便的,Comparator默認也提供了實現好的方法引用,使得我們更加方便的使用:

    例如上面的代碼可以改成如下:

    //以年齡排序 
    students.stream().sorted(Comparator.comparingInt(Student::getAge))
                                .forEach(System.out::println);;

    或者:

    //以姓名排序
    students.stream().sorted(Comparator.comparing(Student::getName)).
                              forEach(System.out::println);

    是不是更加簡潔。

    peek

    peek有遍歷的意思,和forEach一樣,但是它是一个中間操作。

    peek接受一個消費型的函數式接口。

    Stream<T> peek(Consumer<? super T> action);

    例如:

    //去重以後打印出來,然後再歸併為List
    List<Student> sortedStudents= students.stream().distinct().peek(System.out::println).
                                                    collect(Collectors.toList());

    limit

    limit裁剪操作,和String::subString(0,x)有點先溝通,limit接受一個long類型參數,通過limit之後的元素只會剩下min(n,size)個元素,n表示參數,size表示流中元素個數

     Stream<T> limit(long maxSize);

    例如:

    //只留下前6個元素並打印
    students.stream().limit(6).forEach(System.out::println);

    skip

    skip表示跳過多少個元素,和limit比較像,不過limit是保留前面的元素,skip是保留後面的元素

    Stream<T> skip(long n);

    例如:

    //跳過前3個元素並打印 
    students.stream().skip(3).forEach(System.out::println);

    終結操作

    一個流處理中,有且只能有一個終結操作,通過終結操作之後,流才真正被處理,終結操作一般都返回其他的類型而不再是一個流,一般來說,終結操作都是將其轉換為一個容器。

    forEach

    forEach是終結操作的遍歷,操作和peek一樣,但是forEach之後就不會再返迴流

     void forEach(Consumer<? super T> action);

    例如:

    //遍歷打印
    students.stream().forEach(System.out::println);

    上面的代碼和一下代碼效果相同:

    for(Student student:students){
        System.out.println(sudents);
    }

    toArray

    toArrayList##toArray()用法差不多,包含一個重載。

    默認的toArray()返回一個Object[]

    也可以傳入一個IntFunction<A[]> generator指定數據類型

    一般建議第二種方式。

    Object[] toArray();
    
    <A> A[] toArray(IntFunction<A[]> generator);

    例如:

     Student[] studentArray = students.stream().skip(3).toArray(Student[]::new);

    max/min

    max/min即使找出最大或者最小的元素。max/min必須傳入一個Comparator

    Optional<T> min(Comparator<? super T> comparator);
    
    Optional<T> max(Comparator<? super T> comparator);

    count

    count返迴流中的元素數量

    long count();

    例如:

    long  count = students.stream().skip(3).count();

    reduce

    reduce為歸納操作,主要是將流中各個元素結合起來,它需要提供一個起始值,然後按一定規則進行運算,比如相加等,它接收一個二元操作 BinaryOperator函數式接口。從某種意義上來說,sum,min,max,average都是特殊的reduce

    reduce包含三個重載:

    T reduce(T identity, BinaryOperator<T> accumulator);
    
    Optional<T> reduce(BinaryOperator<T> accumulator);
    
     <U> U reduce(U identity,
                     BiFunction<U, ? super T, U> accumulator,
                     BinaryOperator<U> combiner);

    例如:

    List<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
            
    long count = integers.stream().reduce(0,(x,y)->x+y);

    以上代碼等同於:

    long count = integers.stream().reduce(Integer::sum).get();

    reduce兩個參數和一個參數的區別在於有沒有提供一個起始值,

    如果提供了起始值,則可以返回一個確定的值,如果沒有提供起始值,則返回Opeational防止流中沒有足夠的元素。

    anyMatch allMatch noneMatch

    測試是否有任意元素\所有元素\沒有元素匹配表達式

    他們都接收一個推斷類型的函數式接口:Predicate

     boolean anyMatch(Predicate<? super T> predicate);
    
     boolean allMatch(Predicate<? super T> predicate);
    
     boolean noneMatch(Predicate<? super T> predicate)

    例如:

     boolean test = integers.stream().anyMatch(x->x>3);

    findFirst、 findAny

    獲取元素,這兩個API都不接受任何參數,findFirt返迴流中第一個元素,findAny返迴流中任意一個元素。

    Optional<T> findFirst();
    
    Optional<T> findAny();

    也有有人會問findAny()這麼奇怪的操作誰會用?這個API主要是為了在并行條件下想要獲取任意元素,以最大性能獲取任意元素

    例如:

    int foo = integers.stream().findAny().get();

    collect

    collect收集操作,這個API放在後面將是因為它太重要了,基本上所有的流操作最後都會使用它。

    我們先看collect的定義:

     <R> R collect(Supplier<R> supplier,
                      BiConsumer<R, ? super T> accumulator,
                      BiConsumer<R, R> combiner);
    
    <R, A> R collect(Collector<? super T, A, R> collector);

    可以看到,collect包含兩個重載:

    一個參數和三個參數,

    三個參數我們很少使用,因為JDK提供了足夠我們使用的Collector供我們直接使用,我們可以簡單了解下這三個參數什麼意思:

    • Supplier:用於產生最後存放元素的容器的生產者
    • accumulator:將元素添加到容器中的方法
    • combiner:將分段元素全部添加到容器中的方法

    前兩個元素我們都很好理解,第三個元素是幹嘛的呢?因為流提供了并行操作,因此有可能一個流被多個線程分別添加,然後再將各個子列表依次添加到最終的容器中。

    ↓ – – – – – – – – –

    ↓ — — —

    ↓ ———

    如上圖,分而治之。

    例如:

    List<String> result = stream.collect(ArrayList::new, List::add, List::addAll);

    接下來看只有一個參數的collect

    一般來說,只有一個參數的collect,我們都直接傳入Collectors中的方法引用即可:

    List<Integer> = integers.stream().collect(Collectors.toList());

    Collectors中包含很多常用的轉換器。toList(),toSet()等。

    Collectors中還包括一個groupBy(),他和Sql中的groupBy一樣都是分組,返回一個Map

    例如:

    //按學生年齡分組
    Map<Integer,List<Student>> map= students.stream().
                                    collect(Collectors.groupingBy(Student::getAge));

    groupingBy可以接受3個參數,分別是

    1. 第一個參數:分組按照什麼分類
    2. 第二個參數:分組最後用什麼容器保存返回(當只有兩個參數是,此參數默認為HashMap
    3. 第三個參數:按照第一個參數分類后,對應的分類的結果如何收集

    有時候單參數的groupingBy不滿足我們需求的時候,我們可以使用多個參數的groupingBy

    例如:

    //將學生以年齡分組,每組中只存學生的名字而不是對象
    Map<Integer,List<String>> map =  students.stream().
      collect(Collectors.groupingBy(Student::getAge,Collectors.mapping(Student::getName,Collectors.toList())));

    toList默認生成的是ArrayList,toSet默認生成的是HashSet,如果想要指定其他容器,可以如下操作:

     students.stream().collect(Collectors.toCollection(TreeSet::new));

    Collectors還包含一個toMap,利用這個API我們可以將List轉換為Map

      Map<Integer,Student> map=students.stream().
                               collect(Collectors.toMap(Student::getAge,s->s));
    

    值得注意的一點是,IntStreamLongStream,DoubleStream是沒有collect()方法的,因為對於基本數據類型,要進行裝箱,拆箱操作,SDK並沒有將它放入流中,對於基本數據類型流,我們只能將其toArray()

    優雅的使用Stream

    了解了Stream API,下面詳細介紹一下如果優雅的使用Steam

    • 了解流的惰性操作

      前面說到,流的中間操作是惰性的,如果一個流操作流程中只有中間操作,沒有終結操作,那麼這個流什麼都不會做,整個流程中會一直等到遇到終結操作操作才會真正的開始執行。

      例如:

      students.stream().peek(System.out::println);

      這樣的流操作只有中間操作,沒有終結操作,那麼不管流裡面包含多少元素,他都不會執行任何操作。

    • 明白流操作的順序的重要性

      Stream API中,還包括一類Short-circuiting,它能夠改變流中元素的數量,一般這類API如果是中間操作,最好寫在靠前位置:

      考慮下面兩行代碼:

      students.stream().sorted(Comparator.comparingInt(Student::getAge)).
                        peek(System.out::println).
                        limit(3).              
                        collect(Collectors.toList());
      students.stream().limit(3).
                        sorted(Comparator.comparingInt(Student::getAge)).
                        peek(System.out::println).
                        collect(Collectors.toList());

      兩段代碼所使用的API都是相同的,但是由於順序不同,帶來的結果都非常不一樣的,

      第一段代碼會先排序所有的元素,再依次打印一遍,最後獲取前三個最小的放入list中,

      第二段代碼會先截取前3個元素,在對這三個元素排序,然後遍歷打印,最後放入list中。

    • 明白Lambda的局限性

      由於Java目前只能Pass-by-value,因此對於Lambda也和有匿名類一樣的final的局限性。

      具體原因可以參考

      因此我們無法再lambda表達式中修改外部元素的值。

      同時,在Stream中,我們無法使用break提前返回。

    • 合理編排Stream的代碼格式

      由於可能在使用流式編程的時候會處理很多的業務邏輯,導致API非常長,此時最後使用換行將各個操作分離開來,使得代碼更加易讀。

      例如:

      students.stream().limit(3).
                        sorted(Comparator.comparingInt(Student::getAge)).
                        peek(System.out::println).
                        collect(Collectors.toList());

      而不是:

      students.stream().limit(3).sorted(Comparator.comparingInt(Student::getAge)).peek(System.out::println).collect(Collectors.toList());

      同時由於Lambda表達式省略了參數類型,因此對於變量,盡量使用完成的名詞,比如student而不是s,增加代碼的可讀性。

      盡量寫出敢在代碼註釋上留下你的名字的代碼!

    總結

    總之,Stream是Java 8 提供的簡化代碼的神器,合理使用它,能讓你的代碼更加優雅。

    尊重勞動成功,轉載註明出處

    參考鏈接:

    《Effective Java》3th

    如果覺得寫得不錯,歡迎關注微信公眾號:逸游Java ,每天不定時發布一些有關Java乾貨的文章,感謝關注

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

    ※評比南投搬家公司費用收費行情懶人包大公開

  • 取道對歐輸送天然氣 俄烏達成初步協議

    摘錄自2019年12月20日中央社報導

    俄羅斯天然氣工業公司2019年向歐洲供應2008億立方公尺的天然氣,其中有約40%是借道烏克蘭運送,讓烏克蘭每年賺得約30億美元(約新台幣904億元)的過境費,此輸送合約將於年底到期,但自莫斯科2014年併吞克里米亞並支持烏克蘭東部的分離主義分子叛亂活動後,雙方關係急轉直下。

    俄羅斯與烏克蘭歷經數個月的艱難談判,在即將到來的新年截止期限前,簽署取道烏克蘭將俄羅斯天然氣運往歐洲的初步協議。

    俄羅斯通訊社引述俄羅斯天然氣工業公司(Gazprom)發言人說法報導:「俄羅斯與烏克蘭已經簽署諒解備忘錄。」但沒有提供合約細節。法新社報導,俄羅斯能源部長諾瓦克(Alexander Novak)說,這是5年合約,將在月底前簽署。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

  • 築起和平之牆 修復河壩 達佛「氣候變遷戰爭」平息有望

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!