开发支持类库
UUID类
UUID是一种生成无重复字符串的一种程序类,这种程序类的主要功能是根据时间戳实现一个自动的无重复的字符串定义。
一般在获取UUID的时候往往都是随机生成的内容,可以通过如下的方式获取:
//获取UUID对象
public static UUID randomUUID()
//根据字符串获取UUID内容
public static UUID fromString(String name)
在对一些文件继续自动命名处理的情况下,UUID类型非常好用
Optional类
Optional类的主要功能是进行null的相关处理,在以前进行程序开发时,为了防止程序中出现空指针异常,往往可以追加有null的验证。
传统引用传递问题:
interface IMessage{
public String getContent();
}
class MessageImpl implements IMessage{
@Override
public String getContent() {
return "message";
}
}
class MessageUtil{
private MessageUtil (){
}
public static IMessage getMessage(){
return new MessageImpl();
}
public static void useMessage(IMessage msg){
System.out.println(msg.getContent());//有可能因为出现null,而导致空指向
}
}
public class OptionalDemo {
public static void main(String[] args) {
MessageUtil.useMessage(null);
}
}
在引用接收的一方,往往都是被动的进行判断。为了解决被动的处理操作,在Java类中提供有Optional类,这个类可以实现空的处理操作,在这个类里提供有如下的一些操作方法:
//返回空数据
public static <T> Optional<T> empty()
//获取数据
public T get()
//空的时候返回其他数据
public T orElse(T other)
//保存数据,但是不允许出现null 如果在保存数据的时候有null,则会抛出NullPointerException
public static<T> Optional<T>of (T value)
//保存数据,允许为空
public static<T>Optional<T> ofNullable(T value)
修改程序,按照正规的结构完成:
class MessageUtil{
public static Optional<IMessage> getMessage(){
return Optional.of(New MessageImpl) //有对象
}
}
public class OptionalDemo {
public static void main(String[] args) {
IMessage temp = MessageUtil.getMessage().get(); //获取数据
MessageUtil.useMessage(temp);
}
}
如何说现在数据保存的内容是null,那就会在保存处出现异常
由于Optional类允许保存有null的内容,所以在数据获取时也可以进行null的验证
但是如果数据为空,则在使用get方法获取数据的时候就会出现:
“Exception in thread “main” java.util.NoSuchElementException: No value present”异常信息
IMessage temp = MessageUtil.getMessage().orElse(new MessageImpl());
MessageUtil.useMessage(temp);
在所有引用类型的操作处理中,null是一个重要的技术问题,JDK1.8之后提供了新的类,对于null的处理很有帮助,同时也是在日后进行项目开发之中使用次数很多的一个程序类。
ThreadLocal
class Message{//发送的消息体
private String info;
public void setInfo(String info){
this.info=info;
}
public String getInfo(){
return this.info;
}
}
class Channel{//消息的发送通道
private static Message message;
public static void setMessage(Message m){
message=m;
}
public static void sendMessage(){//设置消息
System.out.println("消息发送"+message.getInfo());
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
Message message=new Message();
message.setInfo("message");
Channel.setMessage(message);
Channel.sendMessage();
}
}
对于当前程序实际上采用的是一种单线程的模式来进行处理的。那么如果在多线程的状态下,能否实现一致的操作效果呢?为此将启动三个线程进行处理。
范例:多线程的影响
public static void main(String[] args) {
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第一个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者A").start();
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第二个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者B").start();
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第三个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者C").start();
}
这个时候消息的处理产生了影响
在保持Channel核心结构不改变的情况下,需要考虑每个线程独立操作问题,对于Channel类而言,除了要保留有要发送的消息之外,还应该多存放有一个每一个线程的标记(当前线程),那么这个时候就可以使用ThreadLocal类来存放数据。
在ThreadLocal中提供有如下的方法:
//构造数据
public ThreadLocal()
//设置数据
public void set(T value)
//取出数据
public T get()
//删除数据
public void remove()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQ6sV4YW-1680073892416)(…\img\ThreadLocalFull.jpg)]
class Message{//发送的消息体
private String info;
public void setInfo(String info){
this.info=info;
}
public String getInfo(){
return this.info;
}
}
class Channel{//消息的发送通道
private static final ThreadLocal<Message> THREADLOCAL=new ThreadLocal<Message>();
public static void setMessage(Message m){
THREADLOCAL.set(m);//向ThreadLocal中保存数据
}
public static void sendMessage(){//设置消息
System.out.println("【"+Thread.currentThread().getName()+"发送消息】"+THREADLOCAL.get().getInfo());
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第一个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者A").start();
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第二个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者B").start();
new Thread(()->{
Message msg = new Message();//实例化消息主体对象
msg.setInfo("第三个线程的消息");//设置要发送的内容
Channel.setMessage(msg);
Channel.sendMessage();
},"消息发送者C").start();
}
}
每一个线程通过ThreadLocal只能够存放一个数据
定时调度
定时器的主要操作是进行定时任务的处理,但是这种任务的处理只是实现了一种间隔出发的操作。
如果想要实现定时的处理操作主要需要有一个定时操作的主体类,以及一个定时任务的控制,可以使用两个类实现:
-
java.util.TimerTasker类 实现定时任务处理
-
java.util.Timer类进行任务的启动
//任务启动 public void schedule(TimerTasker task,long delay) //延迟单位是毫秒 //间隔触发 public void scheduleAtFixRate(TimerTasker task,long delay,period)
范例:实现定时任务处理
import java.util.Timer;
import java.util.TimerTask;
class MyTask extends TimerTask {//任务处理
@Override
public void run() {//多线程的处理方法
System.out.println(Thread.currentThread().getName()+"、定时任务执行、当前时间、"+System.currentTimeMillis());
}
}
public class TimerTaskDemo {
public static void main(String[] args) {
Timer time=new Timer();
timer.schedule(new MyTask(),0);//延迟时间设置为零表示立即启动
//定义间隔任务,100毫秒后开始执行,每1000毫秒执行一次
timer.scheduleAtFixedRate(new MyTask(),100,1000);
}
}
Timer的缺点:
Timer对调度的支持是基于绝对时间,而不是基于相对时间,由此任务对系统时钟的改变是敏感的。
这种定时是由JDK最原始的方式提供的支持,但实际开发之中利用此类方法进行定时处理的代码会非常复杂。
Base64解密和解密
JDK1.8提供有新的加密处理操作类,Base64
Base64类中有两个内部类:
-
Base64Encoder 进行加密处理
//加密处理 public byte[] encode(byte[] src)
-
Base64Decoder 进行解密处理
//解密处理 public byte[] decode(String src)
范例 实现加密解密操作
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String message="message";
//加密
String messageEncode = new String(Base64.getEncoder().encode(message.getBytes()));
System.out.println(messageEncode);
//解密
String messageDecode = new String(Base64.getDecoder().decode(messageEncode));
System.out.println(messageDecode);
}
}
虽然Base64可以实现加密和解密的操作,但是由于其是一个公版的算法,所以如果对其进行加密,最好的做法是使用盐值操作。
使用盐值加密
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String salt="salt";
String message="message"+salt;
//加密
String messageEncode = new String(Base64.getEncoder().encode(message.getBytes()));
System.out.println(messageEncode);
//解密
String messageDecode = new String(Base64.getDecoder().decode(messageEncode));
System.out.println(messageDecode);
}
}
即使有盐值处理,加密效果仍然不是很好,所以要用到多次加密。
范例 多次加密处理
import java.util.Base64;
class StringUtil{
public static final String SALT="salt";//公共的盐值
public static final int REPEAT=3;//加密次数
/**
* 加密处理
* @param str 要加密的字符串,需要与盐值整合
* @return {@link String} 加密后的数据
*/
public static String encode(String str){
String temp=str+SALT;
byte[] data=temp.getBytes();
for (int i = 0; i < REPEAT; i++) {
data= Base64.getEncoder().encode(data);
}
return data.toString();
}
public static String decode(String str){
System.out.println("解码字符串"+str);
byte[] data=str.getBytes();
for (int i = 0; i < REPEAT; i++) {
data = Base64.getDecoder().decode(data);
}
return new String(data).replaceAll("\\{\\w+\\}","");
}
}
public class Base64Demo {
public static void main(String[] args) throws Exception{
String encodeString = StringUtil.encode("message");
System.out.println(encodeString);
String decodeString = StringUtil.decode(encodeString);
System.out.println(decodeString);
}
}
return new String(data).replaceAll("\\{\\w+\\}","");
}
}
public class Base64Demo {
public static void main(String[] args) throws Exception{
String encodeString = StringUtil.encode(“message”);
System.out.println(encodeString);
String decodeString = StringUtil.decode(encodeString);
System.out.println(decodeString);
}
}
最好的做法是使用2-3种加密方法,同时再找到一些完全不可解密的算法。