python內置模塊collections介紹

目錄

python內置模塊collections介紹

collections是Python內建的一個集合模塊,提供了許多有用的集合類。

1、namedtuple

python提供了很多非常好用的基本類型,比如不可變類型tuple,我們可以輕鬆地用它來表示一個二元向量。

>>> v = (2,3) 

我們發現,雖然(2,3)表示出了一個向量的兩個坐標,但是,如果沒有額外說明,又很難直接看出這個元組是用來表示一個坐標的。

為此定義一個class又小題大做了,這時,namedtuple就派上用場了。

>>> from collections import namedtuple
>>> Vector = namedtuple('Vector', ['x', 'y'])
>>> v = Vector(2,3)
>>> v.x
2
>>> v.y
3

namedtuple是一個函數,它用來創建一個自定義的tuple對象,並且規定了tuple元素的個數,並可以用屬性而不是索引來引用tuple的某個元素。

這樣一來,我們用namedtuple可以很方便地定義一種數據類型,它具備tuple的不變性,又可以根據屬性來引用,使用十分方便。

我們可以驗證創建的Vector對象的類型。

>>> type(v)
<class '__main__.Vector'>

>>> isinstance(v, Vector)
True

>>> isinstance(v, tuple)
True 

類似的,如果要用坐標和半徑表示一個圓,也可以用namedtuple定義:

>>> Circle = namedtuple('Circle', ['x', 'y', 'r'])
# namedtuple('名稱', [‘屬性列表’])

2、deque

在數據結構中,我們知道隊列和堆棧是兩個非常重要的數據類型,一個先進先出,一個後進先出。在python中,使用list存儲數據時,按索引訪問元素很快,但是插入和刪除元素就很慢了,因為list是線性存儲,數據量大的時候,插入和刪除效率很低。

deque是為了高效實現插入和刪除操作的雙向鏈表結構,非常適合實現隊列和堆棧這樣的數據結構。

>>> from collections import deque
>>> deq = deque([1, 2, 3])
>>> deq.append(4)
>>> deq
deque([1, 2, 3, 4])
>>> deq.appendleft(5)
>>> deq
deque([5, 1, 2, 3, 4])
>>> deq.pop()
4
>>> deq.popleft()
5
>>> deq
deque([1, 2, 3])

deque除了實現list的append()和pop()外,還支持appendleft()和popleft(),這樣就可以非常高效地往頭部添加或刪除元素。

3、defaultdict

使用dict字典類型時,如果引用的key不存在,就會拋出KeyError。如果希望Key不存在時,返回一個默認值,就可以用defaultdict。

>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'defaultvalue')
>>> dd['key1'] = 'a'
>>> dd['key1']
'a'
>>> dd['key2'] # key2未定義,返回默認值
'defaultvalue'

注意默認值是調用函數返回的,而函數在創建defaultdict對象時傳入。

除了在Key不存在時返回默認值,defaultdict的其他行為跟dict是完全一樣的。

4、OrderedDict

使用dict時,key是無序的。在對dict做迭代時,我們無法確定key的順序。

但是如果想要保持key的順序,可以用OrderedDict。

>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

注意,OrderedDict的key會按照插入的順序排列,不是key本身排序

>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的順序返回
['z', 'y', 'x']

OrderedDict可以實現一個FIFO(先進先出)的dict,當容量超出限制時,先刪除最早添加的key。

from collections import OrderedDict

class LastUpdatedOrderedDict(OrderedDict):

    def __init__(self, capacity):
        super(LastUpdatedOrderedDict, self).__init__()
        self._capacity = capacity

    def __setitem__(self, key, value):
        containsKey = 1 if key in self else 0
        if len(self) - containsKey >= self._capacity:
            last = self.popitem(last=False)
            print('remove:', last)
        if containsKey:
            del self[key]
            print('set:', (key, value))
        else:
            print('add:', (key, value))
        OrderedDict.__setitem__(self, key, value)

5、ChainMap

ChainMap可以把一組dict串起來並組成一個邏輯上的dict。ChainMap本身也是一個dict,但是查找的時候,會按照順序在內部的dict依次查找。

什麼時候使用ChainMap最合適?舉個例子:應用程序往往都需要傳入參數,參數可以通過命令行傳入,可以通過環境變量傳入,還可以有默認參數。我們可以用ChainMap實現參數的優先級查找,即先查命令行參數,如果沒有傳入,再查環境變量,如果沒有,就使用默認參數。

下面的代碼演示了如何查找user和color這兩個參數。

from collections import ChainMap
import os, argparse

# 構造缺省參數:
defaults = {
    'color': 'red',
    'user': 'guest'
}

# 構造命令行參數:
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = { k: v for k, v in vars(namespace).items() if v }

# 組合成ChainMap:
combined = ChainMap(command_line_args, os.environ, defaults)

# 打印參數:
print('color=%s' % combined['color'])
print('user=%s' % combined['user'])

沒有任何參數時,打印出默認參數:

$ python3 use_chainmap.py 
color=red
user=guest

當傳入命令行參數時,優先使用命令行參數:

$ python3 use_chainmap.py -u bob
color=red
user=bob

同時傳入命令行參數和環境變量,命令行參數的優先級較高:

$ user=admin color=green python3 use_chainmap.py -u bob
color=green
user=bob

6、Counter

Counter是一個簡單的計數器,例如,統計字符出現的個數:

from collections import Counter
>>> s = 'abbcccdddd'
>>> Counter(s)
Counter({'d': 4, 'c': 3, 'b': 2, 'a': 1})

Counter實際上也是dict的一個子類。

7、小結

collections模塊提供了一些有用的集合類,可以根據需要選用。

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

【其他文章推薦】

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

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

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

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

澳洲動物園抗野火 園長帶猴子老虎回家避難

摘錄自2020年1月2日中央社雪梨報導

在毀滅性野火肆虐澳洲各地的情況下,新南威爾斯省(New South Wales)一家小型動物園,成功保障園區所有動物的安全。

英國廣播公司(BBC)報導,摩哥動物園(Mogo Zoo)的靈長類動物數量在澳洲數一數二,園區內還有斑馬、犀牛與長頸鹿等大型動物。但當動物園處在野火第一線時,飼養人員仍成功保護200隻動物全數未受傷害。

新南威爾斯省12月31日對動物園所在區域下達疏散命令,但職員仍決定留下來保護動物。動物園園長史戴普斯表示,動物園能倖存下來,都是因為事先做好確實規劃。飼養人員先把區內所有可燃物都搬走,接著再遷移動物。

