可变参数
在java程序中调用方法时,必须严格按照方法定义的变量进行参数传递。但是在开发过程中可能会出现一种情况:不确定要传递的参数个数。解决这个问题的思路是将多个参数封装为数组。这是一个打折扣的方法,因为数组并不代表任意多个数据。
在JDK1.5中,引入了可变参数的概念。可变参数的语法形式为:
[public/protected/private] [static/final/abstract] 返回值类型 func(参数类型 ... 变量){
[return [返回值] ;]
}
参数变量传递到方法中,以指定类型的数组进行保存。
public class varargs{
public static void main(String args[]){
System.out.println(add(1,2,3));
System.out.println(add(10,20));
}
public static int add(int ... data){
int sum = 0;
for(int i = 0; i < data.length; i++){
sum += data[i];
}
return sum;
}
}
foreach循环
java中的foreach语句是一种加强型for循环操作。for循环的输出方式需要控制索引,过于麻烦。因此,在JDK1.5中引入foreach形式。
for(数据类型 变量:数组/集合){
//每一次循环,会将数组内容赋值个变量
}
每次循环自动将数组或集合的内容取出,避免了索引问题。
public class foreach{
public static void main(String args[]){
int data[] = new int[]{1,2,3,4,5};
for(int x : data){
System.out.println(x + " ");
}
}
静态导入
如果一个类中的方法全部属于static型方法,其他类在引用此类时,必须先使用import导入所需要的包。然后使用“类名.方法()”进行调用。
如果在调用这些方法时不希望出现类的名称,JDK1.5引入静态导入功能。
import static 包.类.*;
package com.qi.demo;
public class myMath{
public static int div(int x, int y) throws Exception{
System.out.println("===start===");
int result = 0;
try{
result = x / y;
}catch(Exception e){
throw e;
}finally{
System.out.println("===end===");
}
return result;
}
public static int add(int x, int y){
return x + y;
}
}
import static com.qi.demo.myMath.*;
public class static_import{
public static void main(String args[]){
System.out.println("Add operation:" + add(10,20));
try{
System.out.println("divide operation: " + div(10,2));
}catch(Exception e){
e.printStackTrace();
}
}
}
静态导入可以减少代码量,但是过多的静态导入会降低代码的可读性。
泛型
JDk5提供泛型技术。类属性或方法的参数在定义数据类型时,可以直接使用一个标记进行占位,再具体使用时才设置其对应的实际数据类型。这样当设置的数据类型出现错误后,就可以在程序编译时检测出来。使用泛型时,能够采用的类型只能是类,也就是说不能是基本类型,只能是引用类型。例如泛型采用整型,应用Integer,而不是int。
class Point<T>{
private T x;
private T y;
public void setX(T x){
this.x = x;
}
public void setY(T y){
this.y = y;
}
public T getX(){
return x;
}
public T getY(){
return y;
}
}
public class generic{
public static void main(String args[]){
Point<Integer> p = new Point<>();
p.setX(10);
p.setY(20);
Integer x = p.getX();
Integer y = p.getY();
System.out.println("coordinate x: " + x + " y: " +y);
}
}
通配符
对于同一类,由于设置泛型类型不同,其对象表示的含义也不同,因此不能够直接进行引用操作。例如通过泛型定义Message<T>,Message<String>和Message<Integer>虽然都是Message类的对象,但这两个对象不能够直接进行引用传递操作。通过使用通配符“?”解决参数传递问题。通配符可以接受类对象,但是不能修改对象属性。
class Message<T>{
private T msg;
public void setMsg(T msg){
this.msg = msg;
}
public T getMsg(){
return msg;
}
}
public class generic_wildcard{
public static void main(String args[]){
Message<Integer> m1 = new Message<>();
Message<String> m2 = new Message<>();
m1.setMsg(100);
m2.setMsg("hello");
fun(m1);
fun(m2);
}
public static void fun(Message<?> temp){
System.out.println(temp.getMsg());
}
}
在“?”通配符的基础上还有两个子通配符。
? extends 类
设置泛型上限,在声明和方法中使用。表示可以设置该类或其子类。
? super 类
设置泛型下限,在方法中使用。表示只能设置该类或其父类。
泛型接口
泛型可以定义在接口上。使用接口必须定义相应子类。对于使用泛型的接口,有两种实现方式。一是在子类继续设置泛型标记。二是在子类中为父类接口明确定义一个泛型类型。
泛型方法
泛型也可以在方法中定义。在方法中定义泛型时,方法不一定要在泛型类中定义,但要在方法返回值类型前明确定义泛型类型。
Annotation
JDK1.5提出并应用了注解技术。在java SE中,最常见的Annotation是:
@Override
准确覆写操作。保证子类覆写的方法是父类中定义过的方法。当覆写方法出现错误时,可以在编译时检查出来。
@Deprecated
声明过期操作。用于声明过期不建议使用的方法。
@SuppressWarnings
压制警告。开发者明确知道会出现警告信息却执意按照固定方式处理,可以使用@SuppressWarnings压制出现的警告信息。
class Book<T>{
private T title;
public void setTitle(T title){
this.title = title;
}
public T getTitle(){
return title;
}
}
public class annotation_suppresswarnings{
@SuppressWarnings({"rawtypes", "unchecked"})
public static void main(String args[]){
Book book = new Book();
book.setTitle("hello");
System.out.println(book.getTitle());
}
}
接口定义加强
JDK1.8开始,接口中可以定义普通方法与静态方法。java增加这个特性原因如下。随着接口的子类越来越多,如果这个接口功能不足,需要增加新的方法,则需要对所有接口子类覆写新增加的方法。这个设计的工作量是重复的且是巨大的,因此通过放宽接口定义,接口可以定义普通方法和静态方法,接口的方法扩充问题就能得到很好的解决。
在接口中定义普通方法,该方法必须使用default来进行定义。使用default定义的普通方法,需要利用实例化对象明确调用。在接口中定义静态方法,该方法可以由接口名称直接调用。
lambda表达式
JDK1.8中引入lambda表达式。lambda表达式是应用在单一抽象方法接口环境下的一种简化定义形式,解决匿名内部类定义复杂问题。单一抽象方法接口使用@FunctionalInterface注解,表示此为函数式接口,里面只允许定义一个抽象方法。lambda表达式有三种形式。
(params) -> expression
(params) -> statement
(params) -> {statements}
@FunctionalInterface
interface IMessage{
public int add(int ... args);
static int sum(int ... args){
int sum = 0;
for(int temp:args){
sum += temp;
}
return sum;
}
}
public class lambda{
public static void main(String args[]){
//()内是参数,->后是子类覆写抽象方法的方法体
fun((int ... param) -> IMessage.sum(param));
}
public static void fun(IMessage msg){
System.out.println(msg.add(10,20,30));
}
}
方法引用
JDK1.8支持方法的引用操作,相当于为方法定义别名。java8定义了四种方法引用操作形式。
- 引用静态方法
类名称::static方法名称
interface Imessage<P,R>{
public R change(P p);
}
public class method_reference_static{
public static void main(String args[]){
//将String.valueOf()方法变为IMessage接口的change()方法
//valueOf()方法接收int型数据,返回String型数据
Imessage<Integer, String> msg = String::valueOf;
String str = msg.change(1000);
System.out.println(str.replaceAll("0","9"));
}
}
- 引用某个对象的方法
实例化对象::普通方法
@FunctionalInterface
interface IMessage<R>{
public R upper();
}
public class method_reference_common{
public static void main(String args[]){
//String类的toUpperCase()定义:public String toUpperCase()。
//该方法没有参数,有返回值。
IMessage<String> msg = "hello"::toUpperCase;
String str = msg.upper();
System.out.println(str);
}
}
- 引用特定类型的方法
特定类::普通方法
@FunctionalInterface
interface IMessage<P>{
public int compare(P p1, P p2);
}
public class method_reference_special{
public static void main(String args[]){
IMessage<String> msg = String::compareTo;
System.out.println(msg.compare("A","B"));
}
}
- 引用构造方法
类名称::new
@FunctionalInterface
interface IMessage<C>{
public C create(String t, double p);
}
class Book{
private String title;
private double price;
public Book(String title, double price){
this.title = title;
this.price = price;
}
@Override
public String toString(){
return "book: " + this.title + ", price: " + this.price;
}
}
public class metheod_reference_constructor{
public static void main(String args[]){
IMessage<Book> msg = Book::new; //引用构造方法
Book book = msg.create("JAVA", 100);
System.out.println(book);
}
}
内建函数式接口
方法引用操作可能出现的函数式接口有四类:有参数有返回值、有参数无返回值、无参数有返回值、判断真假。JDK1.8提供了一个新的开发包:
java.util.function
该开发包提供四个核心函数式接口,简化开发者的定义,实现操作的统一。
1、功能型接口
@FunctionalInterface
public interface Function<T,R>{
public R apply(T t); //接收**一个**参数,并返回一个处理结果
}
import java.util.function.Function;
public class funcifc_function{
public static void main(String args[]){
Function<String, Boolean> fun = "##hello"::startsWith; //利用对象调用startsWith()
System.out.println(fun.apply("##"));
}
}
注意引用的方法只能有一个输入和一个返回结果。否则,引用方法不能与apply()匹配。
2、消费型接口
@FunctionalInterface
public interface Comsumer<T>{
public void accept(T t); //只接收数据,不返回结果
}
import java.util.function.Consumer;
public class funcifc_consumer{
public static void main(String[] args){
Consumer<String> cons = System.out::print;
cons.accept("hello world");
}
}
3、供给型接口
@FunctionalInterface
public interface Supplier<T>{
public T get(); //不接收数据,只返回结果
}
import java.util.function.Supplier;
public class funcifc_supplier{
public static void main(String args[]){
Supplier<String> sup = "hello"::toUpperCase;
System.out.println(sup.get());
}
}
4、断言型接口
@FunctionalInterface
public intereface Predicate<T>{
public boolean test(T t); //判断
}
import java.util.function.Predicate;
public class funcifc_predicate{
public static void main(String args[]){
Predicate<String> pre = "hello"::equalsIgnoreCase;
System.out.println(pre.test("HELLO"));
}
}