相信每個人都喜歡看簡潔易懂的程式碼,程式碼可讀性也是衡量程式碼品質的重要標準之一,而本文則通過十個具體的程式設計小技巧(部分技巧並不侷限於Java
),希望能夠幫助到你。
考慮以下程式碼:
public boolean isOdd(int num) {
if (num % 2 == 1) {
return true;
} else {
return false;
}
}
我們可能會經常見到類似上面的程式碼,只需要一次簡單的if ... else ...
判斷,而判斷所得到的內容也很簡單,在這種時候,我們就可以使用三元表示式來簡化我們的程式碼,就像下面這樣:
public boolean isOdd(int num) {
return num % 2 == 1 ? true : false;
}
可以發現,通過使用... ? ... : ...
三元表示式,我們能夠寫出更加簡單的程式碼,當然這個程式碼仍然不夠簡潔,在接下來第二點會進行討論,這裡先討論三元表示式。雖然三元表示式可以簡化我們的程式碼,在很多時候也能夠簡化我們的程式碼,但是當判斷的情況過多並且語句較長的時候,我們就不應該使用三元表示式了,就像下面這種情況,我們就不應該採用三元表示式:
public int getMaxDays(int year, int month) {
// 當條件過多時, 使用三元表示就無法體現發揮簡潔的優勢了,我們應該考慮其它的方法
return month == 2 ? (isLeapYear(year) ? 29 : 28) :
(month == 4 || month == 6 || month == 9 || month == 11) ? 30 : 31;
}
private boolean isLeapYear(int year) {
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
再次考慮1中的程式碼:
public boolean isOdd(int num) {
return num % 2 == 1 ? true : false;
}
由於我們返回的結果是布林值,所以在這種情況下,我們就可以直接返回布林表示式即可,而不需要再進行條件判斷,讓程式碼不夠簡潔:
public boolean isOdd(int num) {
return num % 2 == 1;
}
在1中我們以一個反例講訴了三元表示不用改被亂用,這裡我們就先通過if
語句,來進行改寫,寫出第一版程式碼:
public int getMaxDays(int year, int month) {
int result;
if (month == 2) {
result = isLeapYear(year) ? 29 : 28;
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
result = 30;
} else {
result = 31;
}
return result;
}
private boolean isLeapYear(int year) {
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ;
}
我們為了實現單入口單出口
原則,而讓多次判斷都有依賴,如果每個判斷條件記憶體在大量的語句的時候,更會顯示出這種編寫方式的弊端,因此對於這種情況,我們通常會編寫單入口多出口
的程式碼,讓簡便情況儘快得到判斷,每個判斷語句之間不必耦合:
public int getMaxDays(int year, int month) {
if (month == 2) {
return isLeapYear(year) ? 29 : 28;
}
if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
}
return 31;
}
private boolean isLeapYear(int year) {
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
arraycopy
拷貝陣列我們有時可能因為不能在原陣列上進行修改,需要對原陣列進行一份拷貝,然後寫出類似下面這樣的程式碼:
int[] arr = {1, 2, 3, 4, 5};
int[] temp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
temp[i] = arr[i];
}
不過我們可以通過使用系統自帶的arraycopy
函數,讓程式碼更易讀,效率也更高:
int[] arr = {1, 2, 3, 4, 5};
int[] temp = new int[arr.length];
System.arraycopy(arr, 0, temp, 0, arr.length);
try ... with ...
進行資源管理當使用io
流時,我們由於需要對資源進行管理,需要寫出類似下面的程式碼,當多個資源需要管理的時候,不僅難以管理,我們還可能經常會忘記對資源的關閉:
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(""));
fis.read();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
但是通過使用try ... with ...
就可以寫出下面這樣簡便的程式碼,我們不需要再擔心資源的管理問題:
try (FileInputStream fis = new FileInputStream(new File(""))) {
fis.read();
} catch (Exception e) {
e.printStackTrace();
}
相信很多人都知道,位運算在很多情況下都能表現出更好地效能,在某些情況下也能夠簡化程式碼,這裡就講兩個小例子:
使用位移代替乘除法:
a << n // <=> a * 2^n
a >> n // <=> a / 2^n
使用位運算避免二分法中的加法溢位:
相信很多人都知道在二分查詢中,以下程式碼可能因為加法運算的溢位,導致無法得到正確的結果:
int mid = (left + right) / 2;
如果使用下面這種方法就可以避免:
int mid = left + (right - left) / 2;
但是通過使用無符號位移,我們就可以寫出下面這樣簡潔的程式碼,而且也可以避免溢位:
int mid = (left + right) >>> 1;
判斷兩號是否同號
如果不使用位運算,我們需要寫出下面這樣的程式碼:
(a >= 0 && b >= 0) || (a < 0 && b < 0)
但是如果使用^
的特性,我們就可以寫出下面這樣簡潔的程式碼:
(a ^ b) >= 0
很多時候,我們為了進行列印偵錯,都需要對陣列的資料或者字串進行分割列印,例如將[1, 2, 3]
或者"123"
列印為1, 2, 3
的格式,按照傳統的方式,我們需要寫出下面這樣的程式碼:
int[] arr = {1, 2, 3};
StringBuilder sb = new StringBuilder(String.valueOf(arr[0]));
for (int i = 1; i < arr.length; i++) {
sb.append(", ").append(arr[i]);
}
// output: 1, 2, 3
System.out.println(sb);
String str = "123";
String[] split = Pattern.compile("").split(str);
StringBuilder sb = new StringBuilder(split[0]);
for (int i = 1; i < split.length; i++) {
sb.append(", ").append(split[i]);
}
// output: 1, 2, 3
System.out.println(sb);
但是通過使用Stream
的特性,我們就能寫出下面這樣更加方便易讀的程式碼(為了程式碼的可讀性,我們通常會將鏈式呼叫拆成多行):
int[] arr = {1, 2, 3};
// output: 1, 2, 3
System.out.println(
IntStream.of(arr)
.mapToObj(String::valueOf)
.collect(Collectors.joining(", "))
);
String str = "123";
// output: 1, 2, 3
System.out.println(
Pattern.compile("")
.splitAsStream(str)
.collect(Collectors.joining(", "))
);
我們通常需要列印陣列進行偵錯,正如7中所說的那樣,但是我們通常只要能夠得出陣列的資料即可,而不在乎其形式,但是如果直接列印陣列,只會得到一個記憶體地址,不過我們其實可以通過呼叫Arrays.toString(arr)
,很容易就實現我們的需求:
int[] arr = {1, 2, 3};
// output: [1, 2, 3]
System.out.println(Arrays.toString(arr));
Stream
實現計數器有時,我們需要對陣列或者集合中的資料進行統計其次數,我們會寫出如下所示的程式碼:
int[] arr = {1, 2, 3, 4, 5, 6};
Map<Integer, Integer> map = new HashMap<>();
for (int val : arr) {
map.put(val, map.getOrDefault(val, 0) + 1);
}
如果利用Stream
,我們就能夠更加專注於我們的業務邏輯,也可加易讀:
int[] arr = {1, 2, 3, 4, 5, 6};
Map<Integer, Integer> map = IntStream.of(arr)
.boxed()
.collect(Collectors.toMap(k -> k, k -> 1, Integer::sum));
Arrays.asList(arr)
將物件陣列轉換為集合有時我們需要為了將陣列轉換為集合,然後寫出類似下面的程式碼:
String[] strs = new String[10];
List<String> list = new ArrayList<>();
for (String str : strs) {
list.add(str);
}
但是利用Array.asList(arr)
就可以寫出下面這樣簡潔的程式碼:
String[] strs = new String[10];
// Array.asList(arr)生成的結果集合無法進行資料的修改,因此需要使用 new ArrayList<>();
List<String> list = new ArrayList<>(Arrays.asList(strs));
或者使用Stream
這樣進行轉換:
String[] strs = new String[10];
List<String> list = Stream.of(strs).collect(Collectors.toList());
以上就是關於Java
的一些程式設計小技巧,希望能夠對你有些幫助。