Java中lambda表达式的使用
???💕"我不要麻木的死去"💕
作者:Mylvzi?
?文章主要内容:Java中lambda表达式的使用?
一.背景
? lambda表达式是Java SE 8中一个重要的新特性,允许你使用一个表达式来代替功能接口。lambda表达式可以看作一个没有返回值,没有修饰符修饰的方法,它具有参数和这些参数的主体(方法体)Lambda 表达式(Lambda expression),基于数学中的λ演算得名,也可称为闭包(Closure)
二.语法
1.基本语法
??基本语法: (parameters) -> expression 或 (parameters) ->{ statements};
- parameters:类似于方法中的形参列表,参数来源于函数式接口的参数
- ->:可以理解为"被用于"
- expression :方法体? 可以是一条语句也可以是多条语句
2.函数式接口
? 函数式接口就是只含有一条抽象方法的接口
如果接口上声明了@FunctionalInterface,那么编译器就会按照函数式接口进行检验,也即此接口内部只能有一个抽象方法,但是可以使用default来添加一个非抽象方法
@FunctionalInterface
interface FuncInterface1 {
void test();
}
// 这样也是可以的
@FunctionalInterface
interface FuncInterface2 {
void test();
default void test2(){
System.out.println("===");
}
}
三.lambda表达式的基本使用
?lambda表达式就相当于使用一种更简单的方式重写了抽象方法(相比于使用匿名内部类)
以下所有情况的实现方式都有两种,lambda表达式和匿名内部类?
1.无返回值,无参数
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
使用两种方式实现
// 使用lambda表达式重写函数式接口的抽象方法 参数 方法体
NoParameterNoReturn noParameterNoReturn1 = () -> System.out.println("hello1");
noParameterNoReturn1.test();// 输出hello1
// 使用匿名内部类重写函数式接口的抽象方法
NoParameterNoReturn noParameterNoReturn2 = new NoParameterNoReturn() {
@Override
public void test() {
System.out.println("hello2");
}
};
2.无返回值,一个参数
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
使用两种方式实现
// 使用lambda表达式
OneParameterNoReturn oneParameterNoReturn = (x) -> System.out.println(x);
oneParameterNoReturn.test(10);// 打印10
// 使用匿名内部类
OneParameterNoReturn oneParameterNoReturn1 = new OneParameterNoReturn() {
@Override
public void test(int a) {
System.out.println(a);
}
};
注意:当参数只有一个或者方法体只有一句时,可以省略外面的();?
3.无返回值多个参数?
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
使用两种方式实现
// 使用lambda表达式
MoreParameterNoReturn moreParameterNoReturn = (x,y) -> System.out.println(x+y);
moreParameterNoReturn.test(10,20);// 输出30
// 使用匿名内部类
MoreParameterNoReturn moreParameterNoReturn1 = new MoreParameterNoReturn() {
@Override
public void test(int a, int b) {
System.out.println(a+b);
}
};
4.有返回值无参数
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
使用两种方式实现
NoParameterReturn noParameterReturn = () -> {return 10;};
System.out.println(noParameterReturn.test());// 输出10
// 简化
NoParameterReturn noParameterReturn1 = () ->10;
System.out.println(noParameterReturn1.test());// 输出10
// 使用匿名内部类
NoParameterReturn noParameterReturn2 = new NoParameterReturn() {
@Override
public int test() {
return 10;
}
};
5.有返回值一个参数
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
使用两种方式实现
OneParameterReturn oneParameterReturn = (x) -> {return x*x;};
System.out.println(oneParameterReturn.test(10));// 输出100
// 简化
OneParameterReturn oneParameterReturn1 = x -> x*x;
System.out.println(oneParameterReturn1.test(10));// 输出100
// 使用匿名内部类
OneParameterReturn oneParameterReturn2 = new OneParameterReturn() {
@Override
public int test(int a) {
return a*a;
}
};
6.有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
使用两种方式实现
MoreParameterReturn moreParameterReturn = (x,y) -> {return x+y;};
System.out.println(moreParameterReturn.test(10, 20));// 输出30
// 使用匿名内部类
MoreParameterReturn moreParameterReturn1 = new MoreParameterReturn() {
@Override
public int test(int a, int b) {
return a+b;
}
};
以上就是lambda表达式的基本使用?
四.变量捕获
? 1.什么是变量捕获
? 变量捕获:在一个内部作用域内(lambda表达式,匿名内部类等)中引用外部作用域(方法,类)的变量?
? 2.捕获的方式
? 当在内部作用域内引用外部作用域的变量时,Java会在内部作用域内对引用的变量进行拷贝/引用
? 3.匿名内部类的变量捕获
? 匿名内部类就是没有名字的类,往往用于接口的实现,下面使用一个简单的匿名内部类来实现
class Demo {
public void func() {
System.out.println("hello");
}
}
public class Demo10 {
public static void main(String[] args) {
new Demo() {
@Override
public void func() {
System.out.println("hello Demo");
}
};
}
}
?如果在匿名内部类中进行变量的捕获
1.局部变量? 且没有被修改过
2.局部变量? 但是被修改
可以发现,如果对A进行修改就会报错
这也是变量捕获的一个要求,即:
在内部作用域内捕获的变量(使用的变量)只能是被final修饰的或者从来没有被修改过的(被final修饰就代表无法改变)
? 如果你传入的变量并没有被final修饰,则系统会强制要求你传入的变量不能被修改!!!?
?4.lambda表达式中的变量捕获
? lambda表达式可以看作对匿名内部类进行的语法上的精简,同时也可以进行变量的捕获
@FunctionalInterface
interface DemoTest {
void func();
}
当使用被修改过的变量 -->依然报错
尽量使用被final修饰的变量
引用类变量
@FunctionalInterface
interface DemoTest {
void func();
}
public class Demo10 {
// 使用类变量 可以直接访问
public static int a = 10;
public static void main(String[] args) {
// lambda表达式
DemoTest demoTest = () -> {
System.out.println(a);
};
}
对于类变量来说,在lambda表达式中可以直接引用,因为类变量是属于类的,是所有对象公用的,它本身就有"静态"的属性?
五.在优先级队列中的使用
? 优先级队列中往往涉及到比较,我们在实例化优先级队列的时候往往要传递一个比较器,规定比较的对象
// 使用匿名内部类实现Comparator接口
PriorityQueue<Integer> priorityQueue = new PriorityQueue(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
?其实也能看出,Comparator方法应该是一个函数式接口,它属于"多个参数,有返回值"的类型(对应于上面的最后一种情况),此处就可以使用lambda表达式进行语法上的精简
// 使用lambda表达式实现优先级队列中的比较
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((o1,o2) ->{return o1-o2;});
Comparator的源码 -->多个参数,有返回值的接口
六.创建线程
?创建线程的方式有很多种,可以采用匿名内部类,lambda表达式
1.匿名内部类创建线程
// 创建线程 ->使用匿名内部类
Thread thread1 = new Thread() {
@Override
public void run() {
System.out.println("hello thread");
}
};
// 这种方式可以降低耦合性(推荐)
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello thread2");
}
});
为什么可以使用匿名内部类创建一个线程呢?主要是因为Thread类实现了Runnable接口,这个接口是一个函数式接口,只有一个抽象方法run()
2.使用lambda表达式
? 既然Thread可以通过匿名内部类方式创建线程,同时就可以使用lambda表达式来简化创建
// 方式1
Thread thread1 = new Thread(() ->{
System.out.println("hello thread1");
});
thread1.run();// 输出hello thread1
//方式2 利用lambda表达式实例化一个runnable接口 降低耦合性
Runnable runnable = () -> System.out.println("hello thread2");
Thread thread2 = new Thread(runnable);
thread2.run();// 输出hello thread2
七.lambda表达式在集合类中的使用(以后最常用的一种)
?为了能够让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对 接。
1.Collection接口
1.1forEach()
1.源码
forEach()在Iterable接口之下,源码如下:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
对传入的集合的每个元素执行action操作,进一步观察
可以观察到。forEach()方法接受了一个Comsumer类型的参数action,接着会对每一个action执行对应的操作。Consumer是一个函数式接口,属于"一个参数但无返回值"的类型,内部有一个抽象方法accept用于接受参数并执行特定的操作
2.使用匿名内部类实现
List<String> list = new ArrayList<>();
list.add("hello");
list.add("my");
list.add("friends");
list.add("!!!");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s + " ");
}
});
?
3.使用lambda表达式
// lambda表达式
list.forEach((s) -> System.out.print(s + " "));
1.2removeif()
? removeif()用于根据条件删除集合中的对应数据,如果有对应条件的数据,删除,并将标志位removed设置为true(注意:removeif不是只删除一个符合条件的数据,而是类似于removeAll一样的效果)
1.源码:
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
2.图解:
3.使用
List<String> list = new ArrayList<>();
list.add("hello");
list.add("my");
list.add("friends");
list.add("!!!");
// 1.先打印原数据
list.forEach((s) -> System.out.print(s + " "));
// 2.删除长度 <= 3的字符串
boolean flg = list.removeIf(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() <= 3;
}
});
System.out.println("");
// 3.判断是否有删除操作
System.out.println(flg);
// 4.打印删除之后的数据
list.forEach((s) -> System.out.print(s + " "));
打印结果:
?2.List接口
2.1 sort
1.源码:
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
?2.图解:
3.使用:
List<String> list = new ArrayList<>();
list.add("hello");
list.add("my");
list.add("friends");
list.add("!!!");
// 使用匿名内部类
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);// 从小到大排序
}
});
// 使用lambda表达式
list.sort((o1,o2) -> {
return o1.compareTo(o2);
});
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s + " ");
}
});
打印结果:
2.2 reolaceAll?
?1.源码:
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
2.图解:
3.使用:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 打印原数据
System.out.println(list.toString());
// 使用匿名内部类
list.replaceAll(new UnaryOperator<Integer>() {
@Override
public Integer apply(Integer integer) {
return integer*2;// 将所有的值都设置为原来的两倍
}
});
// 使用lambda表达式
list.replaceAll((x) ->{return x*2;});
// 打印修改之后的数据
System.out.println(list.toString());
打印数据:
3.Map接口
3.1?forEach
1.源码:
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
2.图解:
3.使用:
Map<String,Integer> map = new HashMap<>();
map.put("zs",1);
map.put("ls",2);
map.put("ww",3);
// 使用匿名内部类
map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println("key:" + s + " val:" + integer);
}
});
System.out.println("==============");
// 使用lambda表达式
map.forEach((key,val) ->{
System.out.println("key:" + key + " val:" + val);
});
打印结果:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!