00 11Java高級之開發支持類庫

1 UUID類

UUID是一種生成無重複字符串的一種程序類,這種程序類的主要功能是根據時間戳實現一個自動的無重複的字符串定義。

public final class UUID extends Object implements Serializable, Comparable<UUID>

一般在獲取UUID的時候往往都是隨機生成的一個內容,,所以可以通過如下方式獲取:
(1)獲取UUID對象:public static UUID randomUUID()
(2)根據字符串獲取UUID內容:public static UUID fromString​(String name)

package cn.victor.demo;

import java.util.UUID;

public class DateDemo {

	public static void main(String[] args) {
		UUID uuid = UUID.randomUUID();
		System.out.println(uuid.toString());
	}
}


在對一些文件進行自動命名處理的情況下,UUID類型非常好用。文件上傳處理使用UUID來處理是最方便的。

2 Optional類

Optional類的主要功能是進行null的相關處理,在以前進行程序開發的時候,如果爲了防止程序之中出現空指向的異常,往往可以追加有null驗證。
範例:傳統引用傳遞問題

package cn.victor.demo;

public class DateDemo {
	
	public static void main(String[] args) {
		MessageUtil.useMessage(MessageUtil.getMessage());
	}
}

class MessageUtil{
	private MessageUtil() {}
	
	public static IMessage getMessage() {
		return new MessageImple();
	}
	
	public static void useMessage(IMessage msg) {
		System.out.println(msg.getContent());   //有可能因爲出現null,而導致空指向異常
	}
}

interface IMessage{
	public abstract String getContent();
}

class MessageImple implements IMessage{
	public String getContent() {
		return "lks loves hhy";
	}
}




在引用接收的一方往往都是被動的進行判斷,所以爲了解決這種被動的處理操作,在Java類中提供有一個Optional的類,這個類可以實現null的處理操作,在這個類裏面提供有如下的一些操作方法:
(1)返回空的數據:public static <T> Optional<T> empty()
(2)獲取數據:public T get()
(3)保存數據,但不允許出現null:public static <T> Optional<T> of​(T value)
|——如果在保存數據的時候存在有null,則會拋出NullPointerException異常
(4)保存數據,允許爲null:public static <T> Optional<T> ofNullable​(T value)
(5)空的時候返回其它數據:public T orElse​(T other)

範例:修改程序,按照正規的結構完成

package cn.victor.demo;

import java.util.Optional;

public class DateDemo {
	
	public static void main(String[] args) {
		MessageUtil.useMessage(MessageUtil.getMessage().get());
	}
}

class MessageUtil{
	private MessageUtil() {}
	
	public static Optional<IMessage> getMessage() {
		return Optional.of(new MessageImple());
	}
	
	public static void useMessage(IMessage msg) {
		System.out.println(msg.getContent());   //有可能因爲出現null,而導致空指向異常
	}
}

interface IMessage{
	public abstract String getContent();
}

class MessageImple implements IMessage{
	public String getContent() {
		return "lks loves hhy";
	}
}




如果說現在數據保存的內容是null,則就會在保存處出現異常:

由於Optional類中允許保存有null的內容,所以在數據獲取的時候也可以進行null的處理。如果爲null,使用get()獲取數據,就會出現Exception in thread "main" java.util.NoSuchElementException: No value present所以換成orElse()方法。
範例:處理null

package cn.victor.demo;

import java.util.Optional;

public class DateDemo {
	
	public static void main(String[] args) {
		MessageUtil.useMessage(MessageUtil.getMessage().orElse(new MessageImpl()));
	}
}

class MessageUtil{
	private MessageUtil() {}
	
	public static Optional<IMessage> getMessage() {
		return Optional.ofNullable(null);
	}
	
	public static void useMessage(IMessage msg) {
		System.out.println(msg.getContent());   //有可能因爲出現null,而導致空指向異常
	}
}

interface IMessage{
	public abstract String getContent();
}

class MessageImpl implements IMessage{
	public String getContent() {
		return "lks loves hhy";
	}
}




在所有的引用數據類型的操作處理之中,null是一個重要的技術問題,所以JDK 1.8之後提供的這個新的類對於null的處理很有幫助,同時也是在日後進行項目開發之中使用次數很多的一個程序類。

