开发支持类库
UUID类
UUID是一种生成无重复字符串的一种程序类,这种程序类的主要功能是根据时间戳实现一个自动的无重复的字符串定义。
import java.util.UUID;
public class Uuid_study {
public static void main(String[] args) {
System.out.println(UUID.randomUUID());
}
}
一般在获取UUID是往往都是随机生成一个内容,随意可以通过如下方式获取:
- 获取UUID对象:
public static UUID randomUUID();
- 根据字符串获取UUID内容:
public static UUID fromString(String name);
在对一些文件进行自动命名处理的情况下,UUID类型非常好用。
Optional类
Optional类的主要功能是进行null的相关处理,在以前进行程序开发的时候,如果为了防止程序之中出现空指向异常,往往可以追加空的验证。
传统引用传递问题
interface IMessage{
public String getContent();
}
class MessageUtil{
private MessageUtil() {
}
public static IMessage getMessage() {
return null;
}
public static void useMessage(IMessage msg) {
if(msg != null) {
System.out.println(msg.getContent()); //有可能因为出现null出现空指向
}
}
}
class MessageImpl implements IMessage{
public String getContent() {
return "test";
}
}
public class Optinal_study {
public static void main(String[] args) throws Exception {
MessageUtil.useMessage(MessageUtil.getMessage());
}
}
在引用接收的一方往往都是被动的进行判断,为了解决这种被动的处理操作,在Java类中提供一个Optional类可以实现null的处理操作,在这个类中提供如下操作方法:
- 返回空的数据:
public static <T> Optinal<T> empty();
- 获取数据:
public T get();
- 保存数据,但不允许出现null:
public static <T> Optinal<T> of(T value);
- 如果保存数据是存在null,则会排除NullPointerException异常;
- 保存数据,允许为null:
public static <T> Optinal<T> ofNullable(T value);
- null的时候返回其他数据:
public T orElse(T other);
修改上述程序,按照正轨程序进行
package support_package;
import java.util.Optional;
interface IMessage{
public String getContent();
}
class MessageUtil{
private MessageUtil() {
}
public static Optional<MessageImpl> getMessage() {
return Optional.of(new MessageImpl()); //有对象
}
public static void useMessage(IMessage msg) {
if(msg != null) {
System.out.println(msg.getContent()); //有可能因为出现null出现空指向
}
}
}
class MessageImpl implements IMessage{
public String getContent() {
return "test";
}
}
public class Optinal_study {
public static void main(String[] args) throws Exception {
IMessage temp = MessageUtil.getMessage().get(); //获取数据
MessageUtil.useMessage(temp);
}
}
如果现在数据保存的内容是null,则就会在保存出出现异常;
public static Optional<IMessage> getMessage() {
return Optional.of(null); //有对象
}
由于Optional类中允许保存有null的内容,所以在数据或获取的时候恩也可以进行null的处理,但如果为空,在使用get()获取数据的时候就会出现“No value present”,此时可以更换为orElse()方法;
处理null
import java.util.Optional;
interface IMessage{
public String getContent();
}
class MessageUtil{
private MessageUtil() {
}
public static Optional<IMessage> getMessage() {
return Optional.ofNullable(null); //有对象
}
public static void useMessage(IMessage msg) {
if(msg != null) {
System.out.println(msg.getContent()); //有可能因为出现null出现空指向
}
}
}
class MessageImpl implements IMessage{
public String getContent() {
return "test";
}
}
public class Optinal_study {
public static void main(String[] args) throws Exception {
IMessage temp = MessageUtil.getMessage().orElse(new MessageImpl()); //获取数据
MessageUtil.useMessage(temp);
}
}
在所有引用数据类型的操作处理中,null是一个重要的技术问题,所以JDK1.8之后提供的这个类对于null的处理很有帮助,也是在日后开发中使用次数很多的程序类。
ThreadLocal类(重要)
在真正去了解ThreadLocal类作用的下面编写一个简单的程序做一个先期的分析:
定义一个结构
class Message{
//发送的消息体
private String info;
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
}
class Channel{
//消息发送通道
private static Message message;
private Channel() {
}
public static void setMessage(Message m) {
message =m;
}
public static void send() {
//发送消息
System.out.println("[消息发送]"+message.getInfo());
}
}
public class ThreadLocal_Study {
public static void main(String[] args) {
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("test!"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
}
}
对于当前程序实际上采用的是一种单线程的模式来进行处理;如果在多线程的情况下,能否实现完全一致的效果?为此启动三个线程进行处理。
多线程的影响
public class ThreadLocal_Study {
public static void main(String[] args) throws Exception {
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("一线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送A").start();
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("二线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送B").start();
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("三线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送C").start();
}
}
这个时候消息的处理产生了影响。
在保持Channel核心结构不改变的情况下,需要考虑到每个线程的独立操作问题,再这样的情况下,发现对于Channel类额日炎除了要保留有发送的消息之外,还应多存反有一个每一个线程的标记(当前线程),那么这个时候可以通过ThreadLocal类来存放数据,在ThreadLocal里有如下方法:
- 构造方法:
public ThreadLocal();
- 设置数据:
public void set(T value);
- 取出数据:
public T get();
- 删除数据:
public void remove();
class Message{
//发送的消息体
private String info;
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
}
class Channel{
//消息发送通道
private static final ThreadLocal<Message> THREADLOCAL = new ThreadLocal<Message>();
private Channel() {
}
public static void setMessage(Message m) {
THREADLOCAL.set(m);
}
public static void send() {
//发送消息
System.out.println(Thread.currentThread().getName()+"[消息发送]"+THREADLOCAL.get().getInfo());
}
}
public class ThreadLocal_Study {
public static void main(String[] args) throws Exception {
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("一线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送A").start();
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("二线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送B").start();
new Thread(()->{
Message msg = new Message(); //实例化消息主体对象
msg.setInfo("三线程"); //设置发送内容
Channel.setMessage(msg); //设置要发送的消息
Channel.send();
},"消息发送C").start();
}
}
每一个线程通过ThreadLocal只允许保存一个数据。
定时调度
定时器的主要操作是进行定时的处理,Java中提供定时任务的支持,但是这种任务的处理知识实现了一种间隔触发的操作。
如果要想实现定时的处理操作主要需要有一个定时操作的主体类以及一个定时任务的控制,可以使用两个类:
- java.util.TimerTask类:实现定时任务处理
- java.util.TImer类:进行任务的启动,启动的方法:
- 任务启动:
public void schedule(TimerTask task,long delay);
延迟单位为毫秒; - 间隔触发:
public void scheduleAtFixedRate(TimerTask task,long delay,long period);
- 任务启动:
实现定时任务处理
import java.util.Timer;
import java.util.TimerTask;
class MyTask extends TimerTask{
//任务主体
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"、定时任务执行,当前时间"+System.currentTimeMillis());
}
}
public class TimerTask_Study {
public static void main(String[] args) {
Timer timer = new Timer(); //定时任务
//间隔任务,100毫秒后开始执行,每秒执行1次
timer.scheduleAtFixedRate(new MyTask(), 100, 1000);
}
}
这种定时是由JDK最原始的方式提供的支持,但是实际上开发之中利用此类方式进行的定时处理会比较复杂。
Base64加密与解密
加密永远伴随着解密,所谓的加密或者是解密往往需要一些规则。在JDK1.8开始提供有一个新的加密处理操作,Base64处理类:
- Base64.Encoder:进行加密;
- 加密处理:
public byte[] encode(byte[] src);
- 加密处理:
- Base64.Decoder:进行解密;
- 解密处理:
public byte[] decode(String src);
- 解密处理:
实现加密解密操作
import java.util.Base64;
public class Base64_Study {
public static void main(String[] args) {
String msg = "test!";
String encmsg = new String(Base64.getEncoder().encode(msg.getBytes())); //数据加密
System.out.println(encmsg);
String oldMsg = new String(Base64.getDecoder().decode(encmsg));
System.out.println(oldMsg);
}
}
虽然Base64可以实现加密与解密的处理,但是公版的算法不算安全,是使用盐值操作;
即便现在有盐值但仍旧不是很安全,可通过多次加密实现;
import java.util.Base64;
class StringUtil{
private static final String SALT = "?"; //公共的盐值
private static final int REPEAT = 3; //加密次数
/**
* 加密处理
* @param str 加密字符串与盐值整合
* @return 加密后数据
*/
public static String encode(String str) {
//加密处理
String temp = str + SALT;
byte data [] = temp.getBytes(); //将字符串变为字节数组
for(int x =0; x<REPEAT;x++) {
data = Base64.getEncoder().encode(data); //重复加密
}
return new String(data);
}
/**
* 解密处理
* @param str 要解密的内容
* @return 解密后的内容
*/
public static String decode(String str) {
byte data [] = str.getBytes();
for(int x =0;x<REPEAT;x++) {
data = Base64.getDecoder().decode(data);
}
return new String(data);
}
}
public class Base64_Study {
public static void main(String[] args) {
String str = StringUtil.encode("test");
System.out.println(str);
System.out.println(StringUtil.decode(str));
}
}