Java開發筆記(三十五)字元串格式化

来源:https://www.cnblogs.com/pinlantu/archive/2018/12/10/10099505.html
-Advertisement-
Play Games

前面介紹了字元串變數的四種賦值方式,對於簡單的賦值來說完全夠用了,即便是兩個字元串拼接,也只需通過加號把兩個目標串連起來即可。但對於複雜的賦值來說就麻煩了,假設現在需要拼接一個很長的字元串,字元串內部包含了各種類型的變數,有整型,有雙精度型,有布爾型,有字元型,中間還夾雜著一些起粘合作用的子串,如此 ...


前面介紹了字元串變數的四種賦值方式,對於簡單的賦值來說完全夠用了,即便是兩個字元串拼接,也只需通過加號把兩個目標串連起來即可。但對於複雜的賦值來說就麻煩了,假設現在需要拼接一個很長的字元串,字元串內部包含了各種類型的變數,有整型,有雙精度型,有布爾型,有字元型,中間還夾雜著一些起粘合作用的子串,如此一來只能使勁地填寫加號,把各種變數努力加加加加上去,就像有時列印日誌調用System.out.println就非常痛苦,加號多到讓你眼花繚亂。
為了不讓加號如此橫行霸道,String類型從Java5開始,額外提供了format方法對填入字元串的各種變數進行格式化。具體地說,是在一個模板字元串中填寫類似“%s”、“%d”、“%f”這樣的記號先占幾個位置,然後給format方法的輸入參數分別指定對應位置的變數名稱,表示這些變數值依次替換模板中的“%s”、“%d”、“%f”等等記號。以上模板串用到的占位記號也叫做格式轉換符,分別說明如下:
%s : 這是字元串的占位記號,可原樣展示字元串如"Hello"。
%c : 這是字元的占位記號,可原樣展示字元如'A'。
%b : 這是布爾值的占位記號,可原樣展示true或者false。
%d : 這是十進位整數(含位元組型、短整型、整型、長整型)的占位記號,可原樣展示十進位數如255。
%o : 這是八進位整數的占位記號,填寫十進位數,格式化後會轉換成八進位數。例如,輸入整數255會輸出八進位數377。
%x : 這是十六進位整數的占位記號,填寫十進位數,格式化後會轉換成十六進位數。例如,輸入整數255會輸出十六進位數ff。
%f : 這是浮點數的占位記號,格式化後會轉換成七位小數(整數部分與小數部分加起來)。
下麵是利用format方法格式化單個變數值與多個變數值的代碼例子:

		// 往字元串填入另一個字元串
		String fromString = String.format("格式化子串的字元串:%s", "Hello");
		System.out.println("fromString="+fromString);
		// 往字元串填入字元
		String fromChar = String.format("格式化字元的字元串:%s", 'A');
		System.out.println("fromChar="+fromChar);
		// 往字元串填入布爾值
		String fromBoolean = String.format("格式化布爾值的字元串:%b", false);
		System.out.println("fromBoolean="+fromBoolean);
		// 往字元串填入十進位整數
		String fromInt = String.format("格式化整型數的字元串:%d", 255);
		System.out.println("fromInt="+fromInt);
		// 往字元串填入十六進位數
		String fromOct = String.format("格式化十六進位數的字元串:%o", 255);
		System.out.println("fromOct="+fromOct);
		// 往字元串填入八進位數
		String fromHex = String.format("格式化八進位數的字元串:%x", 255);
		System.out.println("fromHex="+fromHex);
		// 往字元串填入浮點數
		String fromFloat = String.format("格式化浮點數的字元串:%f", 3.14);
		System.out.println("fromFloat="+fromFloat);
		// 格式化字元串的時候,同時填充多個變數
		String manyVariable = String.format("以下字元串包括了多個變數值:%s,%c,%b,%d,%o,%x,%f",
				"Hello", 'A', false, 255, 255, 255, 3.14);
		System.out.println("manyVariable="+manyVariable);

 

觀察上面的代碼,可見大部分的基本類型都支持格式化,除了雙精度型。如果雙精度數的精度剛好在浮點數範圍之內,還能藉助標記%f來格式化,要是雙精度數超過了浮點數的精度,還能使用%f格式化嗎?接下來通過以下的測試代碼,看看3.1415926這個雙精度數會被%f格式化成什麼樣子:

		// 註意,雙精度數若是通過%f格式化雙精度數,則會強制轉成浮點數
		String fromDouble = String.format("雙精度數格式化後丟失精度的字元串:%f", 3.1415926);
		System.out.println("fromDouble="+fromDouble);

 

運行以上的測試代碼,列印的日誌結果如下所示:

fromDouble=雙精度數格式化後丟失精度的字元串:3.141593

 

