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();
}
Java基础教程——Lambda表达式的更多相关文章
- Java基础语法-Lambda表达式
1.Lambda表达式主要用于简写接口的操作等出现匿名内部类的地方,如下:我这里先定义一个Swim接口,以及它所定义的swim()方法 interface Swim{ void swim(); } 2 ...
- Java基础教程(8)--表达式、语句和块
一.表达式 表达式由变量和运算符组成.下面是一个简单的赋值表达式: a = 0; 表达式都具有运算结果,因为赋值表达式的运算结果是左侧操作数的值,因此上面的表达式将会返回一个0.可以使用简单的 ...
- Java基础教程:Lambda表达式
Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...
- Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】
原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...
- Java基础教程:泛型基础
Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...
- Java 8中Lambda表达式默认方法的模板方法模式,你够了解么?
为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行.在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容. 模板 ...
- java 8 中lambda表达式学习
转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-o ...
- Lambda 表达式,Java中应用Lambda 表达式
一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...
- Java基础教程(18)--继承
一.继承的概念 继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...
随机推荐
- 面试时说Redis是单线程的,被喷惨了!
Redis是单线程的,这话搁以前,是横着走的,谁都知道的真理.现在不一样,Redis 变了.再说这句话,多少得有质疑的语气来跟你辩驳一番.意志不坚定的,可能就缴械投降,顺着别人走了. 到底是什么样的, ...
- nb-iot技术实现跟踪功能的应用
在互联网和连接的世界里,nb-iot风靡一时.企业和个人正在利用nb-iot技术和nb-iot设备的可靠,快速连接能力,对其技术系统进行渐进式更改,并创建一个互联的"智能"世界. ...
- python构造函数和析构函数
构造函数和析构函数 关注公众号"轻松学编程"了解更多. 1.构造方法的使用 很多类都倾向于将对象创建为有初始化状态.因此类可以定义一个名为__init__()的特殊方法(构造方 ...
- 如果在Yii中,使用AR查询,不直接写sql,则在使用的时候会报错
如果在Yii中,使用AR查询,不直接写sql,则在使用的时候会报错 Student::find() ->select("id,name,from_unixtime(create_tim ...
- K8S Canal基于Prometheus进行实时指标监控
文章来源于本人的印象笔记,如出现格式问题可访问该链接查看原文 部署canal的prometheus监控到k8s中 1.grafana的docker部署方式:https://grafana.com/gr ...
- XJOI 夏令营501-511测试11 游戏
Alice和Bob两个人正在玩一个游戏,游戏有很多种任务,难度为p的任务(p是正整数),有1/(2^p)的概率完成并得到2^(p-1)分,如果完成不了,得0分.一开始每人都是0分,从Alice开始轮流 ...
- JS数组去重的9种方法(包括去重NaN和复杂数组类型)
其实网上已经有很多js数组的去重方法,但是我看了很多篇并自己通过代码验证,发现都有一些缺陷,于是在研究多篇代码之后,自己总结了9种方法,如果有哪里不对请及时纠正我哈~ 转载请表明出处 测试代码 let ...
- tp3.2关闭debug save方法执行失败
解决该问题需要 清除缓存文件 将retime下的文件删除
- 调试HotSpot源代码(配视频)
本文将详细介绍在Ubuntu16.04 LTS上对OpenJDK8进行编译,为了方便大家快速搭建起OpenJDK8的调试开发环境,我还录制了对应的视频放到了B站上,大家可以参考. 视频地址:https ...
- 基于selenium微博个人主页视频下载
# -*- coding: utf-8 -*- import selenium from selenium import webdriver import time import urllib.req ...