諸如獅子、老虎與紅毛猩猩等大型動物都被趕進夜間圍欄內,以確保牠們安全、情緒平靜。但小型動物就需要特殊庇護,所以園長史戴普斯決定把牠們通通帶回自家,至於長頸鹿和斑馬則留在自己的圍欄裡,因為牠們體型夠大,可以避開火源。

史戴普斯說,長頸鹿和斑馬是園內唯一承受壓力的動物,但壓力來源並非火災,而是飼養人員匆忙開車四處滅火,動物園員工事先準備數十萬公升的水,並把水置於車上的小型水槽四處移動,看到火就予以撲滅。他形容自己的團隊日以繼夜投入工作,若非員工的英勇作為,動物園早就陷入火海。

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

【其他文章推薦】

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

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

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

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

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

帛琉禁用有害珊瑚礁防曬乳 違者罰1000美元

摘錄自2020年1月1日中央社科羅報導

太平洋島國帛琉1日起實施一項開創性禁令,不准使用含有對珊瑚礁有害成分的防曬乳液,違者罰1000美元。帛琉實施嚴格環保措施,新設全球最大海洋保護區之一也自此生效。

法新社報導,帛琉總統雷蒙傑索(Tommy Remengesau)表示,帛琉人「必須尊重環境,因為環境是孕育生命之所,沒有環境,帛琉就沒人能倖存」。

自2020年元旦起,在帛琉任何對珊瑚礁具有毒性的防曬乳液,不管是攜帶入境或販售,都會被沒收,並處罰持有者1000美元罰款。

雷蒙傑索表示:「帛琉重要生物棲地到處都發現了防曬乳液中的有毒化學物質,在帛琉最知名的生物組織中也有。我們不介意成為第一個禁用這些化學物質的國家,我們也會為傳達這個訊息盡一份力。」

除了這項禁令之外,帛琉的海洋保護區也自1日起生效,在新規定之下,帛琉的專屬經濟區(EEZ)有80%不准捕魚或從事其他海洋活動,包括採礦和取鯊魚鰭。

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

【其他文章推薦】

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

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

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

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

海洋吸塵器完成首次任務 下一步:為垃圾再製品建立透明「價值鏈」

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

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

【其他文章推薦】

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

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

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

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

北京解讀純電動客車補貼政策

今天(10日)上午,北京市對購買純電動客車有關財政政策進行解讀。北京提供1∶1市級財政補貼,兩級財政補貼總額最高不超過車輛銷售價格的60%。  
補貼範圍   行政事業單位使用財政資金購買純電動客車不納入通知規定的補助範圍。地方純電動客車補貼,直接撥付到汽車生產企業,消費者按銷售價格扣減補助後支付。  
按車長補貼   2015年純電動客車推廣應用補助標準按車長執行,車長超過10米的車補助標準最高,達50萬元 2016年補助標準中引入車長在10米-12米之間的“標準車”概念,在單位載品質能量消耗量小於0.25、續駛里程超過250公里時,補貼金額最多,可達50萬 12米以上、雙層客車參照標準車1.2倍給予補助 8-10米客車,按照標準車0.8倍給予補助 6-8米客車,參照標準車的0.5倍給予補貼 6米及以下客車參照標準車的0.2倍給予補助 2017年補助標準在2016年基礎上下調20%   面向全國開放純電動客車市場,北京市採用備案制管理,只要納入國家《節能與新能源汽車示範推廣應用工程推薦車型目錄》和《免征車輛購置稅的新能源汽車車型目錄》,完成企業和產品備案,即可在京銷售。   凡是滿足交通行業相關規定的運營企業均可購置、運營純電動客車。鼓勵公交、公路客運、旅遊等領域的企業積極開展純電動客車示範推廣工作;積極鼓勵開展各種純電動客車車型示範應用。

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

【其他文章推薦】

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

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

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

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

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

中國有望成全球最大電動車市場

11日,在中國汽車工業協會新聞發佈會上,中汽協常務副會長兼秘書長董揚指出,新能源汽車正從示範向增長階段發展,逐漸成為中國汽車行業的重要組成部分,中國有望成為全球最大的電動汽車市場。   中國汽車工業協會的最新資料顯示,1-7月,新能源汽車生產95530輛,銷售89549輛,同比分別增長2.5倍和2.6倍;7月當月,新能源汽車銷售同比增長3.3倍。   據《中國汽車消費者白皮書》分析,政策導向、續航里程、充電時間和售後保障將成為決定新能源車發展速度的主要因素。

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

【其他文章推薦】

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

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

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

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

LG 化學獲長安汽車 PHEV 訂單 搶攻中國車用電池市場!

車用電池龍頭LG化學 (LG Chem) 將供應車用電池給中國當地汽車大廠長安汽車使用,LG化學從 2009 年就和長安汽車於電動車用電池相關技術進行合作,而在和中國國內電池廠經過激烈競爭之後,LG 化學將獨家供應電池給長安汽車預計於明年量產的次世代插電式油電混合車 (PHEV) 使用。   LG 化學正在江蘇省南京市興建一座年產能可達 10 萬台以上的電池工廠、並計畫於今年內完工,據 LG 化學電池事業本部長權英壽表示,在得到長安汽車的訂單之後,中國前 10 大車廠中、LG 化學已獲得長城汽車、東風汽車等半數車廠的訂單。   韓國時報 (Korea Times) 先前報導,LG Chem 積極布局中國電動車市場,在中國設廠拉客。該公司 5 月 17 日宣布和中國長城汽車 (Great Wall Motor) 簽約,將成為長城電動車的電池供應商,替 2017 年上市的新車供貨。LG Chem 目標是成為中國的車用電池霸主。  

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

【其他文章推薦】

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

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

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

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

mpvue+小程序雲開發,純前端實現婚禮邀請函(相冊小程序)

請勿使用本文章及源碼作為商業用途!

前言

當初做這個小程序是為了婚禮前的需要,結婚之後,希望這個小程序能夠留存下來,特地花了一些空閑時間將小程序轉化成為“相冊類小程序”

體驗碼

準備工作

  1. mpvue框架 
  2. 小程序·雲開發 

注意:使用mpvue前,首先你得先熟悉vue框架的基本使用 

項目結構介紹