可見使用%f格式化雙精度數,超出範圍的小數部分被強行四捨五入了,因而%f並不適合用於直接格式化雙精度型。若想讓雙精度數在格式化時不損失精度,需要程式員指定小數點後面的保留位數,比如%.8f表示格式化時保留八位小數部分,f前面的數字越大代表保留的位數越多,雙精度數的數值精度就越高。利用%.8f改寫之前的雙精度數格式化代碼,改寫後的演示代碼如下:

		// 因此,格式化雙精度數之時,需要指定小數點後面的保留位數
		String fromDecimal = String.format("格式化雙精度數的字元串:%.8f", 3.1415926);
		System.out.println("fromDecimal="+fromDecimal);

 

運行如上的演示代碼,程式運行結果如下所示:

fromDecimal=格式化雙精度數的字元串:3.14159260

 

從日誌信息可見,此時雙精度數的小數部分得以完整地保存了下來。

所謂的格式化,不單單是按照標記填寫具體數值,還要求字元串格式整齊劃一。譬如統計世界各國人口,列表中的各國人口數值應當右對齊,這樣誰多誰少方能一目瞭然。既然要求支持對齊,那麼得先明確該列數字的最大位數,之後才能在位數範圍內選擇左對齊還是右對齊。整數部分最大位數的標記方式與小數部分的保留位數類似,唯一的區別是整數位數的標記不加點號,而小數位數的標記要加點號,例如%8d表示待格式化的整數將占據八個字元空間,並且預設右對齊、左補空格。倘若要求左對齊,則格式化標記需添加符號,像%-8d表示待格式化的整數在八位空間內左對齊,並且右補空格。有時候數字代表一串編碼,即使未達到最大位數也得在左邊補0,此時格式化標記要在位數前面補充0,代表空出來的位置填0而不是填空格,如標記%08d表示待格式化的整數要求右對齊、左補0。下麵是對整數位數進行各種格式化的代碼例子:

		// 對整數分配固定長度,該整數預設右對齊、左補空格
		String fromLenth = String.format("格式化固定長度(預設右對齊)的整數字元串:(%8d)", 255);
		System.out.println("fromLenth="+fromLenth);
		// 對整數分配固定長度,且該整數左對齊、右補空格
		String fromLeft = String.format("格式化固定長度且左對齊的整數字元串:(%-8d)", 255);
		System.out.println("fromLeft="+fromLeft);
		// 對整數分配固定長度,該整數預設右對齊、左補0
		String fromZero = String.format("格式化固定長度且左補0的整數字元串:(%08d)", 255);
		System.out.println("fromZero="+fromZero);

 

運行上述的格式化代碼,得到下列的日誌列印結果:

fromLenth=格式化固定長度(預設右對齊)的整數字元串:(     255)
fromLeft=格式化固定長度且左對齊的整數字元串:(255     )
fromZero=格式化固定長度且左補0的整數字元串:(00000255)

 

由此可見,格式化後的數字既實現了右對齊,也實現了左對齊,還支持在空位補0。

一旦格式化用得多了,便會出現某個變數需要多次填入的情況,比如說“重要的事情說三遍”,後面的句子就得輸入三次,像以下代碼所示的那樣,“別遲到”三字反覆寫了三次:

		// 字元串格式化的時候,可能出現某個變數被多次填入的情況
		String fromRepeat1 = String.format("重要的事情說三遍:%s,%s,%s", "別遲到", "別遲到", "別遲到");
		System.out.println("fromRepeat1="+fromRepeat1);

 

這種做法無疑非常拖沓,不但寫起來費勁,看起來也費神。為此格式化又設計了形如“%n$s”的標記,其中n表示當前標記取的是第幾個參數值,尾巴的s就是普通的格式化標記,中間的美元符號$把兩者隔開。例如標記%1$s表示當前要取第一個參數,且該參數類型為字元串,於是前述的“重要的事情說三遍”即可簡化為以下代碼:

		// 重覆填入某個變數值,可利用“%數字$”的形式,其中“數字$”表示這裡取後面的第幾個變數值
		String fromRepeat2 = String.format("重要的事情說三遍:%1$s,%1$s,%1$s", "別遲到");
		System.out.println("fromRepeat2="+fromRepeat2);

  

現在有個比較常見的業務要求,金額數字通常都要保留小數點後面兩位,像餘額寶的每日收益就精確到小數點後兩位的單位分。此時採取標記%.2f即可實現要求,但是餘額寶內部對賬可不能僅僅保留兩位小數,一般至少保留小數點後三位的單位釐,那麼對賬用的格式化標記就變成了%.3f。這樣有的場合要求更高精度,有的場合精度要求不高,意味著標記%.nf中間的n值是隨時變化著的。若要處理變化的輸入數值,必須通過方法實現相關功能,也就是需要設計一個新方法,該方法的輸入參數包括待格式化的數字,以及需要保留的小數位數,方法的返回值為截取指定小數位的字元串。
對於雙精度數字來說,此時要先根據小數位數構建一個形如%.nf的格式化標記串,再依據該標記格式化最終的數值字元串。由於百分號%是格式化的保留字元,因此要用兩個百分號%%來表達一個百分符號%,於是雙精度數的小數位數格式化代碼書寫如下:

	// 對雙精度類型的變數截取小數位,多餘部分的數字預設四捨五入
	public static String formatWithDouble(double value, int digit) {
		// 先根據小數位數構建格式化標記串。兩個百分號%%可轉義為一個百分符號%
		String format = String.format("%%.%df", digit);
		// 再依據該標記對具體數字進行字元串格式化
		String result = String.format(format, value);
		return result;
	}

 

