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();
}

最新文章

  1. a 标签中加 onclick事件,根据事件中的校验情况来决定是否执行a标签的链接
  2. xss其他标签下的js用法总结大全
  3. TextMate2 最新版下载及源码编译过程
  4. 给select添加自定义值和选项
  5. C# String.Format大全 去 decimal 后面的 0
  6. 玩转SmartQQ之登录
  7. invesments 第三章 上
  8. 我的Android学习之旅(转)
  9. 点击下拉,其余不动的jquery事件(转)
  10. [uwsgi]使用建议(类似最佳实践)
  11. 7.Django CSRF 中间件
  12. c++第五周学习小结
  13. 模仿WC.exe的功能实现--node.js
  14. maven加载springboot project
  15. 小程序问题集:保存失败:Error: ENOENT: no such file or directory, open
  16. 思科4506E做ehterchannel故障排查
  17. 使用xshell+xmanager+pycharm搭建pytorch远程调试开发环境
  18. C#简繁体转换
  19. scala mysql jdbc oper
  20. pytest+request 接口自动化测试

热门文章

  1. 【转】Setting up SDL Extension Libraries on MinGW
  2. Learn day6 模块pickle\json\random\os\zipfile\面对对象(类的封装 操作 __init__)
  3. [Luogu P1268] 树的重量 (巧妙的构造题)
  4. adb命令如何获取appPackage和appActivity的信息
  5. Docker(11)- docker ps 命令详解
  6. UDS诊断之0x11服务
  7. 通过阿里镜像网站制作iso文件安装CentOS6.9
  8. ubuntu设置mentohust开机自动登录校园网
  9. css3 渐变 兼容
  10. SQL2005中清空操作日志的语句(SQL2008有所不同)