Java5 新特性
一、可变参数
为了解决传递参数多个的问题,最初的设计方式便是参数为数组,然后进行各个数据处理。但是,使用数组并不标准,不能每次都需要产生一个数组对象,赋值进数组,再进行方法参数传递。Java1.5 之后提供了可变参数的方式。
[ public | protected | private ] 数据类型 方法名 (数据类型 ... 变量)
在方法体中,仍然把可变参数视为数组,然后对数组遍历,进行数据处理。同时,可变参数仍然支持数组作为参数进行传递。对于不传递任务参数,则方法体会自动将该数组定义为非 null 但数组个数为 0 的数组。
实际开发中,一般参数个数是固定的,因此不会使用到可变参数。但是如果编写诸如框架之类通用性的方法时,则一定用到。
二、foreach
对于类集,也包含数组,进行遍历时,希望能够直接进行内容遍历,不需要通过索引取得。为了实现这一目的,jdk1.5 提供了 foreach 方法实现。
三、泛型
Object 类是所有类的父类,可以使用 Object 类进行数据的统一,避免同一功能因数据类型的不同而编写不同类型的代码,造成冗余代码过多。故采用 Object 类方便设计开发。
虽然实现了数据的统一接收,但是在对象向下转型时,需要进行强制转型,而此时,可能会出现非常多的数据类型,而我们需要一一判断。有可能超出了我们所知的数据类型,那这个时候更加难以判断了。同时,可能会出现数据集合中不同类型的数据,这样进行转型一定出错。这也是为什么少用向下转型的原因。
由上,jdk1.5 之后提供了泛型来解决问题。泛型就是一种表示数据类型的标记,数据类型由用户实际使用时定义,这一标记由任意的大写字母组成。同时,这样也可以在具体调用时固定了代码的数据类型,防止类似 ClassCastException 异常产生。
同时,泛型只能使用引用数据类型,不能使用基本数据类型。
当方法的参数类型以泛型修饰的类为主时,为了避免不确定的数据类型造成的赋值错误和向下转型错误问题,可以使用通配符进行方法的参数类型设置,通配符如下:
?:表示不确定数据类型,不能进行数据修改,只能进行数据取出
? extends 类:确定数据类型的上限,即数据类型不能超过父类
? super 类:确定数据类型的下限,即数据类型不能低于子类。该方式在 java.util.Arrays 类中的 public static void sort(T[] a,Comparator c)方法应用到了。
注意:对于类定义使用了泛型,是对象实例化时,可以不用设置相应的泛型类型,系统默认是 Object 类。
四、枚举
枚举是为了方便开发,同样能够实现多例设计模式而引入 Java 的,使用关键字 enum 定义枚举。严格来说,使用 enum 定义的枚举相当于一个继承了 Enum 这个抽象类。
常用方法:
取得所有枚举:values()
这里需要提醒的是,实际定义枚举,语法要求只能使用 enum,而不能补充使用 extends Enum 定义枚举。
五、Annotation
程序开发在进行配置信息设置时经历了三个阶段:
第一阶段:配置信息直接写在程序之中,不方便修改维护
第二极端:配置信息与程序分离,造成配置过多,不利于查错修改
第三阶段:部分的配置信息对开发者而言是无用的,修改后还会容易出错,因此,将部分配置信息写回到代码中,利用一些标记将配置信息与程序区分开。
故 Java 提供了注解的方式解决这一问题。Java 中提供了三个最为常用的注解基础:
@Override:准确的覆写;
@Deprecated:声明过期操作,@Deprecated 是为了兼顾之前的代码功能,而进行保留的说明,但是之后的代码会建议,使用新的方法,故使用此注解声明过期操作;
@SuppressWarnings:压制警告,@SuppressWarnings,对于程序而言,会出现开发明确知道的警告信息,但是开发者又不希望一直显示警告信息,故使用压制警告注解。
Java8 新特性
一、接口定义增强
对于原有的接口设计,只能定义常量和抽象方法。但是,随着接口的子类不断增多,出现了这样一个问题,接口中需要新定义一个方法,这个方法对于各个子类的功能都相同。那么,从原有对于接口的理解,则应该各个子类都得覆写该方法。实际上,这是不现实的。
因此,JDK1.8 推出了新特性,在接口中可以定义普通方法。但是为了和之前 Java 规则有所区别,在接口中定义普通方法使用 default,定义静态方法使用 static。
代码示例:
package org.fuys.ownutil.instance;
interface Thing {
public void perform();
default void print(){
System.out.println("JDK1.8 New Character By using dafault");
}
static void println(){
System.out.println("JDK1.8 New Character By using static");
}
}
class Cup implements Thing {
public static void drink(){
System.out.println("drink water");
}
@Override
public void perform() {
System.out.println("Interface Define");
}
}
public class NewInterfaceInstance {
public static void main(String[] args) {
Thing thing = new Cup();
thing.perform();
thing.print();
Thing.println();
Cup cup = (Cup)thing;
cup.perform();
Cup.drink();
}
}
复制代码
二、Lamda 表达式
对于接口定义,子类需要覆写所有的抽象方法。那么,对于匿名对象而言,就需要在实际调用的时候,覆写所有的抽象方法。但是,写出匿名对象的真正目的在于某一特定抽象方法的调用,而不是其他的部分。所以,Java1.8 引入了函数式编程。
Lamda 语法:
(参数) -> 单行语句;
(参数) -> {单行语句};
(参数) -> 表达式;
代码示例:
package org.fuys.ownutil.instance;
interface Lamp {
void turnOn();
}
interface Sheep extends Lamp {
void turnOff();
}
public class LamdaInstance {
public static void main(String[] args) {
// original method
lightOn(new Sheep() {
@Override
public void turnOn() {
System.out.println("The sheep light on");
}
@Override
public void turnOff() {
System.out.println("The sheep light off");
}
});
// lamda method
lightOn(() -> System.out.println("The lamp light off"));
}
public static void lightOn(Lamp lamp){
lamp.turnOn();
}
}
复制代码
三、Java8 方法引用
对象引用主要是多个引用操作一个对象。方法引用就是对方法其别名,通过别名仍然可以访问方法。对于方法引用,通过接口里定义一个抽象方法,进行转换。Java8 中定义四种形式如下:
引用静态方法:类名称 :: static 方法名称;
引用某个对象的方法:实例化对象 :: 普通方法;
引用特定类型的方法(对象比较中两个对象作为参数的情况):特定类 :: 普通方法;
引用构造方法:类名称 :: new。
定义接口模型如下:
interface MethodReferenceModel<P,R> {
public R function(P p);
}
复制代码
方法引用所使用的接口只能定义一个抽象方法,故需要对接口进行限制,不能让其定义多个抽象方法。使用注解 @FunctionalInterface 说明接口只能定义一个抽象方法,是函数式接口。
引用特定类型的方法代码示例:
package org.fuys.ownutil.instance;
@FunctionalInterface
interface Shoe <T> {
int takeOn(T t1 ,T t2);
}
public class MethodReferenceInstance {
public static void main(String[] args) {
Shoe<String> shoe = String :: compareTo;
System.out.println(shoe.takeOn("A", "B"));
}
}
复制代码
引用构造方法的代码示例:
package org.fuys.ownutil.instance;
@FunctionalInterface
interface Desk<T> {
T create(String s,double d);
}
class Phone{
private String name;
private double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Phone() {
super();
}
public Phone(String name, double price) {
super();
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Phone [name=" + name + ", price=" + price + "]";
}
}
public class MethodReferenceInstance {
public static void main(String[] args) {
// constructor method reference
Desk<Phone> desk = Phone :: new;
System.out.println(desk.create("MEIZU", 1000.0));
}
}
复制代码
四、内建函数式接口
对于方法引用,需要建立函数式接口。jdk1.8 中 java.util.function 的包下提供了以下四种核心接口。
1、Function,功能型接口,该接口接受参数,返回结果。
定义接口如下
@FunctionalInterface
public interface Function<T,R>{
R apply(T t);
}
复制代码
2、Consumer,消费型接口,负责接收参数,不进行结果返回
定义接口如下:
@FunctionalInterface
public interface Consumer<T>{
void accept(T t);
}
复制代码
3、Supplier,供给型接口,不接收参数,但是返回结果
定义接口如下:
@FunctionalInterface
public interface Supplier<T>{
T get();
}
复制代码
4、Predicate,断言型接口,接受参数,进行判断
定义接口如下:
@FunctionalInterface
public interface Predicate<T>{
boolean test(T t);
}
复制代码
代码示例如下:
// 1,function
Function<String, byte[]> f = String :: getBytes;
System.out.println(Arrays.toString(f.apply("fuyunsong")));
// 3,supplier
Supplier<Date> s = Calendar.getInstance() :: getTime;
System.out.println(s.get());
// 4,predict
Predicate<File> p = File :: exists;
System.out.println(p.test(new File("e:")));
// 2,consumer
Consumer<Integer> c = Runtime.getRuntime() :: exit;
c.accept(1);
复制代码
评论