java8 第三章
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java8 第三章相关的知识,希望对你有一定的参考价值。
Lambda
Structure:
Lambda包含三部分: 1.参数列表 2.箭头 3.Lambda主体(多行时需加{},没有{}时不能用return,单行表达式不需要加{})
Where Use?
只能使用在需要函数式接口的时候才能传递Lambda
函数式接口上使用(functional interface)-->函数式接口简单来说:只能包含一个抽象方法的接口,比如Comparator,Runnable;是Lambda的目标类型
// 注 : 方法签名 = 方法名称+一个参数列表(方法的参数的顺序和类型)组成.
函数式接口的抽象方法的签名(基本上也可说是Lambda表达式的签名) 可以理解成==>函数描述符
函数式接口
--定义:首先是一个接口,其次接口里面只有一个抽象方法,又称SAM(Single Abstract Method interface)接口.
函数式接口可以包含默认方法,他只有一个默认实现.(不是抽象方法)
函数式接口可以包含静态方法,是一个已经实现了的方法.(不是抽象方法)
--函数式接口存在的意义 : 函数式接口代表的一种契约, 一种对某个特定函数类型的契约。 在它出现的地方,实际期望一个符合契约要求的函数。
Lambda表达式不能脱离上下文而存在,它必须要有一个明确的目标类型,而这个目标类型就是某个函数式接口.
Lambda的目标类型一定要是函数式接口.
Java新引入注解@FunctionInterface=>加上就会对接口进行编译级错误检查,不是函数式接口编译不会通过,只有这一个作用.
为了避免装箱操作,对Predicate<T>,Function<T,R>等通用函数式接口的原始类型特化:IntPredicate,IntToLongFuction等.
-- 注 : 装箱 ==> 装箱后的值本质上就是把原始类型包裹起来,并保存在堆里。因此,装箱后的值需要更多的内存,并需要额外的内存搜索来获取被包
裹的原始值.
Java8之前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
新定义的函数式接口
--使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
Consumer -- 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
Function -- 传入一个参数,返回一个结果,方法为R apply(T t)
Supplier -- 无参数传入,返回一个结果,方法为T get()
UnaryOperator -- 一元操作符, 继承Function,传入参数的类型和返回类型相同。
BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
函数式接口使用例子
public class PredicateUsed {
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<T> results =Lists.newArrayList();
for (T s : list){
if (p.test(s)){
results.add(s);
}
}
return results;
}
?
public static void main(String[] args) {
List listOfStrings = Lists.newArrayList();
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List notEmpty = filter(listOfStrings,nonEmptyStringPredicate);
}
}
使用局部变量(限制)
Lambda可以没有限制的捕获实例变量和静态变量,但局部变量必须显示的声明为final或者事实上是final
闭包==>
你可能已经听说过闭包(closure,不要和Clojure编程语言混淆)这个词,你可能会想 Lambda是否满足闭包的定义。用科学
的说法来说,闭包就是一个函数的实例,且它可以无限 制地访问那个函数的非本地变量。例如,闭包可以作为参数传递给
另一个函数。它也可以访 问和修改其作用域之外的变量。现在,Java 8的Lambda和匿名类可以做类似于闭包的事情: 它们
可以作为参数传递给方法,并且可以访问其作用域之外的变量。但有一个限制:它们不 能修改定义Lambda的方法的局部变量
的内容。这些变量必须是隐式最终的。可以认为Lambda 是对值封闭,而不是对变量封闭。如前所述,这种限制存在的原因
在于局部变量保存在栈上, 并且隐式表示它们仅限于其所在线程。如果允许捕获可改变的局部变量,就会引发造成线程 不
安全的新的可能性,而这是我们不想看到的(实例变量可以,因为它们保存在堆中,而堆是在线程之间共享的)。
方法的引用
1.静态方法的引用==>Integer::parseInt
2.任意类型实例方法的引用==>String::length
3.现有对象实例方法的方法引用(假设有局部变量private Name name,支持的实例方法getName)==>name::getName
构造函数的引用
现有构造函数==>当前构造函数名称+关键字new来创建他的一个引用:ClassName :: new(跟静态方法的引用相似)
无参的构造函数 | Supplier<Apple> c1 = Apple :: new; Apple a1 = c1 .get( ); |
构造函数引用指向默认的Apple()构造函数 调用Supplier的get方法将产生一个新的Apple |
构造函数签名为 Apple(Integer weight) |
Function<Integer> c2 = Apple :: new; Apple a2 =c2.apply(100); |
指向Apple(Integer weigiht)的构造函数引用 调用该Function函数的Apply方法,并要求给出重量,产生新的Apple |
构造函数签名是Apple(Integer weight) |
List<Integer> weights = Arrays.asList(7, 3, 4, 10);
List<Apple> apples = map(weights, Apple::new);
public static List<Apple> map(List<Integer> list,
Fuction<Integer,Apple> f){
List<Apple> result = new ArrayList<>();
for (Integer e: list ) {
result.add(f.apply(e3));
}
return result;
}
一个由Integer构成的List中的每个元素都通过我们前面定义的类似的 map方法传递给了Apple的构造函数,得到了一个具有不同重量苹果的List; |
//inventory==>List
//void sort(Comparator<? super E> c)
?
//第一种解决方案(传递代码)
public class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator());
?
//第二种解决方案(使用匿名类)
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
?
//第三种解决方案(使用Lambda)
inventory.sort((Apple a1, Apple a2)-> a1.getWeight().compareTo(a2.getWeight()));
//自动提示重写===>
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
?
//第四种解决方案(引入Comparator的comparing的静态辅助方法, 接收一个Function来提取Comparable键值,并生成一个Comparator对象)
import static java.util.Comparator.comparing;
inventory.sort(comparing((a) -> a.getWeight()));
//自动提示重写===>
import static java.util.Comparator.comparing;
inventory.sort(comparing(Apple::getWeight));//最终方案,强烈反差!
复合Lambda表达式:
--比较器复合
list.sort(Comparator.comparing(Apple::getWeight));
list.sort(Comparator.comparing(Apple::getWeight).reversed());//逆序
list.sort(Comparator.comparing(Apple::getWeight).thenComparing(Apple::getCountry));//比较器链,重量相同,按国家排序
?
--谓词复合
//就是非,返回苹果不是红的
Predicate<Apple> notRedApple = redApple.negate();
//组合两个Lambda用and==>苹果既是红色又比较重
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);
//组合谓词==>要么是重150克以上的红苹果,要么是绿苹果
Predicate<Apple> redAndHeavyAppleOrGreen =redApple.and(a -> a.getWeight() >150)
.or(a -> "green".equals(a.getColor()));
--函数复合
//通过andThen和compose将Function接口所代表的Lambda表达式复合起来
?
例子:
public class LambdaMethod {
public static String addHeader(String text) {
return "Welcome" + " "+text+" ";
}
public static String addFooter(String text) {
return text + "here";
}
public static String checkSpelling(String text) {
return text.replace("lamba", "lambda");
}
public static void main(String[] args) {
Function<String,String> addHeader = LambdaMethod::addHeader;
Function<String,String> transformationPipeline = addHeader.andThen(LambdaMethod::checkSpelling)
.andThen(LambdaMethod::addFooter);
String apply = transformationPipeline.apply("lamba");
System.out.println(apply);
}
}
输出:
Welcome lambda here
以上是关于java8 第三章的主要内容,如果未能解决你的问题,请参考以下文章
java8 .stream().sorted().filter().map().collect()用法
Java8 Stream针对List先分组再求和最大值最小值平均值等