Java8lambda表达式概念以及使⽤lambda操作list集合replaceall()
⼀、Lambda 表达式基本概况
(1)Lambda 表达式,也可称为闭包,它是推动Java 8发布的最重要新特性;Lambda 允许把函数作为⼀个⽅法的参数(函数作为参数传递进⽅法中);使⽤ Lambda 表达式可以使代码变的更加简洁紧凑。
语法如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
(2)以下是lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统⼀识别参数值。
可选的参数圆括号:⼀个参数⽆需定义圆括号,但多个参数需要定义圆括号。
可选的⼤括号:如果主体包含了⼀个语句,就不需要使⽤⼤括号。
可选的返回关键字:如果主体只有⼀个表达式返回值则编译器会⾃动返回值,⼤括号需要指明表达式返回了⼀个数值。
(3)使⽤ Lambda 表达式需要了解以下⼏点:
Lambda 表达式主要⽤来定义⾏内执⾏的⽅法类型接⼝,例如,⼀个简单⽅法接⼝。
Lambda 表达式免去了使⽤匿名⽅法的⿇烦,并且给予Java简单但是强⼤的函数化的编程能⼒。
将匿名内部类简写成lambda表达式的依据:
能够使⽤Lambda的依据是必须有相应的函数接⼝(函数接⼝,是指内部有抽象⽅法的接⼝)。实际上Lambda的类型就是对应函数接⼝的类型。
Lambda表达式另⼀个依据是类型推断机制,在上下⽂信息⾜够的情况下,编译器可以推断出参数表的类型,⽽不需要显式指
明。注意,Java是强类型语⾔,每个变量和对象都必须有明确的类型。
如果使⽤了匿名内部类,编译过后将会产⽣⼀个以$符号结尾的class字节码⽂件,⽽使⽤lambda则不
会产⽣这样的class字节码⽂件,只会产⽣⼀个class⽂件,这是因为jvm将Lambda表达式封装成了主类的⼀个私有⽅法,并通过invokedynamic指令进⾏调⽤。
(4)变量作⽤域
lambda 表达式只能引⽤标记了 final的外层局部变量,这就是说不能在lambda内部修改定义在域外的局部变量,否则会报编译错误。
lambda 表达式内的局部变量可以不⽤声明为final,但是必须不可被后⾯的代码修改(即隐性的具有final 的语义)。
在Lambda 表达式当中不允许声明⼀个与局部变量同名的参数或者局部变量。
⼆、Lambda and Collections
我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起。
为引⼊Lambda表达式,Java8新增了java.util.funcion包,⾥⾯包含常⽤的函数接⼝,这是Lambda表达式的基础,Java集合框架也新增部分接⼝,以便与Lambda表达式对接。
⾸先回顾⼀下Java集合框架的接⼝继承结构:
上图中绿⾊标注的接⼝类,表⽰在Java8中加⼊了新的接⼝⽅法,当然由于继承关系,他们相应的⼦类也都会继承这些新⽅法。下表详细列举了这些⽅法。
接⼝名Java8新加⼊的⽅法
Collection removeIf()、spliterator()、 stream()、 parallelStream() 、forEach()
List replaceAll() 、sort()
接⼝名Java8新加⼊的⽅法
Map getOrDefault()、 forEach()、 replaceAll()、 putIfAbsent() 、remove()、 replace() 、computeIfAbsent() 、computeIfPresent()、compute()、 merge()
这些新加⼊的⽅法⼤部分要⽤到java.util.function包下的接⼝,这意味着这些⽅法⼤部分都跟Lambda表达式相关。
Collection中的新⽅法
(1)forEach()⽅法以list为例说明forEach()⽅法。
该⽅法的签名为void forEach(Consumer<? super E> action),作⽤是对容器中的每个元素执⾏action指定的动作,其中Consumer是个函数接⼝,⾥⾯只有⼀个待实现⽅法void accept(T t)。
需求:假设有⼀个字符串列表,需要打印出其中所有长度⼤于3的字符串。
List<String> list = new ArrayList<>(Arrays.asList("i", "love", "liangliang"));
// 使⽤增强for循环实现
for (String s : list) {
if (s.length() > 3) {
System.out.println("使⽤增强for循环实现:" + s);
}
}
// 使⽤匿名内部类实现Comsumer接⼝
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
if (s.length() > 3) {
System.out.println("使⽤Consumer内部类实现:" + s);
}
}
});
// 上述代码调⽤forEach()⽅法,并使⽤匿名内部类实现Comsumer接⼝。
// lambda写法
list.forEach(s -> {
if (s.length() > 3) {
System.out.println("使⽤lambda表达式实现:" + s);
}
});
// 上述代码给forEach()⽅法传⼊⼀个Lambda表达式,我们不需要知道accept()⽅法,也不需要知道Consumer接⼝,类型推导帮我们做了⼀切。
提⽰:在idea中,如果使⽤了匿名内部类实现,idea会提⽰将它转换成lambda表达式实现,因此如果暂时忘记了如何写lambda表达式可以利⽤这⼀特性快速转成lambda表达式。
(2)removeIf() 以list为例说明removeIf()⽅法。
该⽅法签名为boolean removeIf(Predicate<? super E> filter),作⽤是删除容器中所有满⾜filter指定条件的元素,其中Predicate是⼀个函数接⼝,⾥⾯只有⼀个待实现⽅法boolean test(T t)。
需求:假设有⼀个字符串列表,需要删除其中所有长度⼤于3的字符串。
List<String> list = new ArrayList<>(Arrays.asList("i", "love", "liangliang"));
// 我们知道如果需要在迭代过程中对容器进⾏删除操作必须使⽤迭代器,否则会抛出ConcurrentModificationException,所以迭代器实现如下
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (().length() > 3) {
}
}
// 遍历出来,使⽤lambda表达式
list.forEach(System.out::println);
// 使⽤removeIf()⽅法,并使⽤匿名内部类实现Precicate接⼝
@Override
public boolean test(String s) {
return s.length() > 3;
}
});
list.forEach(System.out::println);
// 使⽤lambda表达式实现删除长度⼤于3的元素
list.forEach(System.out::println);
不得不说idea真的太智能了,提⽰检测功能简直了,不⽤说了今后对于idea的提⽰建议90%我都接受,太智能了。
(3)replaceAll() 以list为例说明replaceAll()⽅法。
该⽅法签名为void replaceAll(UnaryOperator<E> operator),作⽤是对每个元素执⾏operator指定的操作,并⽤操作结果来替换原来的元素。其
中UnaryOperator是⼀个函数接⼝,⾥⾯只有⼀个待实现函数T apply(T t)。
需求:假设有⼀个字符串列表,将其中所有长度⼤于3的元素转换成⼤写,其余元素不变。
List<String> list = new ArrayList<>(Arrays.asList("i", "love", "liangliang"));
// Java7及之前的实现⽅式,采⽤for循环实现
for (int i = 0; i < list.size(); i++) {
String str = (i);
if (str.length() > 3) {
list.set(i, UpperCase());
}
}
list.forEach(System.out::println);
// 调⽤replaceAll()⽅法,并使⽤匿名内部类实现UnaryOperator接⼝
@Override
public String apply(String s) {
if (s.length() > 3) {
UpperCase();
}
return s;
}
});
list.forEach(System.out::println);
// 使⽤Lambda表达式实现
if (s.length() > 3) {
UpperCase();
} else {
return s;
}
});
list.forEach(System.out::println);
(4)sort() 以list为例说明sort()⽅法。
该⽅法定义在List接⼝中,⽅法签名为void sort(Comparator<? super E> c),该⽅法根据c指定的⽐较规则对容器元素进⾏排序。Comparator接⼝我们并不陌⽣,其中有⼀个⽅法int compare(T o1, T o2)需要实现,显然该接⼝是个函数接⼝。
需求:假设有⼀个字符串列表,按照字符串长度增序对元素排序。
List<String> list = new ArrayList<>(Arrays.asList("love", "liangliang", "i"));
// 按元素长度进⾏排序
// 由于Java7以及之前sort()⽅法在Collections⼯具类中,所以代码要这样写:
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 默认是升序排序
return o1.length() - o2.length();
}
});
// 输出排序后的结果
list.forEach(System.out::println);
// 现在可以直接使⽤List.sort()⽅法,结合Lambda表达式实现对list元素排序
list.sort((str1, str2) -> str1.length() - str2.length());
// 还可以进⼀步简化成如下进⾏排序
list.sort(ComparatorparingInt(String::length));
// 输出排序后的结果
list.forEach(System.out::println);
这⾥的::表⽰引⽤,因为如果只是按照默认的或者参数只有⼀个的情况下idea会提⽰你进⾏优化,⽤::引⽤来进⾏替换就⾏了。
参考博⽂:
(1)(⾮常详细,值得仔细阅读)
(2)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论