注意:接下來展示的代碼,有幾個對比,分別是本人優化前和優化后的代碼對比,感興趣的可以着重看一下優化后的成熟寫法。

  • common目錄: 放一些公共資源,如js,css,json
  • components目錄:組件相關的.vue文件都放在這裏
  • pages目錄:所有頁面都放在這個目錄
  • utils目錄:使用mpvue時自動生成,可忽略
  • app.json文件:
{
  "pages": [ "pages/index/main", "pages/photo/main", "pages/map/main", "pages/greet/main", "pages/message/main" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, "tabBar": { "color": "#ccc", "selectedColor": "#ff4c91", "borderStyle": "white", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/index/main", "iconPath": "static/images/1-1.png", "selectedIconPath": "static/images/1-2.png", "text": "邀請函" }, { "pagePath": "pages/photo/main", "iconPath": "static/images/2-1.png", "selectedIconPath": "static/images/2-2.png", "text": "甜蜜相冊" }, { "pagePath": "pages/map/main", "iconPath": "static/images/3-1.png", "selectedIconPath": "static/images/3-2.png", "text": "酒店導航" }, { "pagePath": "pages/greet/main", "iconPath": "static/images/4-1.png", "selectedIconPath": "static/images/4-2.png", "text": "好友祝福" }, { "pagePath": "pages/message/main", "iconPath": "static/images/5-1.png", "selectedIconPath": "static/images/5-2.png", "text": "留言評論" } ] }, "requiredBackgroundModes": ["audio"] }
  • App.vue文件 (本人主要是為了增加項目更新后的提醒),所以在這個文件加了些相關內容,內容如下:
<script>
export default { onLaunch () { // 檢測小程序是否有新版本更新 if (wx.canIUse('getUpdateManager')) { const updateManager = wx.getUpdateManager() updateManager.onCheckForUpdate(function (res) { // 請求完新版本信息的回調 if (res.hasUpdate) { updateManager.onUpdateReady(function () { wx.showModal({ title: '更新提示', content: '新版本已經準備好,是否重啟應用?', success: function (res) { if (res.confirm) { // 新的版本已經下載好,調用 applyUpdate 應用新版本並重啟  updateManager.applyUpdate() } } }) }) // 小程序有新版本,會主動觸發下載操作(無需開發者觸發)  wx.getUpdateManager().onUpdateFailed(function () { // 當新版本下載失敗,會進行回調  wx.showModal({ title: '提示', content: '檢查到有新版本,下載失敗,請檢查網絡設置', showCancel: false }) }) } }) } else { // 版本過低則無法使用該方法  wx.showModal({ title: '提示', confirmColor: '#5BB53C', content: '當前微信版本過低,無法使用該功能,請升級到最新微信版本后重試。' }) } } } </script> <style lang="stylus"> page height 100% image display block </style>
  • main.js文件:
import Vue from 'vue'
import App from './App' Vue.config.productionTip = false App.mpType = 'app' wx.cloud.init({ env: '雲開發環境ID' }) const app = new Vue(App) app.$mount()
  • functions目錄:主要放一些雲函數,這裏不清楚雲函數的文章後面會提及
  • images目錄:主要放一些靜態資源圖片

頁面介紹

首頁——邀請函

首頁着重和大家講解下背景音樂的實現方法

const audioCtx = wx.createInnerAudioContext()

 接口獲取實例

接着,通過實例的相關方法來實現音樂的播放與暫停功能

具體代碼如下:

<script>
import IndexSwiper from 'components/indexSwiper' import tools from 'common/js/h_tools' const audioCtx = wx.createInnerAudioContext() export default { name: 'Index', components: { IndexSwiper }, data () { return { isPlay: true, list: [] } }, onShow () { const that = this that.isPlay = true that.getMusicUrl() }, methods: { audioPlay () { const that = this if (that.isPlay) { audioCtx.pause() that.isPlay = false tools.showToast('您已暫停音樂播放~') } else { audioCtx.play() that.isPlay = true tools.showToast('背景音樂已開啟~') } }, getList () { const that = this const db = wx.cloud.database() const banner = db.collection('banner') banner.get().then(res => { that.list = res.data[0].bannerList }) }, getMusicUrl () { const that = this const db = wx.cloud.database() const music = db.collection('music') music.get().then(res => { let musicUrl = res.data[0].musicUrl audioCtx.src = musicUrl audioCtx.loop = true audioCtx.play() that.getList() }) } }, onShareAppMessage: function (res) { return { path: '/pages/index/main' } } } </script>

以上代碼中使用到了雲開發相關功能,文章後面會介紹,請大家稍安勿躁

相冊頁——就一個輪播圖,這裏就不過多介紹

地圖頁——這裏着重講一下地圖標籤map

map標籤 

這裏講一下標記點markers:

data () {
    return { // qqSdk: '',  markers: [{ iconPath: '../../static/images/nav.png', id: 0, latitude: 30.08059, longitude: 115.93027, width: 50, height: 50 }] } }
<template>
    <div class="map">
        <image mode="aspectFit" class="head-img" src="../../static/images/t1.png"/>
        <map class="content" id="map" longitude="115.93027" latitude="30.08059" :markers="markers" scale="18" @tap="toNav">
        </map>
        <div class="call">
            <div class="left" @tap="linkHe">
                <image src="../../static/images/he.png"/>
                <span>呼叫新郎</span>
            </div>
            <div class="right" @tap="linkShe">
                <image src="../../static/images/she.png"/>
                <span>呼叫新娘</span>
            </div>
        </div>
        <image class="footer" src="../../static/images/grren-flower-line.png"/>
    </div>
</template>

祝福頁——也是雲開發相關內容,後面會介紹

留言頁——也是雲開發相關內容,後面會介紹

雲開發介紹

project.config.json文件:

"cloudfunctionRoot": "static/functions/"

進行雲開發首先我們需要找到上面這個文件,在上面這個json文件中加上上面這行代碼

cloudfunctionRoot 用於指定存放雲函數的目錄

app.json文件:

"window": {
    "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, "cloud": true

增加字段 "cloud": true實現雲開發能力的兼容性

開通雲開發

在開發者工具工具欄左側,點擊 “雲開發” 按鈕即可開通雲開發

雲開發控制台

數據庫

 雲開發提供了一個 JSON 數據庫

 

存儲

 

雲開發提供了一塊存儲空間,提供了上傳文件到雲端、帶權限管理的雲端下載能力,開發者可以在小程序端和雲函數端通過 API 使用雲存儲功能。

 

雲函數

 

雲函數是一段運行在雲端的代碼,無需管理服務器,在開發工具內編寫、一鍵上傳部署即可運行後端代碼。

使用雲開發

雲能力初始化

在小程序端開始使用雲能力前,需先調用 wx.cloud.init 方法完成雲能力初始化

import Vue from 'vue'
import App from './App' Vue.config.productionTip = false App.mpType = 'app' wx.cloud.init({ env: '雲開發環境ID' }) const app = new Vue(App) app.$mount()

數據庫的使用

在開始使用數據庫 API 進行增刪改查操作之前,需要先獲取數據庫的引用。以下調用獲取默認環境的數據庫的引用:

const db = wx.cloud.database()

 要操作一個集合,需先獲取它的引用:

const todos = db.collection('todos')

操作數據庫的相關示例

例:首頁獲取背景音樂資源

getMusicUrl () {
      const that = this const db = wx.cloud.database() const music = db.collection('music') music.get().then(res => { let musicUrl = res.data[0].musicUrl audioCtx.src = musicUrl audioCtx.loop = true audioCtx.play() that.getList() }) }

 例:首頁獲取輪播圖數組

getList () {
      const that = this const db = wx.cloud.database() const banner = db.collection('banner') banner.get().then(res => { that.list = res.data[0].bannerList }) }

例:祝福頁,用戶送上祝福存儲用戶

<script>
import tools from 'common/js/h_tools' export default { name: 'Greet', data () { return { userList: [], openId: '', userInfo: '' } }, onShow () { const that = this that.getUserList() }, methods: { scroll (e) { console.log(e) }, sendGreet (e) { const that = this if (e.target.errMsg === 'getUserInfo:ok') { wx.getUserInfo({ success: function (res) { that.userInfo = res.userInfo that.getOpenId() } }) } }, addUser () { const that = this const db = wx.cloud.database() const user = db.collection('user') user.add({ data: { user: that.userInfo } }).then(res => { that.getUserList() }) }, getOpenId () { const that = this wx.cloud.callFunction({ name: 'user', data: {} }).then(res => { that.openId = res.result.openid that.getIsExist() }) }, getIsExist () { const that = this const db = wx.cloud.database() const user = db.collection('user') user.where({ _openid: that.openId }).get().then(res => { if (res.data.length === 0) { that.addUser() } else { tools.showToast('您已經送過祝福了~') } }) }, getUserList () { const that = this wx.cloud.callFunction({ name: 'userList', data: {} }).then(res => { that.userList = res.result.data.reverse() }) } } } </script>

獲取送祝福的好友列表

getUserList () {
      const that = this wx.cloud.callFunction({ name: 'userList', data: {} }).then(res => { that.userList = res.result.data.reverse() }) }

這裏用到了雲函數,之所以用雲函數是因為小程序端在獲取集合數據時服務器一次默認並且最多返回 20 條記錄,雲函數端這個数字則是 100。

雲函數的使用方法

上面我們講過在project.config.json文件中配置雲函數存放位置

下面是雲函數messageList的index.js文件:

不成熟寫法:

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database() const MAX_LIMIT = 100 exports.main = async (event, context) => { // 先取出集合記錄總數 const countResult = await db.collection('message').count() const total = countResult.total // 計算需分幾次取 const batchTimes = Math.ceil(total / 100) // 承載所有讀操作的 promise 的數組 const tasks = [] for (let i = 0; i < batchTimes; i++) { const promise = db.collection('message').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get() tasks.push(promise) } // 等待所有 return (await Promise.all(tasks)).reduce((acc, cur) => ({ data: acc.data.concat(cur.data), errMsg: acc.errMsg })) }

成熟寫法(分頁查詢):

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database() exports.main = async (event, context) => { const wxContext = cloud.getWXContext() const dbName = 'message' const filter = event.filter ? event.filter : null const pageNum = event.pageNum ? event.pageNum : 1 const pageSize = event.pageSize ? event.pageSize : 10 const countResult = await db.collection(dbName).where(filter).count() const total = countResult.total const totalPage = Math.ceil(total / pageSize) let hasMore if (pageNum >= totalPage) { hasMore = false } else { hasMore = true } return db.collection(dbName).orderBy('time', 'desc').where(filter).skip((pageNum - 1) * pageSize).limit(pageSize).get().then(res => { res.hasMore = hasMore res.total = total res.openId = wxContext.OPENID return res }) }

使用雲函數前,在開發者工具上,找到messageList目錄,右鍵如圖:

 點擊上傳並部署:雲端安裝依賴(不上傳node_modules)

得到如圖的提示:

 安裝完點擊完成就能使用當前雲函數了,使用方法即:

getUserList () {
      const that = this wx.cloud.callFunction({ name: 'userList', data: {} }).then(res => { that.userList = res.result.data.reverse() }) }

數組之所以要倒序是因為希望新祝福的的用戶在最前面显示 

用戶送上祝福的時候存儲用戶

這裏我們用到了雲函數獲取用戶信息,

當小程序端調用雲函數時,雲函數的傳入參數中會被注入小程序端用戶的 openid,開發者無需校驗 openid 的正確性,因為微信已經完成了這部分鑒權,開發者可以直接使用該 openid

不成熟寫法:

下面是雲函數user的index.js文件:

// 雲函數入口文件
const cloud = require('wx-server-sdk')

cloud.init()

// 雲函數入口函數
exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID } }

主要是為了獲取當前操作用戶的openid,獲取當前用戶的openid方法:

getOpenId () {
      const that = this wx.cloud.callFunction({ name: 'user', data: {} }).then(res => { that.openId = res.result.openid that.getIsExist() }) }

接着判斷當前用戶是否已經存在於數據庫中,即getIsExist()方法:

getIsExist () {
      const that = this const db = wx.cloud.database() const user = db.collection('user') user.where({ _openid: that.openId }).get().then(res => { if (res.data.length === 0) { that.addUser() } else { tools.showToast('您已經送過祝福了~') } }) }

如果得到的數組長度為零則添加改用戶到數據庫,否則則提醒當前用戶已經送過祝福

接下來介紹存儲用戶信息的方法,即addUser():

addUser () {
      const that = this const db = wx.cloud.database() const user = db.collection('user') user.add({ data: { user: that.userInfo } }).then(res => { that.getUserList() }) }

存入到數據庫的信息是這樣的:

成熟寫法(使用雲函數一次搞定):

// 雲函數入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database() exports.main = async (event, context) => { const wxContext = cloud.getWXContext() const dbName = 'user' const filter = { _openid: wxContext.OPENID } const countResult = await db.collection(dbName).where(filter).count() const total = countResult.total if (total) { return { has: true } } else { return db.collection(dbName).add({ data: { user: event.user, _openid: wxContext.OPENID, time: db.serverDate() } }) } }
toMessage (e) {
      const that = this
      if (e.target.errMsg === 'getUserInfo:ok') { wx.getUserInfo({ success: function (res) { that.userInfo = res.userInfo wx.navigateTo({ url: `/pages/writeMessage/main?avatar=${that.userInfo.avatarUrl}&name=${that.userInfo.nickName}`  }) that.addUser(that.userInfo) } }) } }, addUser (obj) { wx.cloud.callFunction({ name: 'addUser', data: { user: obj } }) }

總結 

大概的功能就是這麼多,希望可以幫助到大家,覺得寫得不錯的記得給作者點個贊,你們的支持是我不斷更新的最大動力!

源碼地址

後續優化

  • 留言審核
  • 一些動畫效果
  • 分頁處理
  • 雲函數優化
  • 回到頂部

最後

一開始不清楚隨筆和文章的區別,還是希望這篇隨筆能展示在博客園首頁(所以改成隨筆),讓更多的朋友看到

希望對那些有想法又不會後台開發的朋友一些啟示作用,祝你早日做出只屬於自己的小程序。

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

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

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

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

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

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

Springboot中的緩存Cache和CacheManager原理介紹

背景理解

什麼是緩存,為什麼要用緩存

程序運行中,在內存保持一定時間不變的數據就是緩存。簡單到寫一個Map,裏面放着一些key,value數據,就已經是個緩存了

所以緩存並不是什麼高大上的技術,只是個概念,把要多次使用的東西存在一個變量里,時不時取出來使用,就達到了緩存的目的,緩存就是存放數據的容器

那為什麼要用緩存呢,是因為要多次使用。一個程序總有一些數據時可預見被多次使用(預見的準不準就是常說的命中率)

比如一個複雜的計算結果,一次數據庫訪問取得的數據等耗時耗資源的數據就能放入緩存,目的就是為了節省開銷,我們要用有限的資源(CPU,內存,帶寬等等)盡量做最多的事情。

為什麼要用SpringCache(緩存的演變過程)

緩存的思考

如果我們要設計一個緩存,最基本的功能是存和取:

1.能在緩存里存放數據

2.能在緩存里取出數據

可是這不夠呀,比如以下的思考

1.取數據時判斷,數據是否存在,如果不存在是不是要數據庫取

2.如果是過期的內容是不是要更新

3.如果我有多個緩存,一個是我自己設計的HashMap緩存,一個是名聲很大的redis,還有….,那需要個緩存管理器呀

為了讓緩存更好用,更“智能”,越來越多的需求就會被提出來,而緩存就是這樣一步步演變直到SpringCache橫空出世,功能十分強大(說白了就是我們少寫很多代碼)

SpringCache的好處

SpringCache包含兩個頂級接口,Cache(緩存)和CacheManager(緩存管理器),顧名思義,用CacheManager去管理一堆Cache。

最最關鍵的地方:抱緊了Spring的大腿,可以使用註解就能完成數據進入緩存!!

給大家舉個例子,就知道多簡單了

首先,Springboot中會自動加載一個CacheManager(它有默認的實現類),所以只要寫好一個自定義的Cache即可(如果想用系統定義好的或者第三方如RedisCache也行,記得向Spring註冊這個bean即可)

@Component
public class MyCache implements Cache {
  /*
       實現接口方法,一些關於數據set和get的方法
       CacheManager是根據Cache的名字進行管理的
       所以假設這個Cache名為MyCache
  */  
}

然後在得出數據的方法上寫上註釋即可

@Cacheable(value = "MyCache",key = "#id")
public String getNavegationURLs(String id) {
        //一個獲取數據的方法
}

這樣就會在調用這個方法時,會以id為key值,在名為MyCache的Cache容器中查找(註解中value就是緩存名字,不同名字指定使用不同的緩存)

如果沒查到,則執行方法 getNavegationURLs,將返回值存入緩存

如果找到了,就直接將從緩存取值,直接返回,不用執行方法 getNavegationURLs

還有其他方便的Cache註解自行百度,重要的是我們根本不用寫任何關於調用緩存的邏輯代碼,只用關注於緩存自身的邏輯

註解如何起作用的,源碼流程大致了解

為什麼要了解源碼

最直接的原因是因為SpringCache是不支持靈活的緩存時間設置的,所以想了解大概的來龍去脈去實現一個支持緩存過期時間設置和自動更新的類(之後會寫實現博文)。

高大上的原因是想通過這次探索,去了解下Spring對類的管理機制,去接觸下AOP的實現

SpringCache源碼簡單分析

大家從上面例子有沒發現問題,Cache和CacheManager是怎樣做關聯的,其實是Spring掃包實現的

凡是繼承了Cache接口的類,都會被自動注入進CacheManager中,最終存儲於CacheManager的實現類中

 

 接着會生成被@Cacheable(或者其他SpringCache註解修飾過)的代理類,並會將管理它的CacheManager賦值進去

 看這段代碼,就知道如果要設置多個CacheManager,就得在眾多實現類的其中一個加上@Primary,不然會Spring會報錯能選擇的Bean太多而不知道用哪個

 

代理類生成后(包括會根據不同的註解生成信息類CacheOperationMetadata,到時候就會根據這個類的內容進行緩存操作,說白了就是調用我們實現Cache裏面的各種方法)

Springboot底層初始化完成后,進入我們寫的代碼邏輯

如果這時進入了該類的方法,如:

 

 代碼跟進去,你會神奇的發現進入了代理類的intercept方法,怎麼進去的呢~(具體原理看下面3.0)

 這裏面就會根據註解類型,進行緩存的邏輯判斷,然後決定會不會調用我們寫的方法~

 代理類原理介紹(AOP切面之類的都是通過代理哦)

Spring代理分為兩種:

1.JDK原生動態代理,要求被代理的類需要實現接口(通過接口來實現的代理

那麼代理類滿足以下條件:

首先實現一個InvocationHandler,方法調用會被轉發到該類的invoke()方法。 意思是:對代理對象的所有接口方法調用都會轉發到InvocationHandler.invoke()方法,在invoke()方法里我們可以加入任何邏輯,比如修改方法參數,加入日誌功能、安全檢查功能等;之後我們通過某種方式執行真正的方法體  
2.CGLIB動態代理,不要求被代理的類需要實現接口,但是final的方法無法被代理(
通過繼承來實現代理) 那麼代理類滿足以下條件: 實現一個MethodInterceptor,方法調用會被轉發到該類的intercept()方法

具體內容可以參考這篇精品博客:

如果你想自己實現代理類(就是不喜歡用工具包),其實也行啊,輸出符合class規範的二進制字節碼就行啦~~~(認真學習JVM規範吧)

 

至此,該分享的就分享完啦,有什麼問題歡迎留言一起探討~

 

 

 

 

 

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

【其他文章推薦】

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

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

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

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

【其他文章推薦】

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

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

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

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

【集合系列】- 初探java集合框架圖

一、集合類簡介

Java集合就像一種容器,可以把多個對象(實際上是對象的引用,但習慣上都稱對象)“丟進”該容器中。從Java 5 增加了泛型以後,Java集合可以記住容器中對象的數據類型,使得編碼更加簡潔、健壯。

Java集合大致可以分為兩大體系,一個是Collection,另一個是Map

  • Collection :主要由List、Set、Queue接口組成,List代表有序、重複的集合;其中Set代表無序、不可重複的集合;Java 5 又增加了Queue體系集合,代表一種隊列集合實現。
  • Map:則代表具有映射關係的鍵值對集合。

java.util.Collection下的接口和繼承類關係簡易結構圖:

java.util.Map下的接口和繼承類關係簡易結構圖:

其中,Java 集合框架中主要封裝的是典型的數據結構和算法,如動態數組、雙向鏈表、隊列、棧、Set、Map 等。

將集合框架挖掘處理,可以分為以下幾個部分
1) 數據結構
List列表、Queue隊列、Deque雙端隊列、Set集合、Map映射
2) 比較器
Comparator比較器、Comparable排序接口
3) 算法
Collections常用算法類、Arrays靜態數組的排序、查找算法
4) 迭代器
Iterator通用迭代器、ListIterator針對 List 特化的迭代器

二、有序列表(List)

List集合的特點就是存取有序,可以存儲重複的元素,可以用下標進行元素的操作

List主要實現類:ArrayList、LinkedList、Vector、Stack。

2.1、ArrayList

ArrayList是一個動態數組結構,支持隨機存取,尾部插入刪除方便,內部插入刪除效率低(因為要移動數組元素);如果內部數組容量不足則自動擴容,因此當數組很大時,效率較低。

2.2、LinkedList

LinkedList是一個雙向鏈表結構,在任意位置插入刪除都很方便,但是不支持隨機取值,每次都只能從一端開始遍歷,直到找到查詢的對象,然後返回;不過,它不像 ArrayList 那樣需要進行內存拷貝,因此相對來說效率較高,但是因為存在額外的前驅和後繼節點指針,因此佔用的內存比 ArrayList 多一些。

2.3、Vector

Vector也是一個動態數組結構,一個元老級別的類,早在jdk1.1就引入進來類,之後在jdk1.2里引進ArrayList,ArrayList大部分的方法和Vector比較相似,兩者是不同的,Vector是允許同步訪問的,Vector中的操作是線程安全的,但是效率低,而ArrayList所有的操作都是異步的,執行效率高,但不安全!

關於Vector,現在用的很少了,因為裏面的getsetadd等方法都加了synchronized,所以,執行效率會比較低,如果需要在多線程中使用,可以採用下面語句創建ArrayList對象

List<Object> list =Collections.synchronizedList(new ArrayList<Object>());

也可以考慮使用複製容器 java.util.concurrent.CopyOnWriteArrayList進行操作,例如:

final CopyOnWriteArrayList<Object> cowList = new CopyOnWriteArrayList<String>(Object);

2.4、Stack

Stack是Vector的一個子類,本質也是一個動態數組結構,不同的是,它的數據結構是先進后出,取名叫棧!

關於Stack,現在用的也很少,因為有個ArrayDeque雙端隊列,可以替代Stack所有的功能,並且執行效率比它高!

三、集(Set)

Set集合的特點:元素不重複,存取無序,無下標;

Set主要實現類:HashSet、LinkedHashSet和TreeSet。

3.1、HashSet

HashSet底層是基於 HashMap 的k實現的,元素不可重複,特性同 HashMap。

3.2、LinkedHashSet

LinkedHashSet底層也是基於 LinkedHashMap 的k實現的,一樣元素不可重複,特性同 LinkedHashMap。

3.3、TreeSet

同樣的,TreeSet也是基於 TreeMap 的k實現的,同樣元素不可重複,特性同 TreeMap;

Set集合的實現,基本都是基於Map中的鍵做文章,使用Map中鍵不能重複、無序的特性;所以,我們只需要重點關注Map的實現即可!

四、隊列(Queue)

Queue是一個隊列集合,隊列通常是指“先進先出”(FIFO)的容器。新元素插入(offer)到隊列的尾部,訪問元素(poll)操作會返回隊列頭部的元素。通常,隊列不允許隨機訪問隊列中的元素。

Queue主要實現類:ArrayDeque、LinkedList、PriorityQueue。

4.1、ArrayDeque

ArrayQueue是一個基於數組實現的雙端隊列,可以想象,在隊列中存在兩個指針,一個指向頭部,一個指向尾部,因此它具有“FIFO隊列”及“棧”的方法特性。

既然是雙端隊列,那麼既可以先進先出,也可以先進后出,以下是測試例子!

先進先出

public static void main(String[] args) {
                ArrayDeque<String> queue = new ArrayDeque<>();
        //入隊
        queue.offer("AAA");
        queue.offer("BBB");
        queue.offer("CCC");
        System.out.println(queue);
        //獲取但不出隊
        System.out.println(queue.peek());
        System.out.println(queue);
        //出隊
        System.out.println(queue.poll());
        System.out.println(queue);
}

輸出結果:

[AAA, BBB, CCC]
AAA
[AAA, BBB, CCC]
AAA
[BBB, CCC]

先進后出

public static void main(String[] args) {
                ArrayDeque<String> stack = new ArrayDeque<>();
        //壓棧,此時AAA在最下,CCC在最外
        stack.push("AAA");
        stack.push("BBB");
        stack.push("CCC");
        System.out.println(stack);
        //獲取最後添加的元素,但不刪除
        System.out.println(stack.peek());
        System.out.println(stack);
        //彈出最後添加的元素
        System.out.println(stack.pop());
        System.out.println(stack);
}

輸出結果:

[CCC, BBB, AAA]
CCC
[CCC, BBB, AAA]
CCC
[BBB, AAA]

4.2、LinkedList

LinkedList是List接口的實現類,也是Deque的實現類,底層是一種雙向鏈表的數據結構,在上面咱們也有所介紹,LinkedList可以根據索引來獲取元素,增加或刪除元素的效率較高,如果查找的話需要遍歷整合集合,效率較低,LinkedList同時實現了stack、Queue、PriorityQueue的所有功能。

例子

public static void main(String[] args) {
                LinkedList<String> ll = new LinkedList<>();
        //入隊
        ll.offer("AAA");
        //壓棧
        ll.push("BBB");
        //雙端的另一端入隊
        ll.addFirst("NNN");
        ll.forEach(str -> System.out.println("遍歷中:" + str));
        //獲取隊頭
        System.out.println(ll.peekFirst());
        //獲取隊尾
        System.out.println(ll.peekLast());
        //彈棧
        System.out.println(ll.pop());
        System.out.println(ll);
        //雙端的後端出列
        System.out.println(ll.pollLast());
        System.out.println(ll);
}

輸出結果:

遍歷中:NNN
遍歷中:BBB
遍歷中:AAA
NNN
AAA
NNN
[BBB, AAA]
AAA
[BBB]

4.3、PriorityQueue

PriorityQueue也是一個隊列的實現類,此實現類中存儲的元素排列並不是按照元素添加的順序進行排列,而是內部會按元素的大小順序進行排列,是一種能夠自動排序的隊列。

例子

public static void main(String[] args) {
        PriorityQueue<Integer> queue1 = new PriorityQueue<>(10);

        System.out.println("處理前的數據");
        Random rand = new Random();
        for (int i = 0; i < 10; i++) {
                Integer num = rand.nextInt(90) + 10;
                System.out.print(num + ", ");
            queue1.offer(num); // 隨機兩位數
        }

        System.out.println("\n處理后的數據");
        for (int i = 0; i < 10; i++) { // 默認是自然排序 [升序]
            System.out.print(queue1.poll() + ", ");
        }
}

輸出結果:

處理前的數據
36, 23, 24, 11, 12, 26, 79, 96, 14, 73, 
處理后的數據
11, 12, 14, 23, 24, 26, 36, 73, 79, 96, 

五、映射表(Map)

Map是一個雙列集合,其中保存的是鍵值對,鍵要求保持唯一性,值可以重複。

Map 主要實現類:HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties。

5.1、HashMap

關於HashMap,相信大家都不陌生,繼承自AbstractMap,key 不可重複,因為使用的是哈希表存儲元素,所以輸入的數據與輸出的數據,順序基本不一致,另外,HashMap最多只允許一條記錄的 key 為 null。

5.2、LinkedHashMap

HashMap 的子類,內部使用鏈表數據結構來記錄插入的順序,使得輸入的記錄順序和輸出的記錄順序是相同的。LinkedHashMap與HashMap最大的不同處在於,LinkedHashMap輸入的記錄和輸出的記錄順序是相同的!

5.3、TreeMap

能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用 Iterator 遍歷時,得到的記錄是排過序的;如需使用排序的映射,建議使用 TreeMap。TreeMap實際使用的比較少!

5.4、IdentityHashMap

繼承自AbstractMap,與HashMap有些不同,在獲取元素的時候,通過==代替equals ()來進行判斷,比較的是內存地址

get方法源碼部分

public V get(Object key) {
        Object k = maskNull(key);
        Object[] tab = table;
        int len = tab.length;
        int i = hash(k, len);
        while (true) {
            Object item = tab[i];
            //用==比較k和元素是否相等
            if (item == k)
                return (V) tab[i + 1];
            if (item == null)
                return null;
            i = nextKeyIndex(i, len);
        }
}

5.5、WeakHashMap

WeakHashMap繼承自AbstractMap,被稱為緩存Map,向WeakHashMap中添加元素,再次通過鍵調用方法獲取元素方法時,不一定獲取到元素值,因為WeakHashMap 中的 Entry 可能隨時被 GC 回收。

5.6、Hashtable

Hashtable,一個元老級的類,鍵值不能為空,與HashMap不同的是,方法都加了synchronized同步鎖,是線程安全的,但是效率上,沒有HashMap快!

同時,HashMap 是 HashTable 的輕量級實現,他們都完成了Map 接口,區別在於 HashMap 允許K和V為空,而HashTable不允許K和V為空,由於非線程安全,效率上可能高於 Hashtable。

如果需要在多線程環境下使用HashMap,可以使用如下的同步器來實現或者使用併發工具包中的ConcurrentHashMap

Map<String, Object> map =Collections.synchronizedMap(new HashMap<>());

5.7、Properties

Properties繼承自HashTable,Properties新增了load()和和store()方法,可以直接導入或者將映射寫入文件,另外,Properties的鍵和值都是String類型。

六、比較器

Comparable和Comparator接口都是用來比較大小的,一般在TreeSet、TreeMap接口中使用的比較多,主要用於解決排序問題。

6.1、Comparable

Comparable:對實現它的每個類的對象進行整體排序

package java.lang;
import java.util.*;

public interface Comparable<T> {
    public int compareTo(T o);
}

若一個類實現了Comparable 接口,實現 Comparable 接口的類的對象的 List 列表 ( 或數組)可以通過 Collections.sort(或 Arrays.sort)進行排序。

此外,實現 Comparable 接口的類的對象 可以用作 “有序映射 ( 如 TreeMap)” 中的鍵或 “有序集合 (TreeSet)” 中的元素,而不需要指定比較器。

使用例子:

/**
  * 實體類Person實現Comparable接口
  */
public class Person implements Comparable<Person>{
    private int age;
    private String name;

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    @Override
    public int compareTo(Person o){
        return this.age-o.age;
    }
    
    @Override
    public String toString(){
        return name+":"+age;
    }
}

測試

public static void main(String[] args) {
        Person person1 = new Person("張三",18);
        Person person2 = new Person("李四",17);
        Person person3 = new Person("王五",19);

        List<Person> list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);

        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);
}

輸出:

[張三:18, 李四:17, 王五:19]
[李四:17, 張三:18, 王五:19]
6.2、Comparator

Comparator:也是對實現它的每個類的對象進行排序

package java.util;
import ***;

public interface Comparator<T> {
    int compare(T o1, T o2);
    ......
}

如果我們的這個類Person無法修改或者沒有繼承Comparable接口,我們又要對其進行排序,Comparator就可以派上用場了。

將類Person實現的Comparable接口去掉

/**
  * 實體類Person
  */
public class Person {
    private int age;
    private String name;
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString(){
        return name+":"+age;
    }
}

測試類:

public static void main(String[] args) {
        Person person1 = new Person("張三",18);
        Person person2 = new Person("李四",17);
        Person person3 = new Person("王五",19);

        List<Person> list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);

        System.out.println(list);
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                if(o1 == null || o2 == null){
                    return 0;
                }
                //o1比o2小,返回負數
                //o1等於o2,等於0
                //o1大於o2,返回正數
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println(list);
}

輸出:

[張三:18, 李四:17, 王五:19]
[李四:17, 張三:18, 王五:19]

七、常用工具類

7.1、Collections類

java.util.Collections工具類為集合框架提供了很多有用的方法,這些方法都是靜態的,在編程中可以直接調用。整個Collections工具類源碼差不多有4000行,這裏只針對一些典型的方法進行闡述。

7.1.1、addAll

addAll:向指定的集合c中加入特定的一些元素elements

public static <T> boolean addAll(Collection<? super T> c, T… elements)
7.1.2、binarySearch

binarySearch:利用二分法在指定的集合中查找元素

#集合元素T實現Comparable接口的方式,進行查詢
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)

