《java8 in action》读书笔记(1)

行为参数化

官方解释:让方法接受多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。

代码解释:

class Apple{
    private String colors;
    private int weigth;

    public String getColors() {
        return colors;
    }

    public void setColors(String colors) {
        this.colors = colors;
    }

    public int getWeigth() {
        return weigth;
    }

    public void setWeigth(int weigth) {
        this.weigth = weigth;
    }
}
interface ApplePredicate{
    boolean test(Apple apple);
}
public class AppleRedAndHeavyPredicate implements ApplePredicate{
    @Override
    public boolean test(Apple apple) {
        return "red".equals(apple.getColors())&& apple.getWeigth()>150;
    }
}

图片解释:

image

行为参数化的好处:可以轻松的应对不断变化的需求,这种模式可以把一个行为一段代码封装起来,并通过传递和使用创建行为将方法行为参数化。

lambda表达式

1.初识lambda

可以把lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表,函数主题,返回类型,可能还有一个可以抛出的异常列表。

  • 匿名—说匿名,是因为它不像 普通的方法那样有一个明确的名称:写得少而想的多。
  • 函数—说函数,是因为lambda函数不像方法那样属于某个特定的类。但和方法一样,lambda有参数列表,函数主体,返回类型,还可能有可以抛出的异常列表。
  • 传递—lambda表达式可以作为参数传递给方法或存储在变量中。
  • 简洁—无需像匿名函数那样写很多模板代码。

这里写图片描述
箭头左边为lambda参数,箭头右边为lambda主体。

基本语法:(parameters)->expression或者(parameters)->{statements;}

先前:

 Comparator<Apple> byWeight=new Comparator<Apple>() {
       @Override
       public int compare(Apple o1, Apple o2) {
           return o1.getWeigth().compareTo(o2.getWeigth());
       }
   };

之后(用了lambda表达式):

Comparator<Apple> c = 
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

使用案例:

使用案例lambda示例对应的函数式接口
布尔表达式(List<String> list)->list.isEmpty();Predicate<List<String>>
创建对象()->new Apple(10)Supplier<Apple>
消费一个对象(Apple a)->{System.out.println(a.getWeitht());</br>}Consumer<Apple>
从一个对象中选择/抽取(String s)->s.length();Function<String,Integer>或ToIntFunction<String>
组合两个值(int a,int b)->a*bIntBinaryOperator
比较两个对象(Apple a1,Apple a2)->a1.getWeight().compareTo(a2.getWeight());Comparator<Apple>

2.在哪里以及如何使用lambda

①:函数式接口:只定义一个抽象方法的接口。注意:在java8中接口现在还可以拥有默认方法,哪怕有很多默认方法,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。
②:函数描述符:函数式接口的抽象方法的签名基本上就是lambda表达式的签名,我们将这种签名方法叫做函数描述符。例如可以用()->void代表了参数列表为空,且返回void的函数。
总之:lambda可以在函数式接口上使用lambda表达式。

3.环绕执行模式(使用lambda的一般步骤)

①:行为参数化(抽象行为)
②:使用函数式接口来传递行为
③:执行一个行为
④:传递lambda

    /**
     * 1.抽象行为
     * @return
     * @throws IOException
     */
    public static String processFile()throws IOException{
        try(BufferedReader bufferedReader=new BufferedReader(new FileReader("data.txt"))){
            return bufferedReader.readLine();
        }
    }

    /**
     * 2,使用函数式接口来传递行为
     */
    public interface  BufferedReaderProcessor{
        String process(BufferedReader bufferedReader)throws IOException;
    }

    /**
     * 3.执行一个行为
     * @param p
     * @return
     * @throws IOException
     */
    public static String processFile(BufferedReaderProcessor p)throws IOException{
        try(BufferedReader br=new BufferedReader(new FileReader("data.txt"))){
            return p.process(br);
        }
    }
    /**
     * 4.传递lambda
     */
    String oneLine=processFile((BufferedReader bufferedReader)->bufferedReader.readLine());
    String twoLine=processFile((BufferedReader bufferedReader)->bufferedReader.readLine()+bufferedReader.readLine());

4.函数式接口