對於大小數類型而言,BigDecimal提供了專門的setScale方法,該方法不但允許指定截取的小數位,還支持設置特定的舍入規則,當然通常情況使用RoundingMode.HALF_UP代表四捨五入即可。下麵便是截取大小數的方法代碼例子:

	// 對大小數類型的變數截取小數位,可指定多餘部分數字的舍入規則
	public static String formatWithBigDecimal(BigDecimal value, int digit) {
		// 大小數類型的setScale方法需要指定明確的舍入規則,其中HALF_UP表示四捨五入
		BigDecimal result = value.setScale(digit, RoundingMode.HALF_UP);
		return result.toString();
	}

 

接下來外部分別調用上面的雙精度數格式化方法formatWithDouble,以及大小數格式化方法formatWithBigDecimal,具體的測試調用代碼如下所示:

		double normalDecimal = 19.895;
		// 保留雙精度數的小數點後面兩位
		String normalResult = formatWithDouble(normalDecimal, 2);
		System.out.println("normalResult="+normalResult);
		BigDecimal bigDecimal = new BigDecimal("123456789012345678.901");
		// 保留大小數的小數點後面兩位
		String bigResult = formatWithBigDecimal(bigDecimal, 2);
		System.out.println("bigResult="+bigResult);

 

運行上述的精度格式化代碼,輸出以下的日誌列印信息:

normalResult=19.90
bigResult=123456789012345678.90

 

可見不管是雙精度格式化,還是大小數格式化,都實現了四捨五入保留兩位小數的目標。


更多Java技術文章參見《Java開發筆記(序)章節目錄


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 責任鏈模式是一種行為型模式,將一系列處理者鏈接在一起,形成一個處理整體,將具體的請求處理者與請求者進行分離,本文介紹了職責鏈模式的意圖,使用場景,以及結構,角色模塊,並且給出來了Java版本的責任鏈模式實現。 ...
  • 博主按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前採用 (_靠這吃飯_)和 (_純粹喜歡_)兩種語言實現。誠然,每種設計模式都有多種實現方式,但此小冊只記錄最直截了當的實現方式 :) 0. 項目地址 "每天一個設計模式之訂閱 發佈模式·原文地址" "本節課代碼" "《每天一個設計模式·系列 ...
  • 裝飾模式(Decorator Pattern)是一種比較常見的模式。 定義: 動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。 裝飾模式類圖如下所示。 裝飾模式有以下4個角色。 抽象構件(Component)角色:用於規範需要裝飾的對象(原始對象)。 具體構件(Con ...
  • 我們首先來思考一個問題:作為工程師,我們的價值是什麼? 筆者認為是—— 解決用戶問題 。 我們的任何知識和技能,如果不能解決特定的問題,那麼就是無用的屠龍之術;我們的任何經驗,如果不能對解決新的問題有用,那這經驗就是過時的。工程師不是空談者,也不是理論家,再好的理論,再好的設計,不能落地變成產品,不 ...
  • 返回字元出現的第一個位置, 如果字元在被搜索字元串的開頭, 則會返回 ‘0’ 因此, 在使用此函數判斷 字元串是否包含 某一個字元時 使用: 1 ...
  • pom.xml(對Kaptcha.jar的引用) spring-mvc.xml(Kaptche的相關設置) BaseController.java(驗證碼獲取Controller) 前臺js(初始化驗證碼圖片) 當寫完前臺代碼,訪問login.jsp時驗證碼獲取失敗(Status Code:302 ...
  • java基礎之XML 1. XML解析概述 2. DOM4J介紹 2.1 常用包 2.2 內置元素 2.2 Element類 2.3 Attribute類 2.4 常用操作 3. 代碼演示 3.1 DOM4J讀取xml文件 3.2 DOM4J創建xml文件 3.2 DOM4J修改xml文件 ...
  • 在前面,我用了3篇文章解釋python的面向對象: 1. "面向對象:從代碼復用開始" 2. "面向對象:設置對象屬性" 3. "類和對象的名稱空間" 本篇是第4篇,用一個完整的示例來解釋面向對象的一些細節。 例子的模型是父類Employe和子類Manager,從類的定義開始,一步步完善直到類變得完 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...