Java 8中有两个最为重要的改变:第一个是Lambda表达式,另一个则是Stream API。使用Stream配合Lambda表达式、方法引用会让你的代码更简洁。
list.stream().map(good -> good.getName())
.map(string -> string.toUpperCase())
.forEach(string -> System.out.println(string));
list.stream().map(Goods :: getName).map(String :: toUpperCase).forEach(System.out :: println);
Java - Stream流 - 让你的代码更简洁(创建流、中间操作(筛选、映射、排序)、终止操作(匹配、约简、收集))
Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更加简洁的 Java 代码。
Lambda 表达式是一个可传递的代码块, 可以在以后执行一次或多次。
关键:Lambda 表达式在Java中是函数式接口的一个对象(实例)
Lambda表达式分为三部分:
下面将Lambda表达式分为6种情况:
我们以Runnable接口举例说明:创建一个线程:
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Java 8之前的写法是这样的:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("线程运行中");
}
};
runnable.run();
使用Lambda表达式,只留参数列表(这里没有参数,但必须留括号),‘->’ 和方法体:
Runnable runnable = () -> {
System.out.println("线程运行中");
};
runnable.run();
只有一条语句且不是return语句时,方法体的花括号可以省略:
Runnable runnable = () -> System.out.println("线程运行中");
runnable.run();
我们以Consumer接口举例说明:判断一个数是大于0,小于0或等于0:
package java.util.function;
import java.util.Objects;
@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); };
}
}
Java 8之前的写法是这样的:
Consumer<Integer> consumer = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
if (t > 0) {
System.out.println("大于0");
} else if (t < 0) {
System.out.println("小于0");
} else {
System.out.println("等于0");
}
}
};
consumer.accept(0);
使用Lambda表达式,只留参数列表(这里的参数是t),‘->’ 和方法体(这里有多条语句,花括号不能省略):
Consumer<Integer> consumer = (Integer t) -> {
if (t > 0) {
System.out.println("大于0");
} else if (t < 0) {
System.out.println("小于0");
} else {
System.out.println("等于0");
}
};
consumer.accept(-10);
由于参数 t 的类型可以由 Consumer
Consumer<Integer> consumer = (t) -> {
if (t > 0) {
System.out.println("大于0");
} else if (t < 0) {
System.out.println("小于0");
} else {
System.out.println("等于0");
}
};
consumer.accept(-10);
当参数列表中的参数只有一个时,参数旁边的 () 可以省略。
Consumer<Integer> consumer = t -> {
if (t > 0) {
System.out.println("大于0");
} else if (t < 0) {
System.out.println("小于0");
} else {
System.out.println("等于0");
}
};
consumer.accept(-10);
我们自己写一个接口进行说明:
@FunctionalInterface
interface MultiParamNoReturn<T> {
void method(T a, T b);
}
Java 8之前的写法是这样的:
MultiParamNoReturn<Integer> m = new MultiParamNoReturn<Integer>() {
@Override
public void method(Integer a, Integer b) {
System.out.printf("%d + %d = %d\n", a, b, (a + b));
}
};
m.method(10, 11);
使用Lambda表达式,只留参数列表(这里的参数是a,b),‘->’ 和方法体:
MultiParamNoReturn<Integer> m = (a, b) ->
System.out.printf("%d + %d = %d\n", a, b, (a + b));
m.method(5, 6);
我们以Supplier接口举例说明:
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Java 8之前的写法是这样的:
Supplier<Double> supplier = new Supplier<Double>() {
@Override
public Double get() {
return (Double)Math.random()*10000;
}
};
System.out.printf("今天又双叒叕丢了%.2f块钱",supplier.get());
使用Lambda表达式,只留参数列表(这里没有参数),‘->’ 和方法体:
Supplier<Double> supplier = () -> {
return (Double)Math.random()*10000;
};
System.out.printf("今天又双叒叕丢了%.2f块钱\n",supplier.get());
当Lambda表达式的方法体只有一条语句,且是return语句,那么return和花括号都可以省略。
Supplier<Double> supplier = () -> (Double)Math.random()*10000;
System.out.printf("今天又双叒叕丢了%.2f块钱\n",supplier.get());
我们以Predicate接口举例说明:判断一个字符串是否相等:
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
...
}
Java 8之前的写法是这样的:
public static boolean search(List<String> list, Predicate<String> predicate) {
for (String string : list) {
if (predicate.test(string))
return true;
}
return false;
}
public static void main(String[] args) {
List<String> list = Arrays.asList("Lanbda","Lamdba","Landba","Lembda","Lambde");
boolean result = search(list, new Predicate<String>() {
@Override
public boolean test(String t) {
return t.equals("Lambda");
}
});
System.out.println(result);
}
使用Lambda表达式:
public static boolean search(List<String> list, Predicate<String> predicate) {
for (String string : list) {
if (predicate.test(string))
return true;
}
return false;
}
public static void main(String[] args) {
List<String> list = Arrays.asList("Lanbda","Lamdba","Landba","Lembda","Lambde");
boolean result = search(list, t -> t.equals("Lambda"));
System.out.println(result);
}
我们以Comparator接口举例说明:Comparator自然排序:
package java.util;
...
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
...
}
Java 8之前的写法是这样的:
List<Integer> list = Arrays.asList(30,10,62,47,84,7,55);
Collections.sort(list, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
System.out.println(list);
这里有一个问题:为什么Comparator有两个抽象方法compare和equals,但是必须要重写compare,而不必重写equals?
戳我☞☞☞因为重写了超类Object类中任意一个public方法的方法并不算接口中的抽象方法,任何接口的实现都会从其父类Object或其它地方获得这些方法的实现。
使用Lambda表达式:
List<Integer> list = Arrays.asList(30,10,62,47,84,7,55);
Collections.sort(list,(o1, o2) -> Integer.compare(o1, o2));
System.out.println(list);
函数式接口(Functional Interface)是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。我们可以通过Lambda表达式来创建该接口的对象。
我们可以在一个接口上使用 @FunctionalInterface 注解,这样可以检查它是否是一个函数式接口。
在java.util.function包下定义了丰富的函数式接口。
方法引用可以看做是lambda表达式深层次的表达。换句话说,方法引用就是lambda表达式,也就是函数式接口的一个对象(实例)。
使用场景:当要传递给Lambda体的操作,已经有实现的方法了,那么就可以使用方法引用。
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致(相同)。
格式:使用操作符 “::” 将类(或对象)与方法名分割开来。(是已经实现好的方法名及其所在的类或对象)。(可以看成左边的类或对象是调用者,右边的方法是被调用者)
Consumer接口中的方法:void accept(T t)
PrintStream类中的方法:void println(T t)
匿名内部类方式:
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}
};
consumer.accept("hello world");
Lambda表达式方式:
Consumer<String> consumer = string -> System.out.println(string);
consumer.accept("hello world");
方法引用方式:
从Lambda表达式看,可以看成 ‘->’ 左边的参数列表和右边的参数列表相同,且右边的方法已经实现好了,那么用 ‘::’ 将右边的调用者和方法分割开来。
PrintStream printStream = System.out;
Consumer<String> consumer = printStream :: println;
consumer.accept("hello world");
Supplier接口中的方法:T get()
Person类中的方法:String getName()
public class Person{
public String name;
public Person(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;
}
...
}
匿名内部类方式:
Person person = new Person("Tom",10);
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return person.getName();
}
};
System.out.println(supplier.get());
Lambda表达式方式:
Supplier<String> supplier = () -> person.getName();
System.out.println(supplier.get());
方法引用方式:
Supplier<String> supplier = person :: getName;
System.out.println(supplier.get());
Comparator接口中的方法:int compare(T t1, T t2)
Integer类中的方法:int compare(T t1, T t2)
匿名内部类方式:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(comparator.compare(10, 5));
Lambda表达式方式:
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(comparator.compare(1, 5));
方法引用方式:
Comparator<Integer> comparator = Integer :: compare;
System.out.println(comparator.compare(5, 5));
Function接口中的方法:R apply(T t)
Math类中的方法:Long round(Double d)
匿名内部类方式:
Function<Double, Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double d) {
return Math.round(d);
}
};
System.out.println(function.apply(123.7));
Lambda表达式方式:
Function<Double, Long> function = d -> Math.round(d);
System.out.println(function.apply(111.8));
方法引用方式:
Function<Double, Long> function = Math :: round;
System.out.println(function.apply(100.4));
Comparator接口中的方法:int compare(T t1, T t2)
String类中的方法:int t1.compare(T t2)
匿名内部类方式:
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare("c", "a"));
Lambda表达式方式:
Comparator<String> comparator = (o1, o2) -> o1.compareTo(o2);
System.out.println(comparator.compare("z", "a"));
方法引用方式:
Comparator<String> comparator = String :: compareTo;
System.out.println(comparator.compare("a", "z"));
BiPredicate接口中的方法:boolean test(T t, U u)
String类中的方法:boolean t.equals(U u)
匿名内部类方式:
BiPredicate<String, String> biPredicate = new BiPredicate<String, String>() {
@Override
public boolean test(String t, String u) {
return t.equals(u);
}
};
System.out.println(biPredicate.test("Lambda", "Lamdba"));
Lambda表达式方式:
BiPredicate<String, String> biPredicate = (t, u) -> t.equals(u);
System.out.println(biPredicate.test("Lambda", "Lamdba"));
方法引用方式:
BiPredicate<String, String> biPredicate = String :: equals;
System.out.println(biPredicate.test("Lambda", "Lambda"));
Function接口中的方法:R apply(T t)
Person类中的方法:String getName()
匿名内部类方式:
Person person = new Person("Jerry",20);
Function<Person, String> function = new Function<Person, String>() {
@Override
public String apply(Person t) {
return t.getName();
}
};
System.out.println(function.apply(person));
Lambda表达式方式:
Person person = new Person("Jerry",20);
Function<Person, String> function = t -> t.getName();
System.out.println(function.apply(person));
方法引用方式:
Person person = new Person("Jerry",20);
Function<Person, String> function = Person::getName;
System.out.println(function.apply(person));
类似的还有
(x, y) -> x.compareToIgnoreCase(y);
//等价于
String :: compareToIgnoreCase;
构造器引用与方法引用类似,其要求是函数式接口的抽象方法的参数列表与构造器的参数列表相同。抽象方法的返回值类型即为构造器所属类的类型。
格式:类名 “::” new
Supplier接口中的方法:T get()
Person类中的构造器:Person()
匿名内部类方式:
Supplier<Person> supplier = new Supplier<Person>() {
@Override
public Person get() {
return new Person();
}
};
System.out.println(supplier.get());
Lambda表达式方式:
Supplier<Person> supplier = () -> new Person();
System.out.println(supplier.get());
构造器引用方式:
Supplier<Person> supplier = Person :: new;
System.out.println(supplier.get());
BiFunction接口中的方法:R apply(T t, U,u)
Person类中的构造器:Person(String name, int age)
匿名内部类方式:
BiFunction<String, Integer, Person> b = new BiFunction<String, Integer, Person>() {
@Override
public Person apply(String name, Integer age) {
return new Person(name, age);
}
};
System.out.println(b.apply("Jack", 18));
Lambda表达式方式:
BiFunction<String, Integer, Person> b = (name, age) -> new Person(name, age);
System.out.println(b.apply("Jack", 18));
构造器引用方式:
BiFunction<String, Integer, Person> b = Person :: new;
System.out.println(b.apply("Jack", 18));
数组引用与构造器引用类似。
Function接口中的方法:R apply(T t)
匿名内部类方式:
Function<Integer, String[]> function = new Function<Integer, String[]>() {
@Override
public String[] apply(Integer t) {
return new String[t];
}
};
String[] array = function.apply(5);
System.out.println(Arrays.toString(array));
Lambda表达式方式:
Function<Integer, String[]> function = length -> new String[length];
String[] array = function.apply(5);
System.out.println(Arrays.toString(array));
数组引用方式:
Function<Integer, String[]> function = String[] :: new;
String[] array = function.apply(5);
System.out.println(Arrays.toString(array));
如有错误请大家指出了(ง •̀_•́)ง (*•̀ㅂ•́)و