jdk8新特性 forEach方法和方法引用
先說明,jdk8增加了一個包java.util.function,裡面存放的都是新增的函式式介面,方便用lambda表示式重寫其抽象方法
下面列舉三個常見的函式式介面,下行是其抽象方法
Consumer<T>代表了接受一個輸入引數並且無返回的操作
void accep(T t)接收一個引數,使用它
IntConsumer接受一個int型別的輸入引數,無返回值 。
void accept(int value)接收一個int型別引數,使用它
Supplier<T>無引數,返回一個結果。
T get()返回一個T型別的物件
forEach
jdk8在Iterable介面中增加了defalut修飾的forEach()方法,用來遍歷
先看下Iterable介面的原始碼
public interface Iterable<T> { Iterator<T> iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
forEach方法,接收一個Consumer型別的引數action,然後呼叫增強for迴圈對容器物件使用action.accept方法
咱們再來看Consumer介面的原始碼
@FunctionalInterface public interface Consumer<T> { void accept(T t);//抽象方法 default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
accept為抽象方法,需要重寫
到此我們知道怎麼使用forEach來遍歷集合了
要先呼叫容器的forEach方法,重寫Consumer介面的accept方法
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ForEachTest03 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(-1);
// 使用forEach方法遍歷,實驗匿名內部類的方式重寫Consumer介面的accept方法
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.print(t + " ");
}
});
System.out.println();
// 使用lambda方式重寫函式式介面的抽象方法更簡潔
list.forEach((i) -> {
System.out.print(i + " ");
});
}
}
out:
3 5 -1
3 5 -1
方法引用
方法引用指 通過方法的名字來指向一個方法。
方法引用的作用主要是簡化lambda表示式,當lambda表示式只執行一個方法時,可使用方法引用簡寫lambda表示式
語法: 使用兩個冒號 ::
有四種情況:
靜態方法引用
類名::方法名
某個物件的引用,
物件例項::方法名
構造方法引用
構造方法,類名::new
特定類的任意物件的方法引用, 這個方法引用的使用需要注意,自定義類中無引數的方法可以使用,比如toString,hashCode等,或者compareTo等特定方法也可以使用,還沒搞清楚什麼原理呢,建議慎用,正常寫就好了
類名::方法名
下面來示例:任意物件的方法引用
list.forEach((i)->System.out.println(i));
list.forEach(System.out::println);//System.out
示例:靜態方法的方法引用
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class Test05 {
public static void main(String[] args) {
Set<Integer> set1 = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
});
Set<Integer> set = new TreeSet<>(Integer::compareTo);
set.add(3);
set.add(6);
set.add(0);
for (Integer i : set) {
System.out.println(i);
}
}
}
out:
0
3
6
示例構造方法的引用,以下示例四種引用方式
import java.util.function.Supplier;
public class Student {
public String name;
public static Student creatStudent(Supplier<Student> s) {
System.out.println("通過方法引用建立物件");
return s.get();
}
public static void eat(Student student) {
System.out.println("Student " + student.getName() + "is eating");
}
public void drink(Student s) {
System.out.println("student" + s.getName() + "drink something");
}
public void study() {
System.out.println("the student" + this.getName() + " has studyed 5 hours");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("this student's name is " + name);
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
@Override
public String toString() {
System.out.println("Student [name=" + name + "]");
return "Student [name=" + name + "]";
}
}
//測試類
import java.util.Arrays;
import java.util.List;
public class Test06 {
public static void main(String[] args) {
// 構造方法引用
Student s1 = Student.creatStudent(Student::new);
Student s2 = Student.creatStudent(Student::new);
s1.setName("張三");
s2.setName("李四");
Student[] ss = { s1, s2 };
// 靜態方法引用
List<Student> listStu = Arrays.asList(ss);
listStu.forEach(Student::eat);
// 特定物件的方法引用
listStu.forEach(s1::drink);
// 特定類任意物件的特定方法
listStu.forEach(Student::toString);
listStu.forEach(Student::study);
}
}
out:
通過方法引用建立物件
通過方法引用建立物件
this student's name is 張三
this student's name is 李四
Student 張三is eating
Student 李四is eating
student張三drink something
student李四drink something
Student [name=張三]
Student [name=李四]
the student張三 has studyed 5 hours
the student李四 has studyed 5 hours