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;
Lambda和方法引用实战

//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 第三章

java8 .stream().sorted().filter().map().collect()用法

Java8 Stream针对List先分组再求和最大值最小值平均值等

通过 Java 正则表达式提取 semver 版本字符串的片段

Java 8 新特性总结

[vscode]--HTML代码片段(基础版,reactvuejquery)