#元素以外部實現Comparator接口的方式,進行查詢
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
7.1.3、sort
#集合元素T實現Comparable接口的方式,進行排序
public static <T extends Comparable<? super T>> void sort(List<T> list)

#元素以外部實現Comparator接口的方式,進行排序
public static <T> void sort(List<T> list, Comparator<? super T> c)
7.1.4、shuffle

shuffle:混排,隨機打亂原來的順序,它打亂在一個List中可能有的任何排列的蹤跡。

#方法一
public static void shuffle(List<?> list)

#方法二,指定隨機數訪問
public static void shuffle(List<?> list, Random rnd)
7.1.5、reverse

reverse:集合排列反轉

#直接反轉集合的元素
public static void reverse(List<?> list)

#返回可以使集合反轉的比較器Comparator
public static <T> Comparator<T> reverseOrder()

#集合的反轉的反轉,如果cmp不為null,返回cmp的反轉的比較器,如果cmp為null,效果等同於第二個方法.
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
7.1.6、synchronized系列

synchronized系列:確保所封裝的集合線程安全(強同步)

#同步Collection接口下的實現類
public static <T> Collection<T> synchronizedCollection(Collection<T> c)

#同步SortedSet接口下的實現類
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

#同步List接口下的實現類
public static <T> List<T> synchronizedList(List<T> list)

