Java Lambda概要
- Java Lambda表達(dá)式是一種匿名函數(shù)屎篱;它沒(méi)有聲明的方法迅矛,即沒(méi)有訪問(wèn)修飾符简珠、返回值聲明和名字外盯。
Java Lambda表達(dá)式基本語(yǔ)法
- Java中的Lambda表達(dá)式基本語(yǔ)法:
- (argument) -> {body}
- 比如說(shuō):
- (arg1,arg2) -> {body}
- (type1 arg1,type2 arg2) -> {body}
- arg1 -> {body}
- s -> System.out.println(s)
Java Lambda表達(dá)式結(jié)構(gòu)
- 一個(gè)Lambda表達(dá)式可以有0個(gè)或多個(gè)參數(shù)。
- 參數(shù)的類型既可以明確聲明挺尿,也可以根據(jù)上下文來(lái)推斷奏黑。例如,(int a)和(a)效果相同
- 所有參數(shù)需包含在圓括號(hào)內(nèi)编矾,參數(shù)之間用逗號(hào)相隔熟史。例如:(a,b)或(int a,int b)或(String a,String b,float c)
- 空?qǐng)A括號(hào)代表參數(shù)集為空。例如:() -> 42
- 當(dāng)只有一個(gè)參數(shù)窄俏,且其類型可以推導(dǎo)時(shí)蹂匹,圓括號(hào)()可省略。例如:a -> return a * a
- Lambda表達(dá)式的主題可以包含0條或多條語(yǔ)句
- 如果Lambda表達(dá)式的主題只有一條語(yǔ)句凹蜈,花括號(hào){}可以省略限寞。匿名函數(shù)的返回類型與該主體表達(dá)式一致
- 如果Lambda表達(dá)式的主體包含一條以上語(yǔ)句,則表達(dá)式主體必須包含在花括號(hào){}中(形成代碼塊)仰坦,匿名函數(shù)的返回類型與代碼塊的返回類型一致履植,若沒(méi)有返回則為空
Java Lambda示例
- Lambda示例說(shuō)明
- (int a,int b) -> {return a + b;}
- () -> System.out.println("hello world");
- (String s) -> {System.out.println(s);}
- () -> 42
- () -> {return 3.1415};
Lambda表達(dá)式作用
- 傳遞行為,而不僅僅是值
- 提升抽象層次
- API重用性更好
- 更加靈活
方法引用
其實(shí)是lambda表達(dá)式的一種簡(jiǎn)化寫法悄晃。所引用的方法其實(shí)是lambda表達(dá)式的方法體實(shí)現(xiàn)玫霎,語(yǔ)法也很簡(jiǎn)單,左邊是容器(可以是類名妈橄,實(shí)例名)鼠渺,中間是"::",右邊是相應(yīng)的方法名眷细。
本質(zhì)上可以將方法引用看作是一個(gè)“函數(shù)指針” ——function pointer。
如下所示:
ObjectReference::methodName
一般方法的引用格式:
- 1鹃祖、如果是靜態(tài)方法溪椎,則是ClassName::staticmethodName。如 Object ::equals
- 2、如果是實(shí)例方法校读,則是Instance::methodName沼侣。如Object obj=new Object();obj::equals;
- 3、如果是實(shí)例方法歉秫,則可以ClassName::methodName蛾洛。如Object ::equals;
- 4、構(gòu)造函數(shù).則是ClassName::new
方法引用使用場(chǎng)景:lambda表達(dá)式只有一行代碼雁芙,且這行代碼調(diào)用的這個(gè)方法是已經(jīng)存在的轧膘,那么就可以用方法引用去替換掉lambda表達(dá)式。
此為方法引用最簡(jiǎn)單例子:
public class MethodReferenceTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello","world","helloworld");
list.forEach(item -> System.out.println());
list.forEach(System.out::println);
}
}
接下來(lái)看一下稍微復(fù)雜的例子:
1兔甘、如果是靜態(tài)方法谎碍,則是ClassName::staticmethodName。如 Object ::equals
public class Student {
private String name;
private int score;
public Student() {
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public static int compareStudentBySocre(Student student1,Student student2){
return student1.getScore() - student2.getScore();
}
public static int compareStudentByName(Student student1,Student student2){
return student1.getName().compareTo(student2.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
list.sort((studentParam1,studentParam2) -> Student.compareStudentBySocre(studentParam1,studentParam2));
list.sort((studentParam1,studentParam2) -> Student.compareStudentByName(studentParam1,studentParam2));
System.out.println(list);
list.sort(Student::compareStudentBySocre);
list.sort(Student::compareStudentByName);
System.out.println(list);
}
}
2洞焙、如果是實(shí)例方法蟆淀,則是Instance::methodName。如Object obj=new Object();obj::equals;
public class StudentComparator {
public int compareStudentBySocre(Student student1,Student student2){
return student1.getScore() - student2.getScore();
}
public int compareStudentByName(Student student1,Student student2){
return student1.getName().compareTo(student2.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
StudentComparator studentComparator = new StudentComparator();
list.sort((studentParam1,studentParam2) -> studentComparator.compareStudentBySocre(studentParam1,studentParam2));
list.sort((studentParam1,studentParam2) -> studentComparator.compareStudentByName(studentParam1,studentParam2));
list.sort(studentComparator::compareStudentBySocre);
list.sort(studentComparator::compareStudentByName);
}
}
3澡匪、如果是實(shí)例方法熔任,則可以ClassName::methodName。如Object ::equals;
public class Student {
......字段唁情、setter和getter方法省略......
public int compareBySocre(Student student){
return this.getScore() - student.getScore();
}
public int compareByName(Student student){
return this.getName().compareTo(student.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
list.sort(Student::compareBySocre);
list.sort(Student::compareByName);
}
}
4疑苔、構(gòu)造函數(shù).則是ClassName::new
public class MethodReferenceTest2 {
public static void main(String[] args) {
List<String> citys = Arrays.asList("shenzhen","shanghai","beijing","chongqing");
Collections.sort(citys,String::compareTo);
MethodReferenceTest2 methodReferenceTest2 = new MethodReferenceTest2();
String test2String = methodReferenceTest2.getString(Student::new);
String string2 = methodReferenceTest2.getString2(" hello ", String::new);
}
public <T> String getString(Supplier<T> supplier){
return supplier.get() + "test";
}
public <T> T getString2(T str, Function<T,T> function){
return function.apply(str);
}
}
可以看出,doSomething方法就是lambda表達(dá)式的實(shí)現(xiàn)荠瘪,這樣的好處就是夯巷,如果你覺(jué)得lambda的方法體會(huì)很長(zhǎng),影響代碼可讀性哀墓,方法引用就是個(gè)解決辦法趁餐。
函數(shù)式接口
函數(shù)式接口(functional interface 也叫功能性接口,其實(shí)是同一個(gè)東西)篮绰。簡(jiǎn)單來(lái)說(shuō)后雷,函數(shù)式接口是只包含一個(gè)方法的接口。比如Java標(biāo)準(zhǔn)庫(kù)中的java.lang.Runnable和 java.util.Comparator都是典型的函數(shù)式接口吠各。
java 8提供 @FunctionalInterface作為注解,這個(gè)注解是非必須的臀突,只要接口符合函數(shù)式接口的標(biāo)準(zhǔn)(即只包含一個(gè)方法的接口),虛擬機(jī)會(huì)自動(dòng)判斷贾漏, 但 最好在接口上使用注解@FunctionalInterface進(jìn)行聲明候学,以免團(tuán)隊(duì)的其他人員錯(cuò)誤地往接口中添加新的方法。
Java中的lambda無(wú)法單獨(dú)出現(xiàn)纵散,它需要一個(gè)函數(shù)式接口來(lái)盛放梳码,lambda表達(dá)式方法體其實(shí)就是函數(shù)接口的實(shí)現(xiàn)隐圾;每個(gè)lambda表達(dá)式都能隱式的賦值給函數(shù)式接口。
關(guān)于函數(shù)式接口:
- 1掰茶、如果一個(gè)接口只有一個(gè)抽象方法暇藏,那么該接口就是一個(gè)函數(shù)式接口。
- 2濒蒋、如果我們?cè)谀硞€(gè)接口上聲明了@FunctionalInterface注解盐碱,那么編譯器就會(huì)按照函數(shù)式接口的定義來(lái)要求該接口。
- 3沪伙、如果某個(gè)接口只有一個(gè)抽象方法瓮顽,但我們并沒(méi)有給該接口聲明@FunctionalInterface注解,那么編譯器依舊會(huì)將該接口看做是函數(shù)式接口焰坪。
高階函數(shù)
如果一個(gè)函數(shù)接收另一個(gè)函數(shù)作為參數(shù)趣倾,或者返回一個(gè)函數(shù)作為返回值,那么該函數(shù)就叫做高階函數(shù)某饰。
自定義函數(shù)式接口
public class Test3 {
public static void main(String[] args) {
TheInterface i1 = () -> {};
System.out.println(i1.getClass().getInterfaces()[0]);
TheInterface2 i2 = () -> {};
System.out.println(i2.getClass().getInterfaces()[0]);
}
}
@FunctionalInterface
interface TheInterface{
void myMethod();
}
@FunctionalInterface
interface TheInterface2{
void myMethod2();
}
我們知道使用Lambda表達(dá)式是需要使用函數(shù)式接口的儒恋,那么,豈不是在我們開發(fā)過(guò)程中需要定義許多函數(shù)式接口黔漂,其實(shí)不然诫尽,java8其實(shí)已經(jīng)為我們定義好了4類內(nèi)置函數(shù)式接口,這4類接口其實(shí)已經(jīng)可以解決我們開發(fā)過(guò)程中絕大部分的問(wèn)題炬守,只有一小部分比較特殊得情況需要我們自己去定義函數(shù)式接口牧嫉,下面就簡(jiǎn)單來(lái)學(xué)習(xí)一下java8內(nèi)置得4大核心函數(shù)式接口。
一减途、Consumer<T>:消費(fèi)型接口(void accept(T t))
Consumer接口:該接口定義了一個(gè)void accept(T)的抽象方法酣藻,其函數(shù)描述符為 (T) -> void,如果你需要一個(gè)操作某一對(duì)象鳍置,但無(wú)需返回的的函數(shù)式接口辽剧,那么就可以使用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); };
}
}
來(lái)看一個(gè)簡(jiǎn)單得例子:
public class Test3 {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello","world","helloworld");
list.forEach(item -> System.out.println(item.toUpperCase()));
List<String> list2 = new ArrayList<>();
list.forEach(item -> list2.add(item.toUpperCase()));
list2.forEach(item -> System.out.println(item));
list.stream().map(item -> item.toUpperCase()).forEach(item -> System.out.println(item));
list.stream().map(String::toUpperCase).forEach(System.out::println);
}
}
以上為消費(fèi)型接口税产,有參數(shù)怕轿,無(wú)返回值類型的接口。
二辟拷、Supplier<T>:供給型接口(T get())
Supplier接口:既然有消費(fèi)者接口(Consumer)撞羽,那就要有生產(chǎn)者接口(Supplier),該接口定義了一個(gè) T get() 的抽象方法衫冻,其函數(shù)描述符為 () -> T诀紊,如果你需要一個(gè)從某一對(duì)象獲取到某值的接口,那么就可以用Supplier隅俘。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
來(lái)看一個(gè)簡(jiǎn)單得例子:
public class SupplierTest {
public static void main(String[] args) {
Supplier<String> supplier = () -> "hello world";
System.out.println(supplier.get());
Supplier<Student> supplier1 = () -> new Student("張三",20);
System.out.println(supplier1.get().getName());
Supplier<Student> supplier2 = Student::new;
System.out.println(supplier2.get().getName());
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
上面就是一個(gè)供給類型得接口邻奠,只有產(chǎn)出到推,沒(méi)人輸入,就是只有返回值惕澎,沒(méi)有入?yún)?/p>
三、Function<T, R>:函數(shù)型接口(R apply(T t))
Function接口:該接口定義了一個(gè) R applay(T)類型的抽象函數(shù)颜骤,它接受一個(gè)泛型變量T唧喉,并返回一個(gè)泛型變量R,如果你需要將一個(gè)對(duì)象T映射成R忍抽,那么就可以使用Function接口八孝。例如我們需要打印一個(gè)花名冊(cè),但是具體打印的格式需要可靈活配置鸠项,那就將花名冊(cè)打印格式參數(shù)化干跛,需要使用 (Student) -> String 類型的函數(shù)描述符,與Function接口吻合祟绊。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
下面看一個(gè)簡(jiǎn)單的例子:
public class FunctionTest {
public static void main(String[] args) {
FunctionTest test = new FunctionTest();
int compute1 = test.compute(1, value -> {return 2 * value;});
System.out.println(compute1);
int compute2 = test.compute(2, value -> 5 + value);
System.out.println(compute2);
int compute3 = test.compute(3, value -> value * value);
System.out.println(compute3);
String compute4 = test.convert(5,value -> String.valueOf(value + "helloworld"));
System.out.println(compute4);
Function<Integer,Integer> function = value -> value * 2;
int compute5 = test.compute(4, function);
System.out.println(compute5);
}
public <T> T compute(T a, Function<T,T> function){
T result = function.apply(a);
return result;
}
public String convert(int a,Function<Integer,String> function){
String result = function.apply(a);
return result;
}
}
下面看一個(gè)稍微復(fù)雜的例子:
public class FunctionTest2 {
public static void main(String[] args) {
FunctionTest2 test = new FunctionTest2();
int compute = test.compute(2, value -> value * 3, value -> value * value);
int compute2 = test.compute2(2, value -> value * 3, value -> value * value);
System.out.println(compute);
System.out.println(compute2);
}
public <T> T compute(T a, Function<T,T> function1,Function<T,T> function2){
return function1.compose(function2).apply(a);
}
public <T> T compute2(T a,Function<T,T> function1,Function<T,T> function2){
return function1.andThen(function2).apply(a);
}
}
上面就是一個(gè)函數(shù)型接口楼入,輸入一個(gè)類型得參數(shù),輸出一個(gè)類型得參數(shù)牧抽,當(dāng)然兩種類型可以一致嘉熊。
四、Predicate<T>:斷言型接口(boolean test(T t))
Predicate接口:該接口定義了一個(gè)支持泛型的boolean test( T)的抽象方法扬舒,其函數(shù)描述符為 (T)-> boolean阐肤,現(xiàn)在我們就可以直接使用Predicate接口來(lái)替代OToBoolean接口了。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
下面看一個(gè)簡(jiǎn)單得例子:
public class PredicateTest {
public static void main(String[] args) {
Predicate<String> predicate = p -> p.length() > 5;
boolean test = predicate.test("hello");
System.out.println(test);
}
}
下面看一個(gè)稍微復(fù)雜的例子:
public class PredicateTest2 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
conditionFilter(list,item -> item % 2 == 0);
conditionFilter(list,item -> item > 5);
conditionFilter(list,item -> true);
//找出集合中所有大于5且為偶數(shù)的元素
conditionFilter2(list,item -> item > 5,item -> item % 2 == 0);
//找出集合中大于5或?yàn)榕紨?shù)的元素
conditionFilter3(list,item -> item > 5,item -> item % 2 == 0);
//找出集合中所有大于5且為偶數(shù)的元素基礎(chǔ)上取反
conditionFilter4(list,item -> item > 5,item -> item % 2 == 0);
boolean test1 = isEqual("hello").test("hello");
System.out.println(test1);
boolean test2 = isEqual(new Date()).test(new Date());
System.out.println(test2);
}
public static <T> void conditionFilter(List<T> list, Predicate<T> predicate){
list.forEach(t -> {
if(predicate.test(t)){
System.out.println(t);
}
});
}
public static <T> void conditionFilter2(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.and(predicate2).test(item)){
System.out.println(item);
}
});
}
public static <T> void conditionFilter3(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.or(predicate2).test(item)){
System.out.println(item);
}
});
}
public static <T> void conditionFilter4(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.and(predicate2).negate().test(item)){
System.out.println(item);
}
});
}
public static <T> Predicate<T> isEqual(T t){
return Predicate.isEqual(t);
}
}
上面就是一個(gè)斷言型接口讲坎,輸入一個(gè)參數(shù)孕惜,輸出一個(gè)boolean類型得返回值。
五晨炕、其他的一些重要函數(shù)式接口
**BiFunction<T, U, R> **
參數(shù)類型有2個(gè)衫画,為T,U,返回值為R,其中方法為R apply(T t, U u)
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
下面看一個(gè)簡(jiǎn)單得例子:
public class FunctionTest2 {
public static void main(String[] args) {
FunctionTest2 test = new FunctionTest2();
int compute3 = test.compute3(2, 3, (value1, value2) -> value1 + value2);
System.out.println(compute3);
int compute4 = test.compute4(3, 4, (value1, value2) -> value1 + value2, value -> value * value);
System.out.println(compute4);
}
public <T> T compute3(T a, T b, BiFunction<T,T,T> function){
return function.apply(a,b);
}
public <T> T compute4(T a,T b,BiFunction<T,T,T> biFunction,
Function<T,T> function){
return biFunction.andThen(function).apply(a,b);
}
}
public class PersonTest {
public static void main(String[] args) {
Person person1 = new Person("zhangsan",20);
Person person2 = new Person("lisi",38);
Person person3 = new Person("wangwu",40);
List<Person> list = Arrays.asList(person1,person2,person3);
List<Person> resultList = getPersonByUsername("zhangsan", list);
resultList.forEach(person -> System.out.println(person));
List<Person> personByAge = getPersonByAge(20, list);
personByAge.forEach(person -> System.out.println(person));
List<Person> personByAge2 = getPersonByAge2(20, list, (age, personList) ->
personList.stream().filter(person -> person.getAge() > age).collect(Collectors.toList())
);
personByAge2.forEach(person -> System.out.println(person));
}
public static List<Person> getPersonByUsername(String username,List<Person> list){
return list.stream().filter(person -> person.getName().equals(username)).collect(Collectors.toList());
}
public static List<Person> getPersonByAge(int age,List<Person> list){
/*BiFunction<Integer,List<Person>,List<Person>> biFunction = (ageOfPerson,personList) -> {
return personList.stream().filter(person -> person.getAge() > ageOfPerson).collect(Collectors.toList());
};*/
//這里下面一行代碼和上面注釋掉的代碼一個(gè)意思疹味,只是寫法更簡(jiǎn)潔
BiFunction<Integer,List<Person>,List<Person>> biFunction = (ageOfPerson,personList) ->
personList.stream().filter(person -> person.getAge() > ageOfPerson).collect(Collectors.toList());
return biFunction.apply(age,list);
}
public static <T> List<T> getPersonByAge2(int age,List<T> list,BiFunction<Integer,List<T>,List<T>> biFunction){
return biFunction.apply(age,list);
}
}
BinaryOperator<T>(BiFunction子接口)
參數(shù)為T邦邦,對(duì)參數(shù)為T得對(duì)象進(jìn)行二元操作,并返回T類型得結(jié)果榨汤,其中方法為T apply(T t1, T t2)
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
下面看一個(gè)簡(jiǎn)單得例子:
public class BinaryOperatorTest {
public static void main(String[] args) {
Integer compute = compute(3, 5, (value1, value2) -> value1 + value2);
System.out.println(compute);
String min1 = getShortMin("hello", "world", (value1, value2) -> value1.compareTo(value2));
System.out.println(min1);
String min2 = getShortMin("hello", "world", (value1, value2) -> value1.charAt(0) - value2.charAt(0));
System.out.println(min2);
String max = getShortMax("hello", "world", (value1, value2) -> value1.charAt(0) - value2.charAt(0));
System.out.println(max);
}
public static <T> T compute(T a, T b, BinaryOperator<T> binaryOperator){
return binaryOperator.apply(a,b);
}
/**
* 返回兩個(gè)數(shù)的較小值
* @param a
* @param b
* @param comparator
* @param <T>
* @return
*/
public static <T> T getShortMin(T a, T b, Comparator<T> comparator){
return BinaryOperator.minBy(comparator).apply(a,b);
}
/**
* 返回兩個(gè)數(shù)的較大值
* @param a
* @param b
* @param comparator
* @param <T>
* @return
*/
public static <T> T getShortMax(T a, T b, Comparator<T> comparator){
return BinaryOperator.maxBy(comparator).apply(a,b);
}
}
Comparator<T>接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
下面看一個(gè)簡(jiǎn)單得例子:
public class StringComparator {
public static void main(String[] args) {
List<String> list = Arrays.asList("zhangsan","wangwu","lisi","zhaoliu");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println(list);
Collections.sort(list,(o1,o2) -> {
return o2.compareTo(o1);
});
System.out.println(list);
//expression o2.compareTo(o1)
//statement {return o2.compareTo(o1);}
Collections.sort(list,(o1,o2) -> o2.compareTo(o1));
System.out.println(list);
Collections.sort(list,Comparator.reverseOrder());
System.out.println(list);
}
}
Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
下面看一個(gè)簡(jiǎn)單得例子:
new Thread(() -> System.out.println("hello world")).start();
除了上述得類型得接口外還有其他的一些接口供我們使用:
1).BiFunction<T, U, R>
參數(shù)類型有2個(gè),為T秆撮,U,返回值為R换况,其中方法為R apply(T t, U u)
2).UnaryOperator<T>(Function子接口)
參數(shù)為T职辨,對(duì)參數(shù)為T的對(duì)象進(jìn)行一元操作盗蟆,并返回T類型結(jié)果,其中方法為T apply(T t)
3).BinaryOperator<T>(BiFunction子接口)
參數(shù)為T舒裤,對(duì)參數(shù)為T得對(duì)象進(jìn)行二元操作喳资,并返回T類型得結(jié)果,其中方法為T apply(T t1腾供, T t2)
4).BiConsumcr(T, U)
參數(shù)為T仆邓,U無(wú)返回值,其中方法為 void accept(T t, U u)
5).ToIntFunction<T>伴鳖、ToLongFunction<T>节值、ToDoubleFunction<T>
參數(shù)類型為T,返回值分別為int榜聂,long搞疗,double,分別計(jì)算int须肆,long匿乃,double得函數(shù)。
6).IntFunction<R>休吠、LongFunction<R>扳埂、DoubleFunction<R>
參數(shù)分別為int,long瘤礁,double阳懂,返回值為R。
以上就是java8內(nèi)置得核心函數(shù)式接口柜思,其中包括了大部分得方法類型岩调,所以可以在使用得時(shí)候根據(jù)不同得使用場(chǎng)景去選擇不同得接口使用。
這里的函數(shù)式接口可以理解成赡盘,定義了很多不同的參數(shù)個(gè)數(shù)待實(shí)現(xiàn)接口号枕。
Java8內(nèi)置了很多函數(shù)式接口(在java.util.function包下的接口),下面表格有列出:
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
Function | R apply(T t) | 一個(gè)參數(shù) | R |
DoubleFunction | R apply(double value) | 一個(gè)參數(shù) | R |
IntFunction | R apply(int value) | 一個(gè)參數(shù) | R |
UnaryOperator extends Function | T apply(T t) | 一個(gè)參數(shù) | T |
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
BiFunction | R apply(T t, U u) | 兩個(gè)參數(shù) | R |
BinaryOperator extends BiFunction | T apply(T t, T u) | 兩個(gè)參數(shù) | T |
DoubleBinaryOperator | double applyAsDouble(double l, double r) | 兩個(gè)參數(shù) | double |
DoubleBinaryOperator | double applyAsDouble(double l, double r) | 兩個(gè)參數(shù) | |
double | |||
DoubleUnaryOperator | double applyAsDouble(double operand) | 一個(gè)參數(shù) | double |
IntBinaryOperator | int applyAsInt(int left, int right) | 兩個(gè)參數(shù) | int |
LongBinaryOperator | long applyAsLong(long left, long right) | 兩個(gè)參數(shù) | long |
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
DoubleToIntFunction | int applyAsInt(double value) | 一個(gè)參數(shù) | int |
IntToLongFunction | long applyAsLong(int value) | 一個(gè)參數(shù) | long |
DoubleToLongFunction | long applyAsLong(double value) | 一個(gè)參數(shù) | long |
IntToDoubleFunction | double applyAsDouble(int value) | 一個(gè)參數(shù) | double |
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
Predicate | boolean test(T t) | 一個(gè)參數(shù) | boolean |
BiPredicate | boolean test(T t, U u) | 兩個(gè)參數(shù) | boolean |
DoublePredicate | boolean test(double value) | 一個(gè)參數(shù) | boolean |
IntPredicate | boolean test(int value) | 一個(gè)參數(shù) | boolean |
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
Supplier | T get() | 無(wú) | T |
BooleanSupplier | boolean getAsBoolean() | 無(wú) | boolean |
DoubleSupplier | double getAsDouble() | 無(wú) | boolean |
IntSupplier | int getAsInt() | 無(wú) | boolean |
接口 | 方法 | 參數(shù) | 返回值 |
---|---|---|---|
Consumer | void accept(T t) | 一個(gè)參數(shù) | void |
BiConsumer | void accept(T t, U u) | 兩個(gè)參數(shù) | void |
DoubleConsumer | void accept(double value) | 一個(gè)參數(shù) | void |
IntConsumer | void accept(int value) | 一個(gè)參數(shù) | void |
ObjDoubleConsumer | void accept(T t, double value) | 兩參數(shù) | void |
上面為Java 8 中函數(shù)式接口列表
這里給出一份較為全的函數(shù)式接口與描述符對(duì)應(yīng)的接口聲明列表:
函數(shù)式接口 | 函數(shù)描述符 |
---|---|
Predicate | (T) -> boolean |
Consumer | (T) -> void |
Function< T, R > | (T) -> R |
Supplier | () -> T |
UnaryOperator | (T) -> T |
BinaryOperator | (T, T) -> T |
BiPredicate | (L, R) -> boolean |
BiConsumer | (T, U) -> void |
BiFunction | (T, U) -> R |
如果同學(xué)們需要的函數(shù)式接口沒(méi)有被覆蓋陨享,可以根據(jù)JDK中的聲明來(lái)編寫適合自己使用的函數(shù)式接口聲明葱淳。
Optional
用于簡(jiǎn)化Java中對(duì)空值的判斷處理,以防止出現(xiàn)各種空指針異常抛姑。
Optional實(shí)際上是對(duì)一個(gè)變量進(jìn)行封裝赞厕,它包含有一個(gè)屬性value,實(shí)際上就是這個(gè)變量的值定硝。
Optional對(duì)象創(chuàng)建
它的構(gòu)造函數(shù)都是private類型的皿桑,因此要初始化一個(gè)Optional的對(duì)象無(wú)法通過(guò)其構(gòu)造函數(shù)進(jìn)行創(chuàng)建。它提供了一系列的靜態(tài)方法用于構(gòu)建Optional對(duì)象:
empty
用于創(chuàng)建一個(gè)空的Optional對(duì)象;其value屬性為Null诲侮。
如:
Optional o = Optional.empty();
of
根據(jù)傳入的值構(gòu)建一個(gè)Optional對(duì)象;
傳入的值必須是非空值镀虐,否則如果傳入的值為空值,則會(huì)拋出空指針異常沟绪。
使用:
o = Optional.of("test");
ofNullable
根據(jù)傳入值構(gòu)建一個(gè)Optional對(duì)象
傳入的值可以是空值刮便,如果傳入的值是空值,則與empty返回的結(jié)果是一樣的绽慈。
方法
Optional包含以下方法:
方法名 | 說(shuō)明 |
---|---|
get | 獲取Value的值诺核,如果Value值是空值,則會(huì)拋出NoSuchElementException異常久信;因此返回的Value值無(wú)需再做空值判斷,只要沒(méi)有拋出異常漓摩,都會(huì)是非空值裙士。 |
isPresent | Value是否為空值的判斷; |
ifPresent | 當(dāng)Value不為空時(shí)管毙,執(zhí)行傳入的Consumer腿椎; |
ifPresentOrElse | Value不為空時(shí),執(zhí)行傳入的Consumer夭咬;否則執(zhí)行傳入的Runnable對(duì)象啃炸; |
filter | 當(dāng)Value為空或者傳入的Predicate對(duì)象調(diào)用test(value)返回False時(shí),返回Empty對(duì)象卓舵;否則返回當(dāng)前的Optional對(duì)象 |
map | 一對(duì)一轉(zhuǎn)換:當(dāng)Value為空時(shí)返回Empty對(duì)象南用,否則返回傳入的Function執(zhí)行apply(value)后的結(jié)果組裝的Optional對(duì)象; |
flatMap | 一對(duì)多轉(zhuǎn)換:當(dāng)Value為空時(shí)返回Empty對(duì)象掏湾,否則傳入的Function執(zhí)行apply(value)后返回的結(jié)果(其返回結(jié)果直接是Optional對(duì)象) |
or | 如果Value不為空裹虫,則返回當(dāng)前的Optional對(duì)象;否則融击,返回傳入的Supplier生成的Optional對(duì)象筑公; |
stream | 如果Value為空,返回Stream對(duì)象的Empty值尊浪;否則返回 Stream.of(value)的Stream對(duì)象匣屡; |
orElse | Value不為空則返回Value,否則返回傳入的值拇涤; |
orElseGet | Value不為空則返回Value捣作,否則返回傳入的Supplier生成的值; |
orElseThrow | Value不為空則返回Value工育,否則拋出Supplier中生成的異常對(duì)象虾宇; |
使用場(chǎng)景
常用的使用場(chǎng)景如下:
判斷結(jié)果不為空后使用
如某個(gè)函數(shù)可能會(huì)返回空值,以往的做法:
String s = test();
if (null != s) {
System.out.println(s);
}
現(xiàn)在的寫法就可以是:
Optional<String> s = Optional.ofNullable(test());
s.ifPresent(System.out::println);
乍一看代碼復(fù)雜度上差不多甚至是略有提升如绸;那為什么要這么做呢嘱朽?
一般情況下旭贬,我們?cè)谑褂媚骋粋€(gè)函數(shù)返回值時(shí),要做的第一步就是去分析這個(gè)函數(shù)是否會(huì)返回空值搪泳;如果沒(méi)有進(jìn)行分析或者分析的結(jié)果出現(xiàn)偏差稀轨,導(dǎo)致函數(shù)會(huì)拋出空值而沒(méi)有做檢測(cè),那么就會(huì)相應(yīng)的拋出空指針異常岸军!
而有了Optional后奋刽,在我們不確定時(shí)就可以不用去做這個(gè)檢測(cè)了,所有的檢測(cè)Optional對(duì)象都幫忙我們完成艰赞,我們要做的就是按上述方式去處理佣谐。
變量為空時(shí)提供默認(rèn)值
如要判斷某個(gè)變量為空時(shí)使用提供的值,然后再針對(duì)這個(gè)變量做某種運(yùn)算方妖;
以往做法:
if (null == s) {
s = "test";
}
System.out.println(s);
現(xiàn)在的做法:
Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElse("test"));
變量為空時(shí)拋出異常狭魂,否則使用
以往寫法:
if (null == s) {
throw new Exception("test");
}
System.out.println(s);
現(xiàn)在寫法:
Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElseThrow(()->new Exception("test")));