极*Java速成教程 - (8)

Java高级特性

注解

注解可以在代码之外添加更多的信息,更加完整地描述程序,帮助编译器进行工作,或者实现某些特定的Java代码之外的功能。
注解可以简化某些重复的流程,自动化那些过程。

注解的使用

注解的使用与其他修饰符的使用没有区别。Java提供了三种标准注解:

  • @Override
    表明该方法将要覆盖父类的方法,当方法签名与被覆盖方法不同时,编译器就会报错。
  • @Deprecated
    如果开发者使用了被注解的元素,那么编译器就会发出警告。
  • @SuppressWarnings
    关闭不当的编译器警告信息。

注解的定义

在使用注解前,需要对注解进行定义。注解不支持继承,注解的定义像一个空的接口,使用@interface的修饰,定义注解时,上方需要一些元注解。
元注解有四种,用于注解其他的注解:

  • @Target 用于定义你的注解应用于什么地方,比如一个方法或者一个域
    • CONSTRUCTOR 构造器的声明
    • FIELD 域声明
    • LOCAL_VARIABLE 局部变量声明
    • METHOD 方法声明
    • PACKAGE 包声明
    • PARAMETER 参数声明
    • TYPE 类、接口(包括注解类型)或enum声明
  • @Retention 用来定义注解在哪一个级别可以用,如源代码中、类文件中或运行时。
    • SOURCE 注解将被编译器丢弃
    • CLASS 注解在class文件中可用,但会被VM丢弃
    • RUNTIME VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
  • @Documented 将此注解包含在Javadoc中
  • @Inherited 允许子类继承父类中的注解

注解中可以包含一些元素以表示某些值,如果没有元素,那么这种注解叫标记注解。注解的元素可以有默认值。

注解的定义和使用如下:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
  public int id();
  public String description() default "no description";
}

import java.util.*;

public class PasswordUtils {
  @UseCase(id = 47, description =
  "Passwords must contain at least one numeric")
  public boolean validatePassword(String password) {
    return (password.matches("\\w*\\d\\w*"));
  }
}

在设置了注解后,还需要创建注解处理器,对注解进行处理。可以使用类的getDeclaredMethods()获取本类除继承以外的所有方法,getAnnotation()方法获取指定类型的方法注解。

注解元素

注解中可以使用注解元素来记录注解信息。
注解中可以使用如下类型:

  • 所有基本类型
  • String
  • Class
  • enum
  • Annotation
  • 以上类型的数组

元素必须有默认值,否则就必须在使用注解时提供值。对于非基本类型元素,不能以null值为其值(但是空字符串""和特定含义的负值是允许的)

Java的apt工具

在Java中,可以使用apt工具调用注解处理器,使其进行针对源代码的注解处理。必须提供一个工厂类或者工厂类的路径。
但在Java7以上,推荐使用javax.annotation.processing工具进行注解处理器的开发。相关内容参考注解处理器详解

并发

并行的方法

使用runnable接口

线程可以驱动任务,任务可以通过实现Runnable接口并编写run()方法来描述。
将Runnable对象提交给Thread构造器,可以创建一个线程来驱动任务。然后使用Thread类的start()方法,就可以启动任务。

通过java.util.concurrent包中的Executor类,可以对Thread对象进行管理。
通过newCachedThreadPool()方法创建线程池,然后对ExecutorService对象调用execute()方法注册任务,即可进行并行处理。调用shutdown()方法即可停止接受新任务。
除了CachedThreadPool,还有FixedThreadPool等线程池可以使用,FixedThreadPool可以一次性预先执行代价高昂的线程分配任务,同时对线程数量也可以进行限制。SingleThreadExecutor同时只会运行一个线程,这个执行器会序列化提交的任务,同时维护一个任务队列,依次执行。
在所有线程池中,在现有线程可能的情况下,都会被自动复用。

使用Callable接口

通过实现Callable接口,类也可以并发执行,通过call()方法可以在任务完成后返回一个返回值。这种方法必须使用ExecutorService对象的submit()方法提交任务。
submit()方法会产生Future对象,该对象可以用isDone()方法查询是否已经完成,当任务完成时,可以使用get()方法获取返回结果。get()方法同时也是一个阻塞方法。

可以在类的内部,通过内部类的方法继承Thread类或者是实现runnable接口,达到多线程的效果。

并行的控制

通过Thread.sleep()方法或者是TimeUnit.MILLISECONDS.sleep()方法,可以使线程休眠。
在run()方法内(在构造器中设置无效)使用线程对象的setPriority()方法可以设置线程优先级,getPriority()方法可以获取线程优先级,JDK的优先级和操作系统优先级并不对应,可移植的方法是使用Thread.MIN_PRIORITY,Thread.MAX_PRIORITY和Thread.NORM_PRIORITY。
使用yield()可以暗示在线程调度中可以做出让步(并不保证实现)。
在线程启动前,使用Thread对象的setDeamon()方法可以设置线程为后台线程。通过实现ThreadFactory接口,可以在接口内的newThread()方法中对创建的Thread进行setDeamon()设置。可以通过isDeamon()查询线程是否为后台线程。
对线程对象调用join()方法,可以将本线程挂起,直到超时或目标线程t结束才恢复。interrupt()方法会中断join,并且设置中断标志。isInterrupted()方法根据中断标志返回值,然而中断时会抛出异常,异常被捕获时会清理这个标志。

并行的异常处理

可以通过在ThreadFactory类中通过setUncaughtExceptionHandler()方法将一个实现了Thread.UncaughtExceptionHandler接口的异常处理器附加到线程上,如果线程抛出异常,那就交由异常处理器进行处理。还可以使用setDefaultUncaughExceptionHandler()方法设置线程的默认异常处理器。

并行的竞争控制

可以通过synchronized关键词对共享资源进行修饰,Java即可自动检查资源是否有锁,是否可用。在使用synchronized关键字时,域应该时private的,否则关键字不能保证其他任务不会访问域造成冲突。
还可以使用java.util.concurrent类库中的locks类显式地加锁。lock类可以通过lock();tryLock()和unlock()方法加锁去锁。ReentrantLock允许尝试获取但是最终没有获取锁,当没有获取到锁时可以离开进行其他处理而不是等待。

猜你喜欢

转载自www.cnblogs.com/CoveredWithDust/p/Fast_JAVA_8.html