#同步Map接口下的實現類
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)

#同步SortedMap接口下的實現類
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

7.2、Arrays類

java.util.Arrays工具類也為集合框架提供了很多有用的方法,這些方法都是靜態的,在編程中可以直接調用。整個Arrays工具類源碼有3000多行,這裏只針對一些典型的方法進行闡述。

7.2.1、asList

asList:將一個數組轉變成一個List,準確來說是ArrayList

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
}

注意:這個List是定長的,企圖添加或者刪除數據都會報錯java.lang.UnsupportedOperationException

7.2.2、sort

sort:對數組進行排序,適合byte,char,double,float,int,long,short等基本類型,還有Object類型

#基本數據類型,例子int類型數組
public static void sort(int[] a)

#Object類型數組
#如果使用Comparable進行排序,Object需要實現Comparable
#如果使用Comparator進行排序,可以使用外部比較方法實現
public static void sort(Object[] a)
7.2.3、binarySearch

binarySearch:通過二分查找法對已排序的數組進行查找。如果數組沒有經過Arrays.sort排序,那麼檢索結果未知。

適合byte,char,double,float,int,long,short等基本類型,還有Object類型和泛型。

#基本數據類型,例子int類型數組,key為要查詢的參數
public static int binarySearch(int[] a, int key)

