Java基础教程——Lambda表达式
Lambda表达式
Java8引入Lambda表达式,可以使代码更简洁。
格式:参数,箭头,代码
(参数名)->{代码}
Lambda表达式体现了“函数式编程思想”——
面向对象的思想:找一个能解决问题的对象,调用对象完成事情。
函数式编程思想:只要结果,不管过程,不在乎是谁做、怎么做。
Lambda表达式的前提——函数式接口。
函数式接口,且只有一个未实现方法,可用注解@FunctionalInterface进行限定。
接口有且只有一个未实现方法,Lambda才能进行推导。
可以有其它非抽象方法,比如默认方法。
lambda表达式可推导、可省略:
- 参数类型可以不写
- 参数只有一个的话,类型和()都可以省略
- 如果{}中的代码只有一行,可以省略{}、return、分号
package ah;
import java.util.*;
public class TestLambda {
public static void main(String[] args) {
System.out.println("---- 1.线程(无参数)");
// |--(1.1)匿名内部类写法
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
});
t.start();
// |--(1.2)Lambda表达式写法
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread());
});
t2.start();
System.out.println("---- 2.集合排序(带参数)");
List<Phone> lst = new ArrayList<>();
lst.add(new Phone(1000, 300));
lst.add(new Phone(2000, 200));
lst.add(new Phone(3000, 100));
// |--(2.1)匿名内部类写法
Collections.sort(lst, new Comparator<Phone>() {
@Override
public int compare(Phone o1, Phone o2) {
return (int) (o2.price - o1.price);
}
});
System.out.println(lst);
// |--(2.2)Lambda表达式写法
Collections.sort(lst, (Phone o1, Phone o2) -> {
return o2.hot - o1.hot;
});
System.out.println(lst);
// |--(2.3)Lambda表达式省略写法(参数类型省略,{}、return、分号省略)
Collections.sort(lst, (o1, o2) -> o1.hot - o2.hot);
System.out.println(lst);
System.out.println("---- 3.一个参数的场合:参数括号能省略");
// |--(3.1)输出集合内容
lst.forEach(s -> System.out.println(s));
// |--(3.2)自定义接口和方法,参数使用接口
testArgIsInterface(s -> System.out.println(s), 100);
}
static void testArgIsInterface(IoneArg arg, int n) {
arg.m(n);
}
}
class Phone {
double price;
int hot;
public Phone(double price, int hot) {
this.price = price;
this.hot = hot;
}
@Override
public String toString() {
return "Phone [price=" + price + ", hot=" + hot + "]";
}
}
@FunctionalInterface
interface IoneArg {
void m(int n);
}
---- 1.线程(无参数)
Thread[Thread-0,5,main]
---- 2.集合排序(带参数)
Thread[Thread-1,5,main]
[Phone [price=3000.0, hot=100], Phone [price=2000.0, hot=200], Phone [price=1000.0, hot=300]]
[Phone [price=1000.0, hot=300], Phone [price=2000.0, hot=200], Phone [price=3000.0, hot=100]]
[Phone [price=3000.0, hot=100], Phone [price=2000.0, hot=200], Phone [price=1000.0, hot=300]]
---- 3.一个参数的场合:参数括号能省略
Phone [price=3000.0, hot=100]
Phone [price=2000.0, hot=200]
Phone [price=1000.0, hot=300]
100
Supplier接口
java.util.function 包下有很多函数式接口,比如:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Supplier接口称为“生产型接口”,指定接口的泛型,get方法会产生相应类型的数据。
使用示例:
import java.util.function.Supplier;
public class TestSupplier {
// 将Supplier类型作为参数,以便Lambda知道接口类型
// 要实现的功能:获取数组的最大值
static int getMax(Supplier<Integer> sup) {
return sup.get();
}
public static void main(String[] args) {
int arr[] = { 5, 3, 2, -5, 99, 76 };
int maxOfArr = getMax(() -> {
int max = arr[0];
for (int n : arr) {
max = max < n ? n : max;
}
return max;
});
System.out.println(maxOfArr);
}
}
99
Consumer接口
和Supplier接口相对,用于“消费”,接受参数用于处理。addThen方法用于连续处理。
@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); };
}
}
Consumer示例:
import java.util.function.Consumer;
public class TestConsumer {
public static void main(String[] args) {
testAccept((str) -> {
System.out.println(str);
}, "孙行者");
testAndThen((str) -> System.out.println("A" + str),
(str) -> System.out.println(str + "Z"), "猪悟能");
}
static void testAccept(Consumer<String> c, String s) {
// accept接受数据:可以使用数据(相当于消费)
c.accept(s);
}
static void testAndThen(Consumer<String> c1, Consumer<String> c2, String s) {
c1.accept(s);
c2.accept(s);
System.out.println("---default andThen:相当于把两个Consumer连起来使用");
c1.andThen(c2).accept(s);
System.out.println("---连接分先后,参数为后");
c2.andThen(c1).accept(s);
}
}
孙行者
A猪悟能
猪悟能Z
---default andThen:相当于把两个Consumer连起来使用
A猪悟能
猪悟能Z
---连接分先后,参数为后
猪悟能Z
A猪悟能
Predicate接口
predicate:谓词。指boolean-valued,主要有ADD,OR,NOT
源码:
@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);
}
}
示例:对字符串进行判断
import java.util.function.Predicate;
public class TestPredicate {
static void testTest(Predicate<String> p, String s) {
System.out.println(p.test(s));
}
static void testAnd(Predicate<String> p1, Predicate<String> p2, String s) {
System.out.println(p1.and(p2).test(s));
}
public static void main(String[] args) {
testTest((s) -> s == null, "A");
// 判断字符串不为null,同时长度>5
testAnd(
// 参数1:判断不为null
(s) -> s != null,
// 参数2:判断长度>5
(s) -> s.length() > 5,
// 参数3:
"123456");
}
}
false
true
示例:
import java.util.*;
import java.util.function.Predicate;
public class TestPredicate2 {
// 对数组进行过滤,把符合条件的放入集合中
static List<String> filter(Predicate<String> p1, Predicate<String> p2,
String[] arr) {
List<String> lst = new ArrayList<>();
for (String str : arr) {
if (p1.and(p2).test(str)) {
lst.add(str);
}
}
return lst;
}
public static void main(String[] args) {
String[] s = { "关羽,蜀,武", "张飞,蜀,武", "典韦,魏,武", "诸葛亮,蜀,文" };
// 将蜀国的文官放入列表
List<String> lst = filter(
// 参数1:一种操作
(name) -> {
String[] split = name.split(",");
String nation = split[1];
if ("蜀".equals(nation)) {
return true;
} else {
return false;
}
},
// 参数2:另一种操作
(name) -> name.split(",")[2].equals("文"),
// 参数3:被操作的字符串
s);
System.out.println(lst);
}
}
[诸葛亮,蜀,文]
Function接口
根据一个类型的数据(前置条件)得到另一个类型的数据(后置条件)。
package java.util.function;
import java.util.Objects;
@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;
}
}
示例:
import java.util.function.Function;
public class TestFunction {
static void testApply(Function<String, Integer> f, String s) {
Integer n = f.apply(s);
System.out.println(n);
}
static void testAddThen(Function<String, String> f1,
Function<String, String> f2, Function<String, String> f3, String s) {
// compose:组合,先做
// addThen:后做
String ret = f1.compose(f2).andThen(f3).apply(s);
System.out.println(ret);
}
public static void main(String[] args) {
String str = ">>1234";
testApply(
// 参数1:把字符串转换为整数
s -> {
s = s.substring(2);
return Integer.parseInt(s);
},
// 参数2:要处理的字符串
str);
testAddThen(
// 参数1
s -> s + "【齐天大圣】",
// 参数2:做了compose的参数(先做)
s -> s + "【弼马温】",
// 参数3:做了andThen参数(后做)
s -> s + "【斗战胜佛】",
// 参数四:字符串
"孙悟空");
}
}
1234
孙悟空【弼马温】【齐天大圣】【斗战胜佛】
延迟执行
有些场景下,代码执行后,结果不一定被使用,这将造成浪费。Lambda表达式是“延迟执行”的,正好作为解决方案,提升性能。
比如:
public class TestLambdaLazy {
// 非Lambda参数,会产生字符串
public static void log(int level, String msg) {
if (level == 1) {
System.out.println(msg);
}
}
// Lambda表达式写法:参数改为函数式接口
// 参数虽然传递(对象),但是不使用的时候不执行
public static void log(int level, Message msg) {
if (level == 1) {
System.out.println(msg.setMsg());
}
}
public static void main(String[] args) {
int sum = 100;
log(2, "总计:" + sum);// 其实没有打印,字符串徒劳拼接
log(2, () -> {
System.out.println("Lambda执行");
return "总计:" + sum;
});
}
}
// Lambda用的函数式接口
interface Message {
String setMsg();
}