java库中的函数式接口
函数式接口函数描述符原始类型特化
Predicate<T>T->booleanIntPredicate,LongPredicate,DoublePredicate
Consumer<T>T->voidIntConsumer,LongConsumer,DoubleConsumer
Function<T,R>T->RToLongFunction<T> ToDoubleFunction<T> </br>ToIntFunction<R> DoubleFunction<R> LongToIntFunction LongToDoubleFunction LongFunction<R> IntToLongFunction IntToDoubleFunction IntFunction<R>
Supplier<T>()->TBooleanSupplier IntSupplier LongSupplier DoubleSupplier
UnaryOperator<T>T->TLongUnaryOperator IntUnaryOperator DoubleUnaryOperator
BinaryOperator<T>(T,T)->TLongBinaryOperator IntBinaryOperator DoubleBinaryOperator
BiPredicate<L,R>(L,R)->boolean
BiConsumer<T,U><T,U>->voidObjDoubleConsumer<T> ObjLongConsumer<T> ObjIntConsumer<T>
BiFunction<T,U,R>(T,U)->RToDoubleBiFunction<T,U> ToLongBiFunction<T,U> ToIntBiFunction<T,U>

5.方法引用

①:初识方法引用
官方解释:仅仅调用特定方法的lambda的一种快捷写法。

基本思想:如果一个lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述它。

实质:根据已有的方法实现来创建lambda表达式。

用法:目标引用放在分隔符“:”前,方法名称放在分隔符后。

lambda 及其等效方法引用的例子

lambda等效的方法引用
(Apple a)->a.getWeight()Apple::getWeight
()->Thread.currentThread().dumpStack()Thread.currentThread()::dumpStack
(str,i)->str.substring(i)String::substring
(String s)->System.out.println(s)System.out::println

②:如何构建方法引用

方法引用主要有三类:
1. 指向静态方法的方法引用:(Integer的parseInt方法,可以用方法引用写作Integer::parseInt)
2. 指向任意类型实例方法的方法引用:(例如String的length方法,可以写作:String::Length)
3. 指向现有对象实例方法的方法引用(假设你有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensiveTransaction::getValue)

③:构造函数引用
对于一个现有构造函数,你可以利用它的名字和关键字new来创建它的一个引用:ClassName::new。它的功能与指向静态方法的引用类似。例如Apple类的一个无参构造函数的方法引用可以写为:Apple::new ,如果Apple的构造函数方法签名为(Integer weight),那么它就适合Function接口的签名,你就可以这样写:
Function

6.lambda复合

①:比较器复合
背景:或许你见过java8中可以使用静态方法Comparator.comparing,根据提取用于比较的键值的Function来返回一个Comparator。

Comparator<Apple> c=Comparator.comparing(Apple::getWeight)
  1. 逆序: 上述代码用于正序排序,如果是逆序排序应该怎么办?其实不用去创建一个Comparator实例对象,接口有一个默认的方法reverse可以使得给定的比较器进行逆序排序,因此上述代码中哪个比较器,只需要修改一下就可以使用
inventory.sort(comparing(Apple::getWeight).reversed());
  1. 比较器链: 有时可能会遇到这样的一种情况,两个对象的比较参数一样大小,比如两个苹果的重量一样重怎么办?在这种情况下你可以会出现第二比较参数,例如根据是否原产国排序,这时,你可以利用比较器链优雅的来解决这个问题了。
inventory.sort(comparing(Apple::getWeight)).reversed().thenComparing(Apple::getCountry);

②:谓词复合
谓词接口包括三个方法:negate,and,和or。可以通过Predicate来创建更多更复杂的谓词,比如:可以使用negate方法来返回一个predicate的非,比如苹果不是红的:
Predicate notRedApple=redApple.negate();

③:函数复合
函数复合是指可以把Function接口所代表的lambda表达式复合起来,Function接口为此配了‘andThen’和‘compose’两个默认方法,它们都会返回Function的一个实例。

  • andThen:

    andThen方法会返回一个函数,它先对输入应用一个给定函数,再对输入应用另外一个函数,比如假设有一个函数f给数字加1(x->x+1)另一个函数g给函数乘2,你可以将它们组合成一个函数h,先给数字加1,再给结果乘2:

    Function<Integer,Integer> f=x->x+1;
    Function<Integer,Integer> g=x->x+2;
    Function<Integer,Integer> h=f.andThen(g);
    int result=h.apply(1);//结果为4
  • compose:
    先把给定的函数用作compose的参数里面的那个函数,然后再把函数本身用于结果。比如在上一个例子里用compose的话,它将意味着f(g(x)),而andThen则意味着g(f(x)):
    Function<Integer,Integer> f=x->x+1;

    Function<Integer,Integer> g=x->x=2;

    Function<Integer,Integer> h=f.compose(g);

    int result=h.apply(1);//结果为3
相关推荐
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页