3 ThreadLocal類

在真正去了解ThreadLocal類對象作用的時候下面編寫一個簡單的程序做一個先期的分析。
範例:現在定義一個這樣的結構

package cn.victor.demo;

public class DateDemo{
	public static void main(String[] args) {
		Message msg = new Message();
		msg.setInfo("lks loves hhy!");
		Channel.setMessage(msg);
		Channel.send();
	}
}

class Channel{
	private static Message msg;
	
	private Channel() {}
	
	public static void setMessage(Message msg) {
		Channel.msg = msg;
	}
	
	public static void send() {
		System.out.println("[Message sending]" + msg.getInfo());
	}
}

class Message{
	private String info;
	
	public Message() {}
	
	public void setInfo(String info) {
		this.info = info;
	}
	
	public String getInfo() {
		return this.info;
	}
}





對於當前程序實際上採用的是一種單線程的模式來進行處理的。那麼如果在多線程的狀態下能否實現完全一致的操作效果呢?爲此將啓動三個線程處理。
範例:多線程的影響

package cn.victor.demo;

public class DateDemo{
	public static void main(String[] args) {
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksA loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		}, "Thread-A").start(); 
	
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksB loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		},"Thread-B").start(); 
		
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksC loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		},"Thread-C").start(); 
		
	}
}

class Channel{
	private static Message msg;
	
	private Channel() {}
	
	public static void setMessage(Message msg) {
		Channel.msg = msg;
	}
	
	public static void send() {
		System.out.println(Thread.currentThread().getName() + "[Message sending]" + msg.getInfo());
	}
}

class Message{
	private String info;
	
	public Message() {}
	
	public void setInfo(String info) {
		this.info = info;
	}
	
	public String getInfo() {
		return this.info;
	}
}




這是消息的處理產生了影響。

在保持Channel(所有發送的通道)核心結構不改變的情況下,需要考慮到每個線程的獨立操作問題。那麼在這樣的情況下就發現對於Channel類而言除了要保留髮送的消息之外,還應該多存放有一個線程的標記(當前線程),那麼這個時候就可以通過ThreadLocal來存放數據。在ThreadLocal提供有如下的操作方法:
(1)構造方法:public ThreadLocal()
(2)設置數據:public void set​(T value)
(3)取出數據:public T get()
(4)刪除數據:public void remove()

範例:解決線程同步問題

package cn.victor.demo;

public class DateDemo{
	public static void main(String[] args) {
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksA loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		}, "Thread-A").start(); 
	
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksB loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		},"Thread-B").start(); 
		
		new Thread(()->{
			Message msg = new Message();
			msg.setInfo("lksC loves hhy!");
			Channel.setMessage(msg);
			Channel.send();
		},"Thread-C").start(); 
		
	}
}

class Channel{
	private static final ThreadLocal<Message> THREADLOCAL = new ThreadLocal<Message>();
	
	private Channel() {}
	
	public static void setMessage(Message msg) {
		THREADLOCAL.set(msg);
	}
	
	public static void send() {
		System.out.println(Thread.currentThread().getName() + "[Message sending]" + THREADLOCAL.get().getInfo());
	}
}

class Message{
	private String info;
	
	public Message() {}
	
	public void setInfo(String info) {
		this.info = info;
	}
	
	public String getInfo() {
		return this.info;
	}
}




每個線程通過ThreadLocal只允許保存一個數據。

4 定時調度

定時器的主要操作是進行定時任務的處理,就好比你們每天早上起來的鈴聲一樣。在Java中提供有定時任務的一個支持,但是這種任務的處理只是實現了一種間隔觸發的操作。

如果要想實現定時的處理操作主要需要一個定時操作的主體類,以及定時任務的控制。可以使用兩個類實現:
(1)java.util.TimerTask類:實現定時任務處理;
(2)java.util.Timer類:進行任務的啓動,啓動的方法:
|——任務啓動:public void schedule​(TimerTask task, long delay)
|——間隔觸發:public void scheduleAtFixedRate​(TimerTask task, long delay, long period)

範例:實現定時任務的處理

package cn.victor.demo;

