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种加密程序,同时再找到一些完全不可解密的加密算法

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