#Object類型數組,key為要查詢的參數
#如果使用Comparable進行排序,Object需要實現Comparable
#如果使用Comparator進行排序,可以使用外部比較方法實現
public static int binarySearch(Object[] a, Object key)
7.2.4、copyOf

copyOf:數組拷貝,底層採用System.arrayCopy(native方法)實現。

適合byte,char,double,float,int,long,short等基本類型,還有泛型數組。

#基本數據類型,例子int類型數組,newLength新數組長度
public static int[] copyOf(int[] original, int newLength)

#T為泛型數組,newLength新數組長度
public static <T> T[] copyOf(T[] original, int newLength)
7.2.5、copyOfRange

copyOfRange:數組拷貝,指定一定的範圍,底層採用System.arrayCopy(native方法)實現。

適合byte,char,double,float,int,long,short等基本類型,還有泛型數組。

#基本數據類型,例子int類型數組,from:開始位置,to:結束位置
public static int[] copyOfRange(int[] original, int from, int to)

#T為泛型數組,from:開始位置,to:結束位置
public static <T> T[] copyOfRange(T[] original, int from, int to)
7.2.6、equals和deepEquals

equals:判斷兩個數組的每一個對應的元素是否相等(equals, 對於兩個數組的元素a和a2有a==null ? a2==null : a.equals(a2))