import java.util.Timer;
import java.util.TimerTask;

class MyTask extends TimerTask{

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "Timer Task, Time now: " +System.currentTimeMillis());
	}
	
}

public class DateDemo{
	public static void main(String[] args) {
		Timer timer = new Timer();
		//timer.schedule(new MyTask(), 100);
		//定義間隔任務,100毫秒後開始執行,每個1秒再次執行。
		timer.scheduleAtFixedRate(new MyTask(), 100, 1000);
	}
}

這種定時是由JDK最原始的方式提供的支持,但是實際開發之中利用此類方式進行的定時處理實現的代碼會非常的複雜。

5 Base64加密與解密

正常來講加密永遠都要伴隨着解密,所謂的加密或者是解密往往都需要有一些所謂的規則。在JDK 1.8開始,提供有新的加密處理操作類,Base64處理,在這個類裏面有兩個內部類:
(1)Base64.Encoder:進行加密處理:
|——加密處理:public byte[] encode​(byte[] src)
(2)Base64.Decoder:進行解密處理:
|——解密處理:public byte[] decode​(byte[] src)
|——解密處理:public byte[] decode​(String src)

範例:實現加密和解密操作

package cn.victor.demo;

import java.util.Base64;

class Base64Util{
	private Base64Util() {}
	private static Base64.Decoder myBase64De = Base64.getDecoder();
	private static Base64.Encoder myBase64En = Base64.getEncoder();
	
	public static String encode(String src) {
		byte[] bytes = src.getBytes();
		return new String(myBase64En.encode(bytes));
	}
	
	public static String decode(String src) {
		return new String(myBase64De.decode(src));
	}
}

public class DateDemo{
	public static void main(String[] args) {
		String temp = "";
		System.out.println(temp = Base64Util.encode("lks loves hhy!"));  //encode
		System.out.println(Base64Util.decode(temp));  //decode
	}
}

雖然Base64可以實現加密與解密的處理,但是由於其是一個公版的算法,所以如果直接對數據進行加密往往並不安全,那麼最好的做法是使用鹽值操作。

範例:鹽值操作實現加密

package cn.victor.demo;

import java.util.Base64;

class Base64Util{
	private Base64Util() {}
	private static Base64.Decoder myBase64De = Base64.getDecoder();
	private static Base64.Encoder myBase64En = Base64.getEncoder();
	private static final String SALT = "{forever}";
	
	public static String encode(String src) {
		src += SALT;
		byte[] bytes = src.getBytes();
		return new String(myBase64En.encode(bytes));
	}
	
	public static String decode(String src) {
		return new String(myBase64De.decode(src));
	}
}

public class DateDemo{
	public static void main(String[] args) {
		String temp = "";
		System.out.println(temp = Base64Util.encode("lks loves hhy!"));  //encode
		System.out.println(Base64Util.decode(temp).replaceAll("\\{\\w+\\}", ""));  //decode
	}
}

即便現在有鹽值實際上發現加密的效果也不是很好,最好的做法是多次加密。
範例:複雜加密操作

package cn.victor.demo;

import java.util.Base64;

class Base64Util{
	private Base64Util() {}
	private static Base64.Decoder myBase64De = Base64.getDecoder();
	private static Base64.Encoder myBase64En = Base64.getEncoder();
	private static final String SALT = "{forever}";
	private static final int COUNT = 3;
	
	public static String encode(String src) {
		src += SALT;
		byte[] bytes = src.getBytes();
		
		for(int i =0; i < COUNT; i++) {
			bytes = myBase64En.encode(bytes);
		}
		return new String(bytes);
	}
	
	public static String decode(String src) {
		byte[] bytes = src.getBytes();
		for(int i =0; i < COUNT; i++) {
			bytes = myBase64De.decode(bytes);
		}
		return new String(bytes).replaceAll("\\{\\w+\\}", "");
	}
}

public class DateDemo{
	public static void main(String[] args) {
		String temp = "";
		System.out.println(temp = Base64Util.encode("lks loves hhy!"));  //encode
		System.out.println(Base64Util.decode(temp));  //decode
	}
}

最好的做法是使用2-3種加密程序,同時再找到一些完全不可解密的加密算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章