IDEA Git操作(三)使用 cherry-pick、交互式 rebase 自由修改提交树
說明
本教程按照?git在線練習?順序進行,將在線測試的命令操作落地到 IDEA,使用開發工具來實現所有在線練習中的操作。
你可以結合?git在線練習?來學習本教程,先在線學習git命令,再在 IDEA 中實現相同操作。
?
cherry-pick
?
準備提交結構
?
- 切換到 master,并重置到第二次提交
- 刪除 pushed 和 local 分支
新建 bugFix、side 和 another 分支
- 對bugFix、side和another分支,分別做兩次提交
- 切換到 master
上面的提交歷史對照?learngitbranching.js.org?的結構圖
cherry-pick bufFix 2、side 1和another 2三個提交到 master 分支
選中這三個提交
右鍵選擇 cherry-pick
如果出現代碼合并提示,選擇 merge,將 bufFix 2 提交的代碼合并到 master 的代碼
按照正確代碼邏輯,向中間合并代碼
完成后,生成了一個新的提交
接下來,按照相同的操作,完成 side 1 和 another 2 的代碼合并操作,同樣也會生成兩個新的提交
上面的提交歷史對照?learngitbranching.js.org?的結構圖
交互式 rebase
?
準備提交結構
?
- 重置master到第二次提交
- 刪除 bugFix、side 和 another 分支
- 做四次提交
上面的提交歷史對照?learngitbranching.js.org?的結構圖
用交互式 rebase 操作自由調整提交
在 master 分支,右鍵點擊 “添加打印3”,選擇交互式 rebase
在交互界面中,丟棄“添加打印3”
向上移動一步 “添加打印6”
查看將要執行的命令
在這里看到,會按以下順序執行:
點擊開始執行 rebase 操作
?
過程中可能會出現3次合并代碼的操作提示,可以按照三步的順序,合并三句打印代碼
上面的提交歷史對照?learngitbranching.js.org?的結構圖
用交互 rebase 將 4,6,5 壓縮成一個分支
learngitbranching.js.org?中略過了壓縮分支的操作
右鍵點擊“添加打印4”的提交,執行交互式 rebase
將 5 和 6 設置為 Fixup
設置完的狀態如下
rebase 完成后,三次提交被壓縮為一次提交
筆記匯總目錄
Spring Cloud 微服務
Spring Cloud入門操作手冊(Hoxton)
?
RabbitMQ
RabbitMQ
RabbitMQ - Spring boot 整合
Lucene Solr
Lucene Solr 811
?
Docker
Docker
Docker案例
?
Kubernetes
Kubernetes
k8s部署Spring Cloud應用
?
分布式事務
分布式事務(一)Mysql本地事務和事務隔離級別
分布式事務(二)分布式事務方案
分布式事務(三)Seata分布式事務框架-AT模式介紹
分布式事務(四)Seata AT模式-Spring Cloud微服務案例
分布式事務(五)Seata AT模式-Spring Cloud微服務添加 AT 分布式事務
分布式事務(六)Seata TCC模式-TCC模式介紹
分布式事務(七)Seata TCC模式-Spring Cloud微服務添加 TCC 分布式事務
分布式事務(八)Spring Cloud微服務系統基于Rocketmq可靠消息最終一致性實現分布式事務
?
RocketMQ
RocketMQ (一) 安裝
RocketMQ (二) 雙主雙從同步復制集群方案
RocketMQ (三) 基本原理
RocketMQ (四) 使用RocketMQ原生API收發消息代碼樣例
RocketMQ (五) Springboot 整合 RocketMQ 收發消息樣例
RocketMQ 發送事務消息原理分析和代碼實現
Java基礎
java編程基礎(一)二進制
java編程基礎(二)位運算符
java編程基礎(三)冒泡排序
java編程基礎(四)選擇排序
java編程基礎(五)二分法查找
java編程基礎(六)遞歸
2006
就業
簡歷:自我介紹: 接收短期或長期出差, 接收高強度加班抗壓能力極強
項目:
自研項目: 主題一致,
外包:
人力:類型一致
項目:類型一致
國企:
復習
1.做題,打樁: Java面試寶典,碼出高效
2.mysql(多表聯查)\servlet()SSM(圖)
3.SSM(圖) shiro
4.jt業務 redis ( 是什么, 在項目里解決什么問題, ) \Nginx\Mycat\SSO\zookeeper\dubbo
5.cloud mq 分布式事務
課程安排
大數據
指海量數據及其處理方式
大數據(big data),IT行業術語,是指無法在一定時間范圍內用常規軟件工具進行捕捉、管理和處理的數據集合,是需要新處理模式才能具有更強的決策力、洞察發現力和流程優化能力的海量、高增長率和多樣化的信息資產。
在維克托·邁爾-舍恩伯格及肯尼斯·庫克耶編寫的《大數據時代》 [1] 中大數據指不用隨機分析法(抽樣調查)這樣捷徑,而采用所有數據進行分析處理。大數據的5V特點(IBM提出):Volume(大量)、Velocity(高速)、Variety(多樣)、Value(低價值密度)、Veracity(真實性)。
大數據相關技術
數據收集
爬蟲,python,jsoup,Nucth
數據倉庫 :Hive?ELK
日志:Flume分布式日志收集工具,log4j
IOT:物聯網
數據清洗
SQL: id name age gender addr 姓名 性別 18歲及以上的 select name, gender from user where age >= 18
邏輯: if(person != null){…}
數據存儲
Hadoop.HDFS?(Google File System)
數據處理
離線處理: Hive
流式處理:?Flink,Spark,Storm
MQ:?kafka
數據傳輸:?Sqoop
狀態監控:zookeeper
環境準備
8G 克隆三臺虛擬機
hadoop01 1G
hadoop02 512M
hadoop03 512M
4G 克隆一臺虛擬機
hadoop01 1G
hadoop
分布式的海量數據存儲和處理系統,同時具有集群資源管理和任務調度的能力.
歷史
Google:全文檢索,海量數據存儲,海量數據處理,爬蟲
2004年《google file system》(GFS)《Mapreduce》(MR)
2006年《Big Table》(上億行,上百萬列這樣的高表或者寬表)
Doug cutting(Java): Nutch(爬蟲) Lucene、HDFS、Mapreduce Hadoop
Hbase(k,v)
大數據技術發源自搜索引擎領域,直到現在很多大數據技術中都會有搜索引擎的影響.
DataSet: 離線數據
DataStream: 流式數據
概念
Hadoop允許使用簡單的編程模型跨計算機集群對大型數據集進行分布式處理
版本
hadoop1.x: HDFS(海量數據存儲) Mapreduce(海量數據的離線計算,集群資源管理,任務調度)
hadoop2.x: HDFS(海量數據存儲) Mapreduce(海量數據的離線計算) Yarn(集群資源管理,任務調度) 2.7.1
hadoop3.x: HDFS(海量數據存儲) Mapreduce(海量數據的離線計算) Yarn(集群資源管理,任務調度)
HDFS
海量數據存儲,無限存儲
Hadoop的安裝
可能出現的錯誤
提示命令找不到 環境變量配置錯誤或者沒有source /etc/profile
Flume
定義
是一個分布式的海量日志收集工具.用于收集,聚合,移動大量的日志數據. 具備簡單的流式數據處理模型的特點.但是不需要計算.所以說他簡單.
重要概念 RegExp
log : 江哥今天沒來上課,不知道去哪了
Event:事件,JSON = {“headers” : “value”, “body” : “江哥今天沒來上課,不知道去哪了”},Flume在接收到日志數據之后,會先將其進行封裝,每一條日志都會被封裝為一個Event.然后再進行傳輸.
Agent: 代理, flume是一個分布式的軟件,就像Hadoop中不同的節點都有自己的名字一樣.flume的所有節點都叫Agent,每一個Agent中都包含三個部分.sourcechannel和sink
Source: 數據源,是Flume用來接收數據的組件.日志數據首先會進入到source模塊,并在改模塊進行封裝(Event).輸出給Channel進行緩存.
Channel:緩存,被動接收source傳來的Event并進行緩存.等待Sink對event的消費.一般情況下,為了追求速度,都使用內存資源來緩存數據,那么此時就要注意:需要給緩存設置最大值.
Sink:輸出, 指定數據輸出的位置,消費Channel中的event
靈活的特性
多級流動
扇入
扇出
知識回顧
Flume是一個分布式的日志收集工具.
重要概念
Event:事件,Flume在收集到日志數據之后不是直接傳輸,而是先封裝其為
Event(JSON) : {“headers”:“自定義內容”,“body”:“日志本身”}
Agent:Flume本身是分布式的,他所有的節點都叫做Agent,代理. 其中每個agent內部都會有三個組件,分別是,source\channel\sink
Source:Flume的數據源,負責數據的接入,當日志數據進入到source時,source會先將其進行封裝(Event),然后將event輸出到Channel中進行緩存.
Channel: 被動接收source傳來的數據,對所有數據進行緩存,等待Sink的消費.一般情況為了追求速度,使用內存來做緩存,所以必須設置最大容量.
Sink:指定數據的輸出位置,消費Channel中緩存的數據.
靈活特性
多級流動: 兩臺以上的服務器串聯傳輸數據.
扇入: 多個服務器同時將數據發送給一臺服務器
扇出: 一臺服務器講數據分發給多臺
Hive
MapReduce在離線數據處理中遇到的問題
概念
Hive是一個基于Hadoop的數據倉庫客戶端. 使用簡單的SQL方式來處理海量離線數據,避免開發MR程序的成本過高的問題.內部集成了非常豐富的函數庫.并且在內置函數不能滿足開發需求時.Hive也允許用戶自定義函數(UDF)來解決更為復雜的問題(很少)
數據倉庫
倉庫(有用,但不常用的)
數據倉庫是一個面向主題的,穩定的,集成的,反映歷史數據的數據存儲系統.一般用于為管理者的決策分析提供數據的支持.
Hive表的類型
內部表和外部表
MANAGED_TABLE 內部表(托管表): 先創建表,然后在表中寫數據,內部表指的是數據和表結構都屬于Hive當Hive要刪除這個表時,元數據和表數據都會被刪除.
create table tb_book1 (id int, name string) row format delimited fields terminated by ‘\t’;
EXTERNAL_TABLE 外部表: 先有數據已經保存在HDFS中,根據數據文件的格式,創建Hive的表結構,然后將表結構映射在數據上,來管理相關數據.
create external table tb_book2 (id int,name string) row format delimited fields terminated by ‘\t’ location ‘/2006book2’;
實驗
分區表
分區表時Hive作為數據倉庫實現面向主題的唯一方式
分桶表
分桶的應用場景: 1.HashMap 2.數據庫分庫 3.Nginx負載均衡 IPhash
只在測試時.數據量大并且隨意抽取樣本數據不準確時.使用分桶表.
知識回顧
Hive是什么? 是一個基于Hadoop的數據倉庫客戶端,使用SQL的方式操作.內置了非常豐富的函數庫.并且支持自定義函數.
數據倉庫? 一個面向主題的,穩定的,集成的,反應歷史數據的數據存儲系統,一般為管理者提供決策分析的數據支持.
內部表: 先創建表然后在表中寫數據
外部表托管表:先有數據,然后根據數據文件的格式,創建表結構,然后將表結構映射在數據上
內部表刪除數據時,元數據和表數據都會被刪除,外部表刪除時,元數據會被刪除,表數據則不會被刪除
分區表:Hive作為數據倉庫實現面向主題的唯一方式.
分桶表:只在測試階段使用,為了解決,數量大,并且數據依據時間或者類似其他維度有規律.測試時如果全量原始數據加載測試,耗時太長,如果隨意抽取部分數據結果不具有代表性,可能會影響判斷. 此時,使用分桶表來解決這個數據抽樣問題
項目第二次重構: 海量日志數據的離線分析
Sqoop
是連接基于HDFS的文件存儲系統,和關系型數據庫的數據橋梁.能夠輕松實現將HDFS中存儲的數據輸出到Mysql等關系型數據,或者從關系型數據庫中導入數據到HDFS.
Kafka
MQ,消息隊列, 海量數據存儲(HDFS),和流式數據處理(Spark,Flink)
ActiveMQ(6k)\RabbitMQ(1.2w)\RocketMQ(3-5w):更適合于業務系統,能夠保證數據一致性(數據不會丟失)
Kafka(25-50w)\ZeroMQ(Storm)速度非常快,但是有小概率的數據丟失情況(十億分之一)
重要概念
消費者\生產者客戶端: 連接消費者和生產者,達到解耦的目的.同時保證Kafka的可伸縮性.
Broker: kafka中,所有的機器節點都叫做broker按照int類型數據進行編號默認從0開始.主要的任務就是保存隊列中的數據.
Topic: 將不同業務的數據,用主題(文件夾)隔離開,避免數據錯誤消費.一個主題上可以掛在多個生產者和多個消費者.
Partition: 按照0-n來編號,實際上就是在不同的Broker中來分布存放Topic的一部分數據,具有不同事件鍵的數據會被分配到不同的分區中,來隔離不同子業務的數據.在分區內部,所有數據都會被進行編號0-n 來保證數據消費的順序是FIFO.并且與Offset配合來使消費者避免重復消費的問題,或者消費指定的數據.
Leader\Follower: kafka為了保障數據的安全.在分區層面上對數據進行了備份.原始的分區為Leader 復制出的備份分區為Follower,Follower存放在與Leader不同的Broker上.在正常情況下,所有的讀寫數據的工作全部由Leader完成,Follower只負責實時同步Leader中的數據變化.當Leader不可用時.兩個Follower會由Zookeeper組織完成選舉體態Leader.
ConsumerGroup:消費者組,用于解決發布訂閱中多個消費者共享一份數據負載均衡的問題.一個組在消費者客戶端中注冊一個offset組內成員的消費行為都會使offset發生改變.
Flink
Flink是一個分布式的計算引擎,能夠處理流式數據和離線數據.(無邊界/有邊界)
核心API
DataSet : 用于處理離線數據
DataStream : 一般用于處理流式數據,同時也支持將離線數據以流的形式來處理
Scala學習寶典(保姆級)
前言
為什么要學習Scala
分布式高并發語言Go、R、Erlang等等為何選擇Scala?
Spark是大數據處理的核心方式,用scala語言編寫!
Kafka分布式發布訂閱消息系統,由LinkedIn捐給Apache,以極高的吞吐量著稱,是目前最火爆的MQ,用scala語言編寫!
Flink最新一代分布式海量數據計算框架,Alibaba收購并開源,自己開發Blink分支,Scala語言編寫!
學前寄語
在我個人看來,Scala是一門非常優雅的語言,但優雅的背后要付出的辛苦也很多,比如學習Scala的人都會說,Scala語法非常簡潔,但這也意味著抽象級別比較高,對初學者而言不好理解。也會有人說,Scala語法非常靈活,一個功能可以有非常多的實現方法,可以說條條大路通羅馬,那么代價就是對于初學者來說,路多了反而不好選擇。
所以在這里我對初學者的忠告是:在學習Scala前期,先走通一條路,屏蔽掉多余的干擾項,可能我們第一次使用Scala實現的項目看起來是非常笨拙的,但是沒關系,任何的學習都是循序漸進的,不要追求一蹴而就。走通之后再回頭,去尋找更好的替代方案。這樣才能享受學習。
Scala簡介
Scala combines object-oriented and functional programming in one concise, high-level language. Scala’s static types help avoid bugs in complex applications, and its JVM and JavaScript runtimes let you build high-performance systems with easy access to huge ecosystems of libraries.
Scala是一個將面向對象和函數式編程結合在一起的簡潔的高級語言。Scala的靜態類型有助于避免復雜應用程序中的錯誤,其可以運行在JVM和JavaScript的特點使您可以輕松訪問龐大的生態系統庫來構建高性能系統。
Scala的誕生
Martin OrderSky馬丁 奧德斯基 是JVM開發團隊核心成員,是JDK1.5泛型,增強for循環,自動類型轉換,JDK1.8Lambda等重要特性的作者.
在對JAVA的維護過程中,馬丁非常推崇JAVA的面向對象及垃圾回收,是James Gosling的小迷弟. 但作為編輯器開發的狂熱愛好者的他,又覺得JAVA的語法過于繁瑣.所以相繼自己開發了另外兩種語言Pizza和Scala.其中Scala被用于實驗室科研后推廣開源.在上邊提到JDK1.5和1.8的兩個版本中的新特性就是從Pizza和Scala中遷移而來.
Scala誕生于2001年,但真正被人們所熟知并廣泛應用于大數據開發是在十多年之后.可以說是Spark和Kafka帶火了Scala.
James Gosling曾在采訪中說,如果讓他選擇“今天使用的語言不是Java,那就是Scala”。
函數式編程
C:面向過程編程
Java:面向對象編程
Scala:面向函數編程
函數式編程:將所有復雜的問題的解決拆分為若干函數的處理,每一個函數可以去實現一部分功能,利用很多次函數的處理最終解決問題。函數式編程相對于面向對象編程更加的抽象,好處是代碼可以非常的簡潔,更多的采用常量而不是變量來解決問題,這樣額外帶來的好處是在線程并發時可以減少甚至杜絕多線程并發安全問題,特別適合于應用在處理高并發場景、分布式場景下的問題。函數式編程可以使用高階函數,函數在scala中是一等公民,可以更加靈活的進行程序的編寫。
函數式編程并不是面向對象編程的發展,而是另外一種解決問題的思路,兩者之間也并沒有絕對的好壞之分,在不同的場景中各有各的優缺點。
總結:Scala是一個面向對象的函數式編程語言.
Scala和java的關系
java是由C語言開發,scala基于java,現在看來大部分情況下,青出于藍而勝于藍!
分布式開發中會面對很多棘手的問題,如面臨服務器之間的通信、遠程調用、序列化、反序列化等等。但有了scala這一切變得輕松,它全部都做了內部實現。讓我們訪問分布式集群環境就和訪問單機一樣簡單。
同時Scala無縫集成Java,Scala編譯器會先把源文件編譯成.class文件再運行。Scala可以調用幾乎所有的Java類庫,也可以從Java應用程序中調用Scala的代碼。它也可以訪問現存的數之不盡的Java類庫,這讓用戶(潛在地)遷移到Scala更加容易。
Java => 編譯 => .class => JVM
Scala => 編譯 => .class => JVM
Scala => JVM(支持,但不推薦,不是解釋執行)
擴展:groovy、clojure(storm)都可以編譯成.class,利用JVM。
Scala的特點
Scala環境搭建
SDK下載安裝及測試
提示:Scala基于Java,需要提前安裝JDK并配置環境變量
官網:https://www.scala-lang.org/
說明: 編寫本篇教程時,Scala的最新版本為2.13.3,但是基于后續Spark\Kafka\Flink三個主流框架的版本及對Scala的版本要求.我們最終選擇Scala-2.12.7這個版本作為基礎環境. 2.11版本之后差別并不大,所以該文所有代碼預計在2.11\2.12\2.13版本環境中都可以正常運行.
1.訪問Scala官網,找到所需安裝包進行下載.https://www.scala-lang.org/download/all.html
在這里,我們選擇的是2.12.7這個版本進行下載.
2.進入2.12.7版本下載頁后,在尾部找到對應系統安裝包進行下載.
3.安裝Scala,雙擊msi包,一路下一步即可.注意中間在安裝目錄選擇時,路徑不要有中文或空格.
選擇合適的目錄
4.檢查環境
5.Hello World
?
IDEA插件安裝
在IDEA的File菜單中打開Settings窗口
選擇Plugins在Marketplace中搜索Scala,找到Scala插件后點擊Install.
等待插件下載完成,點擊重啟IEDA
如果網絡環境不佳無法自動下載插件.此時需要手動導入,具體導入方法可以參考我的另一篇文章:?https://blog.csdn.net/dcc15011003101/article/details/107805938
第一個Scala工程
創建一個新的工程
創建一個Object(至于什么是Object之后會詳細解釋)
命名為: cn.tedu.scalabasic.HelloWorld
選擇Object選項
編寫代碼
右鍵運行
結果
主方法
Scala基礎語法
注釋
Scala中注釋的寫法與Java一致
package cn.tedu.scalabasic
/**
?* Scala基礎語法
?*/
object ScalaGrammar {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 1.注釋
? ? Scala中的注釋形式與Java中一致.包括文檔注釋,多行注釋,單行注釋
? ? ?*/
? ? /**
? ? ?* 這是一個文檔注釋
? ? ?*/
? ? /*
? ? 這是一個多行注釋
? ? ?*/
? ? //這是一個單行注釋
? }
}
代碼分隔
在Scala代碼中每行代碼的結尾不需要分號";"作為結束符(自動推斷),也可以加分號.
package cn.tedu.scalabasic
/**
?* Scala基礎語法
?*/
object ScalaGrammar {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 2.代碼分隔符
? ? 在Scala中,代碼行與行之間的分隔符與Java相同,使用分號;,但是一般不需要寫,Scala實現了自動推斷.
? ? ?*/
? ? println("再見,劉沛霞");
? ? println("你好,張慎政")
? ? println("么么噠,董長春")
? }
}
變量和常量定義
在Scala中變量和常量分別使用var和val來定義.可以聲明類型但不必要(類型自動推斷).
其中,官方建議盡量不要使用var而是使用val來定義,有利于內存回收.和線程的安全.
package cn.tedu.scalabasic
/**
?* Scala基礎語法
?*/
object ScalaGrammar {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 3.常量變量
? ? 在Scala中,變量使用var來定義,常量使用val定義
? ? 并且在定義變量和常量時一般都不寫類型.Scala按照上下文可以自動推斷
? ? **重要**:在Scala中我們更推薦大家盡可能的使用常量來定義屬性,這更利于內存回收.
? ? ?*/
? ? var a = 12
? ? val b = 10
? ? val c: Int = 11
? ? a += 1
? ? // ? ?b += 2 ?//編譯報錯,常量不可變
? ? println(a)
? ? println(b)
? }
}
標識符
Scala 可以使用兩種形式的標志符,字符數字和符號。
字符數字使用字母或是下劃線開頭,后面可以接字母或是數字,符號"$“在 Scala 中也看作為字母。然而以”$“開頭的標識符為保留的 Scala 編譯器產生的標志符使用,應用程序應該避免使用”$"開始的標識符,以免造成沖突。
同時,Scala與Java相同的是同樣建議使用駝峰規則命名.
package cn.tedu.scalabasic
/**
?* Scala基礎語法
?*/
object ScalaGrammar {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 4.標識符
? ? Scala標識符規則與Java大致相同.不能以符號和數字開頭(_和$可以).
? ? 其中以$例外一般不作為標識符的開頭使用,暫時不必深究.
? ? 命名格式推薦使用駝峰命名法:AaaBbb,aaaBbb,AAA_BBB
? ? 不能使用關鍵字和保留字命名
? ? ?*/
? ? val userName = "董長春"
? ? // ? ?val if = 12 //編譯報錯,關鍵字和保留字不能用作標識符
? }
}
關鍵字保留字
方法和操作符
在Scala中有這樣一句話:操作符即方法,方法即操作符
意思是方法可以按照操作符的使用規則來使用,操作符也可以按照方法的方式使用
package cn.tedu.scalabasic
/**
?* Scala基礎語法
?*/
object ScalaGrammar {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 5.操作符和方法
? ? 在Scala中有這樣一句話:操作符即方法,方法即操作符
? ? 意思是方法可以按照操作符的使用規則來使用,操作符也可以按照方法的方式使用
? ? ?*/
? ? val str = "123_456_789"
? ? val strs = str split "_" //這里以操作符的形式(1 + 2)使用split方法
? ? for (s <- strs) {
? ? ? println(s)
? ? }
? ? println(2.*(4)) //這里以方法的形式(a.split("_"))使用+操作符
? ? //對于沒有參數的方法,也可以不寫括號
? ? val num: Int = 123
? ? println(num.toString())
? ? println(num.toString)
? }
}
Scala數據類型
在Java中,分為基本數據類型(8種) 和 引用類型(繼承自Object).其中基本數據類型直接以字面量的形式賦值,沒有屬性和方法.
在Scala中數據類型與Java的設計類似,并且針對面向對象和函數式編程做了更進一步的優化.
?
其中:
官方圖譜:
AnyVal
這里我們先對AnyVal做詳細講解
值類型的定義
package cn.tedu.scalabasic
import scala.collection.immutable.StringOps
/**
?* AnyVal值類型的聲明
?*/
object DataTypes {
? def main(args: Array[String]): Unit = {
? ? val a: Byte = 123
? ? println(a,a.getClass)
? ? val b: Short = 123
? ? println(b,b.getClass)
? ? val c: Int = 123
? ? println(c,c.getClass)
? ? val d: Long = 123L ?//此處加不加L都可以
? ? println(d,d.getClass)
? ? val e: Float = 1.23f ?//為區別Double,Float類型后加f
? ? println(e,e.getClass)
? ? val f: Double = 1.23
? ? println(f,f.getClass)
? ? val g: Char = '@'
? ? println(g,g.getClass)
? ? val h: Boolean = false
? ? println(h,h.getClass)
? ? val i: Unit = "123" //不管這里賦值什么,他的值始終是()這是Unit的默認值.
? ? println(i,i.getClass)
? ? /*
? ? ? 特殊說明
? ? ? 雖然String是java.lang.String.在Scala中屬于AnyRef類型,
? ? ? 但是在實際操作是會被隱式轉換為StringOps類型屬于AnyVal
? ? ? 通過以下實驗可以證明
? ? ?*/
? ? val j: String = "123"
? ? println(j,j.getClass) //(123,class java.lang.String)
? ? println(j.length(),j.length) ?//(3,3) 這里我們知道,java.lang.String類中是沒有length屬性的只有length()方法
? ? val k: StringOps = "123"
? ? println(k,k.getClass) //(123,class scala.collection.immutable.StringOps) length在StringOps中定義
? }
}
值類型的轉換
自動類型轉換
在Scala中類型的轉換包括兩種,一種是值類型轉換,另外一種是引用類型轉換,這里我們先重點講解值類型的轉換.
值類型可以通過以下方式進行轉換:
其轉換方向取決于長度,只能由范圍小的類型自動轉換為范圍大的,不能大變小.
package cn.tedu.scalabasic
/**
?* 類型轉換
?*/
object TypeTrans {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 自動類型轉換
? ? 在計算的過程中,值類型會進行自動轉換,根據范圍由小到大
? ? Byte->Short->Int->Long->Float->Double
? ? ? ? ? ? ? ? ? ↑
? ? ? ? ? ? ? ? ?Char
? ? ?*/
? ? var a: Int = 12
? ? var b: Byte = 1
? ? var c: Char = 'a'
? ? var d: Long = 12
? ? var e: Double = 11.1
? ? var f: Short = 3
? ? var g: Float = 3.2f
? ? println(a+b,(a+b).getClass)
? ? println(a+c,(a+c).getClass)
? ? println(a+d,(a+d).getClass)
? ? println(a+e,(a+e).getClass)
? ? println(a+f,(a+f).getClass)
? ? println(d+g,(d+g).getClass)
? }
}
?
說明:浮點數32位的范圍大于Long的64位,由轉換公式決定.
強制類型轉換
范圍大的數據類型通過 .toxxx 實現向范圍小的數據類型強制轉換,注意可能會造成精度的缺失.
package cn.tedu.scalabasic
/**
?* 類型轉換
?*/
object TypeTrans {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 強制類型轉換
? ? 范圍大的數據類型通過 .toxxx 實現向范圍小的數據類型強制轉換,注意可能會造成精度的缺失.
? ? ?*/
? ? val h: Int = 12
? ? val i: Double = 2.12
? ? val j: Int = (h + i).toInt
? ? println(j)
? }
}
?
值類型和String類型之間的相互轉換
?
package cn.tedu.scalabasic
/**
?* 類型轉換
?*/
object TypeTrans {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 值類型和String類型之間的相互轉換
? ? ?*/
? ? //值類型轉換為String類型有兩種方式,分別是a+"" 和 a.toString
? ? val k:Int = 12
? ? println(k+"",(k+"").getClass)
? ? val l:Int = 12
? ? println(l.toString,(k.toString).getClass)
? ? //String類型數據轉換為值類型的前提是可轉,使用.toXxx
? ? val m:String = "123"
// ? ?val m:String = "12a" ?//報錯:java.lang.NumberFormatException
? ? println(m.toInt,m.toInt.getClass)
? }
}
?
運算符
算數運算符
Scala中的算數運算符與Java基本一致,唯一不同是沒有++和–.
package cn.tedu.scalabasic
/**
?* Scala中的操作符
?*/
object ScalaOperator {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 算數運算符
? ? ?*/
? ? val a = 13
? ? val b = 3
? ? println(a + b)
? ? println(a - b)
? ? println(a * b)
? ? println(a / b)
? ? println(a / 3.0) ?//如果在除法運算時需要精確值,需要有至少一個浮點型
? ? println(a % b)
? }
}
賦值運算符
Scala中的賦值運算符與Java基本一致
package cn.tedu.scalabasic
/**
?* Scala中的操作符
?*/
object ScalaOperator {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 賦值運算符
? ? ?*/
? ? var c = 3 //將3這個值賦值給變量a
? ? c += 3
? ? println(c)
? ? c -= 3
? ? println(c)
? ? c *= 3
? ? println(c)
? ? c /= 3
? ? println(c)
? ? c %= 3
? ? println(c)
? }
}
關系運算符
Scala中的關系運算符與Java基本一致
package cn.tedu.scalabasic
/**
?* Scala中的操作符
?*/
object ScalaOperator {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 關系運算符
? ? ?*/
? ? println(a>b)
? ? println(a>=b)
? ? println(a<b)
? ? println(a<=b)
? ? println(a==b)
? ? println(a!=b)
? }
}
邏輯運算符
Scala中的邏輯運算符與Java基本一致,但是在取反操作時不能像Java一樣多層取反.
package cn.tedu.scalabasic
/**
?* Scala中的操作符
?*/
object ScalaOperator {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 邏輯運算符
? ? ?*/
? ? var bool1 = true
? ? var bool2 = false
? ? println(bool1 && bool2)
? ? println(bool1 || bool2)
? ? println(!bool2) //Scala不支持多層取反(!!!!!true)
? }
}
位運算符
Scala中的位運算符與Java基本一致,了解即可.
流程控制
程序的執行順序需要根據需求進行相應的控制,比如執行的順序,執行條件,執行次數等.
順序結構
Scala像大部分語言一樣,代碼一般按照從上到下的順序執行.
一行代碼中安裝從左到右的順序執行,同一行內如果有括號,先算括號里.
數學計算中遵循先乘除后加減.
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 順序結構
? ? ?*/
? ? println("Hello World")
? ? println(1+2+"Hello World"+3+2*2+(4+5))
? }
}
分支結構
在Scala分支結構中,只有if…else if…else 沒有Java中的switch…case(模式匹配)
需要注意的是if分支結構是可以有返回值的.所以可以使用if語句替代Scala中沒有的三元運算符.
與Java一致的是,分支結構可以多層嵌套.
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 分支結構
? ? ?*/
? ? val age = 19
? ? if (age >= 18) {
? ? ? println("你已經成年了")
? ? } else if (age >= 500) {
? ? ? println("你已經成精了")
? ? } else {
? ? ? println("你還是個孩子")
? ? }
? ? //在Scala中沒有三元運算符 a?b:c,使用if...else代替
? ? var result = if (age >= 18) "你已經成年了" else "你還是個孩子"
? ? println(result)
? }
}
循環結構
for循環
在Scala中for循環用于控制程序執行次數,與Java一致,同時具備了更加豐富的功能.
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 循環結構-for
? ? ?*/
? ? for (i <- 1 to 10) {
? ? ? println(i)
? ? }
? ? //九九乘法表
?? ?for (i <- 1 to 9) {
? ? ? for (j <- 1 to i) {
?? ??? ?//print(j + "*" + i + "=" + i * j + "\t")
? ? ? ? //在Scala中變量和字符串的拼接可以簡化為占位符
? ? ? ? print(s"${j} * ${i} = ${i*j}\t")
? ? ? }
? ? ? println()
? ? }
? ? //簡寫
? ? for (i <- 1 to 9; j <- 1 to i) {
? ? ? print(s"${j} * ${i} = ${i*j}\t")
? ? ? if (i == j) println()
? ? }
? ? //循環條件,守衛,步長
? ? for(i <- 1 to 10 if i % 2 == 0) println(i)
? ? //推導式:生成一個2到10的偶數集合
? ? var nums = for(i <- 1 to 10 if i % 2 == 0) yield i
? ? println(nums)
? }
}
?
while循環
Scala中while與Java中寫法和用法都一致.但是更推薦使用for,因為for更加簡潔.
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 循環結構-while
? ? ?*/
? ? var num1 = 0
? ? while (num1 <= 10) {
? ? ? num1 += 1
? ? }
? ? println(num1)
? ? var num2 = 0
? ? do {
? ? ? num2 += 1
? ? } while (num2 <= 10)
? ? println(num2)
? }
}
?
break()和breakable
在Scala中沒有break和continue想要使用類似功能只能用scala.util.control.Breaks._工具
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? break()和breakable
? ? ?*/
? ? ?//導包
? ? import scala.util.control.Breaks._
? ? //break
? ? breakable {
? ? ? for (i <- 1 to 10) {
? ? ? ? println(i)
? ? ? ? if (i == 6) break()
? ? ? }
? ? }
? ? //continue
? ? for (i <- 1 to 10) {
? ? ? breakable {
? ? ? ? if (i % 2 == 0) break()
? ? ? ? println(i)
? ? ? }
? ? }
? }
}
?
代碼塊
在Java中我們學過靜態代碼塊,在Scala中也有代碼塊的概念,就是用大括號括起來的一段代碼.并且在Scala中代碼塊是可以有返回值的.
package cn.tedu.scalabasic
/**
?* 流程控制
?*/
object ProcessControl {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 代碼塊
? ? */
? ? val block = {
? ? ? println("代碼")
? ? ? val v1 = 12
? ? ? val v2 = 14
? ? ? v1 + v2 ?//最后一行的表達式為返回值
? ? }
? ? println(block)
? }
}
方法和函數
在Scala中方法和函數是不一樣的.一般情況下在使用時并不需要特殊區分.
方法
Scala中的方法定義與Java不同更加簡潔.
一般情況下返回值類型可以省略.遞歸方法除外.
return可以省略,默認方法體中最后一行被返回.
只有一行代碼的時候大括號也可以省略.
當返回值類型為Unit(沒有返回值)時,=也可以省略不寫,也就是說如果不寫等號該方法不會返回任何數據.這種形式在Scala中叫做"過程"
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 方法的定義
? ? ?*/
? ? def getSum1(a:Int,b:Int):Int = {
? ? ? return a+b
? ? }
? ? //返回值類型可以省略(自動推斷)
? ? //return可以省略(默認返回最后一行)
? ? //{}可以省略(只有一行代碼)
? ? def getSum2(a:Int,b:Int)= a + b
? ??
? ? val sum1 = getSum1(1,2)
? ? val sum2 = getSum2(3,4)
? ??
? ? println(sum1)
? ? println(sum2)
? ? //沒有返回值時,=等號可以不寫.這種形式在Scala中叫做:過程
? ? def sayHello() {
? ? ? println("Hello,World")
? ? ? return 1 ?//即使寫了返回1,因為沒有等號= 方法也不會返回任何數據.
? ? }
? ? val hello = sayHello()
? ? println(hello)
? }
}
?
遞歸
方法內部調用自己,即為遞歸
遞歸方法定義時不能省略返回值類型
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? //遞歸方法定義時必須聲明返回值
? ? def getFactorial(n: Int): Int = {
? ? ? if (n == 1) n else n * getFactorial(n - 1)
? ? }
? ? val factorial = getFactorial(5)
? ? println(factorial)
? }
}
?
方法的參數
默認參數
在方法的定義時,我們有時會遇到這樣的需求: 某些參數通常是不變的數據只有少數情況下才會變化.如果大多數情況下都需要手動傳入同樣值不符合編程中復用的原則.默認參數就可以解決這類問題.
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 默認參數
? ? ?*/
? ? def getUserInfo(name:String,age:Int,addr:String = "張家口"):String = {
? ? ? s"${name}來自${addr},今年${age}歲了"
? ? }
? ? val info1 = getUserInfo("董長春",12)
? ? val info2 = getUserInfo("馬夢詩",12)
? ? val info3 = getUserInfo("劉沛霞",12,"天津")
? ? println(info1)
? ? println(info2)
? ? println(info3)
? }
}
?
指定參數
指定參數時指,在調用方法是通過指定參數名來改變參數傳遞的前后順序.
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 指定參數
? ? ?*/
? ? def getProduct(a: Int = 5, b: Int = 10) = (a + 3) * b
? ? //改變參數傳入的順序
? ? println(getProduct(b = 4, a = 3))
? ? //避免在參數有默認值時錯傳
? ? println(getProduct(b = 1))
? }
}
可變參數
當方法的參數列表中有多個不確定的參數時,可以是用可變參數,與Java類似.
可變參數用數組來保存,可以直接調用數組的方法.
如果參數列表中既有普通參數,也有可變參數,可變參數必須寫在最后.
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 可變參數
? ? ?*/
? ? def getSum4(nums:Int*) = nums.sum //可變參數是用數組保存的,可以直接使用數組的方法.
? ? //需要注意的是,如果參數列表中既有普通參數,也有可變參數,可變參數需要寫在最后.
? ? //def getLogs(logs:String*,id:Int) = {} //編譯錯誤:*-parameter must come last
? }
}
方法的調用
在Scala中方法的調用也是非常靈活的,我們來總結一下.
后綴調用
最普通的調用方式就是后綴調用,這與Java中是一致的.都是對象.methodName(參數)的形式.
中綴調用
中綴調用其實在前邊已經接觸過,就是方法即運算法,運算符及方法的體現.
比如:1 to 10.就是1.to(10)
大括號調用
當參數只有一個時,也可以將小括號替換為大括號.比如: 對象.methodName{參數},用的不多.
無括號調用
當沒有參數時,方法的調用可以不寫括號,比如:array.sum
惰性加載
為了解決資源推遲加載,優化啟動速度,區別加載順序等問題,Scala中設計了一個惰性加載的概念.
所有被lazy修飾的val所指向的資源不會直接加載,而是延遲到使用時才會加載.
需要注意的是,lazy只能修飾val 不能修飾var
當用于接收方法返回值得val被lazy修飾是,這個方法會惰性加載.叫做惰性方法.
這種惰性加載的形式在Java中也有,只不過Java沒有原生支持,而是通過代碼邏輯來實現,叫做懶加載,比如單例中的懶漢式.在Spring等對象管理框架中也有懶加載的概念.
package cn.tedu.scalafunction
/**
?* 方法
?*/
object Method {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 惰性方法(類似Java中的懶加載)
? ? ?*/
? ? def getSum3(a:Int,b:Int) = {
? ? ? println("getSum3已經加載")
? ? ? a + b
? ? }
// ? ?val sum3 = getSum3(1,2)
? ? lazy val sum3 = getSum3(1,2)
? ? println(sum3)
? }
}
函數
在Scala中函數與方法是不同的.方法依附于對象,而函數本身就是對象.
函數的定義方式也與方法不同.
object Function {
? def main(args: Array[String]): Unit = {
? ? /*
? ? 函數的定義
? ? 1.函數本身是一個對象.
? ? 2.函數參數列表和函數體之間是 => 來鏈接
? ? 3.函數不需要寫返回值類型.
? ? 4.函數定義時的變量名就是函數名,也就是這個對象的引用,調用時使用函數名(參數)的形式調用.
? ? 5.函數可以直接用lazy修飾作為惰性函數.
? ? ?*/
? ? val getSum = (a:Int,b:Int) => {a + b}
? ? println(getSum(1,2))
? ? val printMsg = () => {println("Hello")}
? ? printMsg()
? ? lazy val getMax = (v1:Int,v2:Int) => {if (v1>v2) v1 else v2}
? ? println(getMax(2, 3))
? ??
? ? /*
? ? 方法轉函數
? ? 有時候我們需要將一段邏輯作為參數傳遞,但是方法不支持傳遞,可以將其轉化為函數.
? ? 通過本案例的輸出結果,我們也可驗證,函數是對象,而方法不是.
? ? ?*/
? ??
? ? def getInfo() = {println("我叫董長春")}
? ? println(getInfo)
? ? val toFunction = getInfo _
? ? println(toFunction)
? }
}
類和對象
回顧面向對象
在Java的學習過程中,面向對象無疑是重中之重.而Scala是一門面向對象的函數式編程語言,所以面向對象的概念或者思想在Scala學習過程中也是不能忽視的.
什么是面向對象
面向對象是一種編程思想,是相對于面向過程的又一層高級抽象.
我們將一系列事物的特性或者功能抽象出來并對其進行封裝,這個封裝結果就是類,而屬于這個類的所有個體就是這個類的對象.
面向對象的特點
封裝: 保證安全性
繼承: 保證復用性
多態: 保證拓展性
類的定義和對象創建
Scala中簡單的類定義與Java相同,內部可以定義成員屬性和成員方法.
package cn.tedu.scalaoop
/**
?* 定義一個類
?*/
class Person {
? //初始化屬性有三種方式
? var name:String = "" ?//姓名
? var age:Int = _ ? ? ? //年齡
? var addr = "" ? ? ? ? //地址
? def sayHello(){println(s"大家好我是${name},今年${age}歲了,來自${addr}.")}
}
對象的創建方式與Java也類似,通過new關鍵字實現對象的創建
在使用空參構造時,類名后的括號可以省略.
對象可以訪問類的公共屬性和方法.
package cn.tedu.scalaoop
/**
?* 創建對象
?*/
object PersonObject {
? def main(args: Array[String]): Unit = {
? ? val p1 = new Person()
? ? //構造方法為空時,括號可以省略
? ? val p2 = new Person
? ? p2.name = "董長春"
? ? p2.age = 18
? ? p2.addr = "張家口"
? ? p2.sayHello()
? }
}
訪問權限修飾符
Scala中訪問權限修飾符與Java稍有不同,但是功能是一致的.
Scala中共有四種訪問權限修飾符
包括:private \ private[this] \ protected \ 默認
| private[this] | 作用域私有的,只能在范圍內中訪問,對于其他私有 |
| private | 類私有的,只能在本類訪問 |
| protected | 受保護的,只能在本類及其子類中訪問 |
| 默認 | 公共的(public)全局可訪問 |
一般情況下,開發中更多的使用到默認的,和private私有的.
package cn.tedu.scalaoop
/**
?* 定義一個動物類
?*/
class Animal {
? var name = ""
? private var age = 0
? protected var color = ""
? private[this] var eat = ""
? def sayHello(){println(name,age,color,eat)}
}
?
package cn.tedu.scalaoop
object AnimalObject {
? def main(args: Array[String]): Unit = {
? ? val animal = new Animal
? ? animal.name = "驢"
? ? //非公有不能訪問
// ? ?animal.age
// ? ?animal.color
// ? ?animal.eat
? }
? class Donkey extends Animal{
? ? var animal = new Animal
? ? animal.name
// ? ?animal.age ?//私有不能訪問
? ? animal.color ?//子類可以訪問protected修飾的屬性
// ? ?animal.eat ?//私有不能訪問
? }
}
?
構造器
像Java創建對象一樣,Scala在創建對象的時候也是調用構造器,而Scala中構造器的寫法與Java不用,直接定義在類名之后的小括號里.
單例對象
伴生類和伴生對象
private[this]權限修飾
apply()方法
繼承
特質Trait
包和樣例
容器
數組
元組
列表
集合
映射
迭代器
函數式編程
模式匹配
IO
高階函數
隱式轉換
泛型
集合
Actor
Akka
- ?
?
?
?
總結
以上是生活随笔為你收集整理的IDEA Git操作(三)使用 cherry-pick、交互式 rebase 自由修改提交树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于Windows 2003 安装Int
- 下一篇: Python笔记-上证指数收益率计算