#基本數據類型,例子int類型數組,a為原數組,a2為目標數組
public static boolean equals(int[] a, int[] a2)

#Object數組,a為原數組,a2為目標數組
public static boolean equals(Object[] a, Object[] a2)

deepEquals:主要針對一個數組中的元素還是數組的情況(多維數組比較)

#Object數組,a1為原數組,a2為目標數組
public static boolean deepEquals(Object[] a1, Object[] a2)
7.2.7、toString和deepToString

toString:將數組轉換成字符串,中間用逗號隔開

#基本數據類型,例子int類型數組,a為數組
public static String toString(int[] a)

#Object數組,a為數組
public static String toString(Object[] a)

deepToString:當數組中又包含數組,就不能單純的利用Arrays.toString()了,使用此方法將數組轉換成字符串

#Object數組,a為數組
public static String deepToString(Object[] a)

八、迭代器

JCF的迭代器(Iterator)為我們提供了遍歷容器中元素的方法。只有容器本身清楚容器里元素的組織方式,因此迭代器只能通過容器本身得到。每個容器都會通過內部類的形式實現自己的迭代器。

ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
Iterator<String> it = list.iterator();//得到迭代器
while(it.hasNext()){
    String obj = it.next();//訪問元素
    System.out.println(obj);
}

JDK 1.5 引入了增強的for循環,簡化了迭代容器時的寫法

//使用增強for迭代
ArrayList<String> list = new ArrayList<String>();
list.add(new String("a1"));
list.add(new String("a2"));
list.add(new String("a3"));
for(String obj : list){
    //enhanced for statement
    System.out.println(obj);
}

九、總結

以上,主要是對java集合的整體架構進行簡單的介紹,如果有理解不當之處,歡迎指正。

十、參考

1、JDK1.7&JDK1.8 源碼
2、
3、

作者:炸雞可樂
原文出處:

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

【其他文章推薦】

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

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

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

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