發表文章

一段全都是蛋的簡易Java故事化教學例範程式碼

圖片
插圖: Alfredobear 因為聽到某熊聊到,在線上程式課程中學到陣列 (Array),而且把它形容成「儲蛋格」(egg storage tray),覺得很有趣,因此瞬間就給了我一個靈感,來寫一小段Java物件與串流的教學範例程式。 類別 (class) 是絕大多數物件導向程式語言 (Object-Oriented Programming Languages) 的基本單元,在物件導向的理論中,class代表了我們所要描述/解決的問題體系中某一實體或概念的抽象結果。 換句話說,因為我們不能把真實的蛋放進數位世界裡(就算做得到也變成另外一回事了),因此針對我們要解決的問題,把蛋「抽象化」(通常是抽取我們要的數據、狀態或是特徵),再加上一些和蛋有關的行為或是處理工作,就成了所謂的class的基本內容,基本的框架是長這樣: class Egg { // data field, status, characteristics... // behaviors, processing tasks... } 那麼想到陣列,也就是儲蛋格(因為太囉唆以下改稱蛋架egg rack),就會想到創建一個集合型態 List ,裡面專門放蛋,像是這樣: List<Egg> eggRack; 從這裡故事就開始了,我開始導入了串流界面相關的功能了……(聽到這會眼神死的人且慢) 首先,空的蛋架很無聊,又沒有蛋可以吃,身為蛋食愛好者當然是無法接受,因此我們需要一個無限供應蛋的串流(輸送帶),源頭裝上一個專門供蛋的供應器 ( Supplier<Egg> )。但大部份時候無限供蛋也可以釀成災難,所以我們需要指定數量限制,例如一百顆就好(!),然後在末端裝上一個集蛋器,這樣就可以做為裝滿蛋的蛋架: eggRack = Stream. generate (Egg:: new ) // 無限供蛋器 . limit ( 100 ) // 限制數量以免釀災 . collect (Collectors. toList ()); // 集蛋器 這裡 Egg::new 其實就是 Supplier 格式: () -> new Egg() 的簡寫,稱做method reference,

Upper City Taris隨想—在瘟疫蔓延時

圖片
有一段旋律一直在腦海揮之不去,不書寫書寫有點難過。那是出自知名配樂家Jeremy Soule之手的一段音樂,出現在Upper City, Taris (from Star Wars: Knights of the Old Republic ) Taris是星際大戰舊共和國時期的一個著名的行星城市,在那個還沒有死星的年代,它已是經歷過大規模毀滅的星球之一。如今《舊共和國武士》已經成為星戰迷公認的聖地,配樂家的神來之筆,無疑為它增添了不少魅力。 Jeremy Soule有許多動人之作,這段配樂雖然不長,卻像一顆圓潤的珍珠般美麗。也許是想像的法國號天生具有的魔力,但因為自己是音樂創作者關係,其實平常很少有音樂可以折磨我那麼久。我一直在想是為什麼,特別是在這個瘟疫蔓延的時期。我意識到,應該有潛意識深處、更深的牽動。 Taris的城市結構,一如其它星戰地景一般,充滿了真實世界的象徵、隱喻。Upper City是上流社會、人類專屬的區域,擁有無敵的美景與視野、充斥著一片表面的祥和,即使在西斯帝國因為追捕一名絕地武士而實施隔離的時期,人們依然若無其事地在空曠的街道平台上閒晃、醉酒,或是在酒吧裡享樂、賭著Pazaak牌,完全沒有警覺大難臨頭。 愈往下,愈是幫派與非人類(Aliens)活動的地方,械鬥、競技、賽車,虛無與玩命的氣氛愈發強烈,一路到了最底層的Undercity,雖然是這個小行星唯一能踏實地踩在泥土上的地方,整個星球的自動化重型基礎設施也都在這裡,卻是一個不見天日的流放世襲罪犯之處,甚至隱藏著恐怖的瘟疫,一旦感染將變身成為可怕的怪物rakghoul,被深鎖在(隔離區中的)隔離區域之中。 然而發生在Taris還有更多細密的對話:非常時期的伙伴關係、無能為力的痛苦記憶、隱姓埋名的歲月、光明與幽暗的抉擇...等等,也許一字一句都牽動著真實生活中那些沉睡卻仍偶爾浮現的夢境。而身為超越時空的地球人,行走在Taris的每時每刻,都知道這個星球後來的結局:在西斯瘋狂的轟炸之下成為廢墟一片、原本塵封於Undercity的可怕瘟疫又重見天日...... “If the Empire has this kind of power, what chance do we have?” (如果帝國擁有這種力量,我們還能有什麼勝算?) 也許是自己的家鄉在古時就曾經歷過可怕的滅絕,來自Taris的Se

病毒肆虐下、資料集間國名比對的聯想

圖片
下面這份國家地區名單,是最近整理數據時用程式比對所列出來的結果: 181 Country/Regions loaded. Bosnia and Herzegovina Congo (Brazzaville) Congo (Kinshasa) Cote d'Ivoire Eswatini Holy See Korea, South Moldova North Macedonia Taiwan* Tanzania United Arab Emirates United Kingdom US Syria Laos Libya West Bank and Gaza Kosovo Burma 比對結果來自這兩個數據來源: NovelCOVID API based on https://www.worldometers.info/coronavirus/ https://github.com/novelcovid/api 2019 Novel Coronavirus COVID-19 (2019-nCoV) Data Repository by Johns Hopkins CSSE https://github.com/CSSEGISandData/COVID-19 這份清單產生的過程是這樣的:程式先從 1. 取得各國數據(共206個),存在資料庫中;接著由 2. 讀取國名(共181個),並與資料庫中206個國名做比對,若找不到完全吻合的,就會被列出來做進一步查核。 由於數據來源不同,想要將兩份數據放在一起比較,必須先比對出標示名稱的差異性。然而這份清單只是初步的單向比對,還未做逆向比對,因為只處理到一半,所以還不是最後的結果。不過因為觀察的過程引發了我的一些感觸,因此就先記下來。 目前清單上有二十個名稱,看起來就已經頗令人玩味,也許是因為自己的國家被打了星號,所以對這種差異特別有感觸吧? "Taiwan*" vs. "Taipei and environs" 那麼就先從星號寫起吧。可能許多人已經知道,原來JH的網站上標註的是Taiwan,但某一天大家發現突然被改成了 "Taipei and environs"(臺北與週邊地區),

泛型(generics)與函式界面(functional interface)做為強型別語言的一對翅膀

圖片
今天想來聊點泛型 (generics) 與 函式界面 (functional interface) 在強型別(strong-typed)語言中所扮演的重要角色。 身為Java愛好者、加上從事的工作和語義息息相關,不諱言地對於「強型別」的語言有一種執著。尤其在我們成長的年代,電腦並沒有像今天畫面包裝得美美的視窗防呆界面,對於機器的基底有多「固執」總有一種深刻的體會。若機器只接受整數 123 ,你一不小心給他字串 "123" ,就有可能當場「死」給你看。 而強型別語言的一板一眼有時確實也令人頭痛,就算可以運用多形 (polymorphism) 來增加語義上的彈性,仍然存在不少限制。例如我們可以用下面兩個同名函式來解決上面的問題,同時接受整數和字串: int inc ( int n) { return ++n; } int inc (String n) { return Integer. valueOf (n)+ 1 ; } 不過其實它們也就是兩個機器不會搞混的函式罷了,語義的一致性是給人類看的,機器認的是方法簽章(method signature),兩個函式實際上並沒有什麼關聯性。 當泛型和函式界面先後導入Java之後,強型別的優勢可說突然如虎添翼。為了不讓講古佔太大的篇幅,以下直接來研究一個最近實際遇到的例子。 最近因為武漢肺炎的關係,時常透過寫程式研究一些COVID-19的數據,茲舉以下這個存放某個國家某日數據的value object為例: class COVIDValue { String country; int recovered, cases, critical, active, deaths, todayCases, todayDeaths; double casesPerOneMillion, deathsPerOneMillion; // constructors, getters... } 它包含了三種不同型別( String 、 int 及 double )的資料欄位。假設我們寫了一個函式 list() 用來將存放在 List<COVIDValue> data 集合中的所有資料按某種順序列印出來,至於要依什麼順序,則由傳入的參數 k

Reply to mkyong - "Java – How to print a Pyramid"

圖片
今天來寫點小東西。 雖然從小寫程式,尤其大學時特別喜歡OOP的概念,但後來離開coding很長一段時間,並且剛好錯過了Java的崛起。多年前當我下定決心重拾寫程式的熱愛、並且從零開始學習Java時,mkyong的部落格正是親切地陪伴著我成長的資源之一。 無意間在Twitter上看到格主發的小問題,也是一樣那麼的親切: https://twitter.com/mkyong/status/1237331183827972096 因此我也試著把我的答案寫一寫,當作禮物回贈給他。 有趣的是,愈簡單的問題,似乎愈容易顯現出程式師個人的語法偏好。 謝謝mkyong! package info. muspoe . fun ; import java.util.function.Consumer ; import java.util.function.IntFunction ; import java.util.stream.IntStream ; public class MyPyramids { public static void main (String[] args) { int rows = 10 ; Consumer<IntFunction<String>> pyramidFactory = mapper -> IntStream. rangeClosed ( 1 , rows) . mapToObj (mapper) . forEach (System. out ::println); System. out . println ( "\n1. Half Pyramid\n" ); pyramidFactory. accept ( "*" ::repeat); System. out . println ( "\n2. Full Pyramid\n" ); pyramidFactory. accept (i -&g

用Neo4j撈取資料的一些小技巧:以SWAPI為例

圖片
在網路上已經有許多neo4j匯入外部資料的教學影片,這裡嘗試分享一些Cypher的撰寫技巧,用以解決幾個匯入時會遇到的小問題。 SWAPI  是  (:Starwars Fan :ProgrammingGeek)  應該都熟知的API,它提供不少星戰電影中的資訊(雖然不是最多...只有正史、而且只到 第七部曲 ):例如Planets(行星)、Spaceships(太空船)、Vehicles(太空船之外的交通工具)、People(人物)、Films(影片)、以及Species(種族)等等。 常見的撈取資料寫法大致像是這樣: WITH ' https://swapi.co/api/people/?format=json' AS url CALL apoc.load.json(url) YIELD value UNWIND value.results AS p CREATE (n: StarWarsPerson ) SET n.name=p.name, n.height=p.height, n.mass=p.mass... RETURN n; 問題一、API一次只給一部份資料 不過這裡遇到一個問題,許多API都不會一次給你所有的資料,以SWAPI為例,資料庫明明有87個人,但若不指定號碼的話,它只會吐給你前十個;除非你指定人物編號、一個一個撈出來,例如 WITH ' https://swapi.co/api/people/ 88 /?format=json' AS url CALL apoc.load.json(url) YIELD value AS p CREATE (n: StarWarsPerson ) SET n.name=p.name, n.height=p.height, n.mass=p.mass RETURN n; 指定88號,我們得到了 Captain Phasma 。 除非運用programming language API(例如Java API),否則要一個一個撈還挺煩的。不過畢竟Neo4j還是有一點迴圈的能力,所以如果我們用下面這個小技巧,以動態產生網址的方式就可以解決掉第一個問題: UNWIND range( 1 , 88 ) AS i CALL apoc.

以圖形資料建構Star Wars星戰宇宙中的行星們

圖片
Star Wars Universe(星際大戰宇宙,以下簡稱星戰宇宙)是一個極為龐大的科幻空間/文本。歷經了近半個世紀的集體創作,光是累積出來的虛構單元,例如人物、星球/星系、城市、語文、種族、科技物...等等,就多到難以勝數,加上發生在這龐大的人、事、物之間、橫跨萬年以上的複雜故事情節,規模可說非常壯觀。 從資訊量與知識架構的角度,除了官方資料之外,網路上熱心整理星戰宇宙素材的網友也是多到不勝枚舉,也有許多提供機器可讀取的格式。因為備課的需求,我便想利用這些資料來建立一個星戰宇宙圖(graph),做為大學課程的教材。