关于Lambda表达式与Stream(抄袭)

说明

在网上看到一个人写的总结,挺好,因此全量摘抄下来,以便理解和查阅

Lambda 表达式

Lambda 语法


Lambda 表达式在Java中引入了一个新的语法元素和操作符 -> ,它将Lambda分成两个部分:
左侧 :指定Lambda表达式需要的所有参数
右侧 :指定了Lambda体,即Lambda表达式要执行的功能

语法格式一: 无参,无返回值,Lambda体只需要一条语句
package com;

public class Test1 {

    public static void main(String[] args) {

        // 不用lambda
        /*Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("I'm run");
            }
        };*/

        Runnable runnable = () -> System.out.println("I'm run");
        runnable.run();
    }
}
语法格式二: Lambda有一个参数,且无返回值
package com;

import java.util.function.Consumer;

public class Test2 {
    public static void main(String[] args) {
        //不用lambda
        /*Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };*/

        Consumer<String> consumer = (s)-> System.out.println(s);
        
        consumer.accept("hi,coulson");
    }
}
语法格式三: Lambda有一个参数,参数的小括号可以省略
package com;

import java.util.function.Consumer;

public class Test3 {

    public static void main(String[] args) {

        Consumer<String> com = x-> System.out.println(x);
        com.accept("hi");
    }
}
语法格式四:Lambda需要两个参数,并且有返回值,多条语句时必须加上{}
package com;

import java.util.function.BinaryOperator;

public class Test4 {

    public static void main(String[] args) {

        BinaryOperator<Integer> bi = (x,y) ->{
            System.out.println("加法");
            return x+y;
        };
        Integer apply = bi.apply(6,4);
        System.out.println(apply);
    }
}
语法格式五:当lambda体只有一条语句时,return 与与大括号可以省略
package com;

import java.util.function.BinaryOperator;

public class Test5 {

    public static void main(String[] args) {
        BinaryOperator<Integer> bi = (x,y) -> x+y;
        int result = bi.apply(34,43);
        System.out.println(result);

    }
}
语法格式六:Lambda的参数列表的类型可以不写,因为jvm编译器可以通过上下文进行"类型推断"
package com;

import java.util.function.BinaryOperator;

public class Test6 {

    public static void main(String[] args) {
        BinaryOperator<Integer> bi = (x,y) -> x+y;
        int result = bi.apply(51,52);
        System.out.println(result);

    }
}

类型推断

上述Lambda表达式中的参数类型都是由编译器推断得出的。Lambda表达式中无需指定类型,程序依然可以编译,这是因为javac根据程序的上下文,在后台推断出了参数的类型。Lambda表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的"类型推断"

函数式接口

只包含一个抽象方法的接口,成为函数式接口。
可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式跑出一个受检异常,那么该异常需要在目标解耦的抽象方法上进行声明)。
我们可以在任意函数式接口上使用@FunctionalInterface注解,这样可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

package com;

@FunctionalInterface
public interface TestFunction {
    
    String getValue(String str);
}
package com;

@FunctionalInterface
public interface TestFunction2<T,R> {
    
    R getValue(T t1, T t2);
}

作为参数传递Lambda表达式

package com;

public class Test6 {

    /**
     * 数据处理方法
     * @param str
     * @param function
     * @return
     */
    public String strHandler(String str, TestFunction function) {

        return function.getValue(str);
    }

    public static void main(String[] args) {
        
        // 自定义函数式接口,并使用Lambda表达式
        String result = new Test6().strHandler("abcd", x->x.toUpperCase());
        System.out.println(result);
    }
}
package com;

public class Test7 {

    public void op(Integer num1, Integer num2, TestFunction2<Integer, Integer> tf) {
        System.out.println(tf.getValue(num1, num2));
    }

    public void test3() {
        op(20,30,(x,y) -> x+y);
    }

    public static void main(String[] args) {
        new Test7().test3();
    }
}

注意:
作为参数传递Lambda表达式:为了将Lambda表达式作为参数传递,接受Lambda表达式的参数类型必须是与该Lambda表达式兼容的函数式接口的类型

Java8内置四大核心函数式接口

函数式接口参数类型返回类型用途
Consumer消费类型接口Tvoid对类型为T的对象应用操作,包含方法void accept(T t)
Supplier 供给型接口T返回类型为T的对象,包含方法:T get();
Function<T,R>函数型接口TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法: R apply(T t);
Predicate断定型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值。包含方法boolean test(T t);
package com;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class TestConsumer {

    public void consumer(Map<String, Double> money, Consumer<Map<String,Double>> con){

        con.accept(money);
    }

    public static void main(String[] args) {
        Map<String,Double> map = new HashMap<>();
        map.put("money",100000d);
        new TestConsumer().consumer(map,x-> x.put("money",x.get("money") - 2000d));
        System.out.println(map);
    }
}

package com;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;

public class TestSupplier {

    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }

        return list;
    }

    public static void main(String[] args) {
        List<Integer> list = new TestSupplier().getNumList(3, () -> {
            Random random = new Random();
            int i = random.nextInt(100);
            System.out.println("产生整数:" + i);
            return i;
        });
        System.out.println(list);
    }
}

package com;

import java.util.UUID;
import java.util.function.Function;

public class TestFunction {

    public String converString(String str, Function<String,String> function) {
        return function.apply(str);
    }

    public static void main(String[] args) {
        String name = "hello";
        String coverString = new TestFunction().converString(name, (x)->x+ UUID.randomUUID().toString());
        System.out.println(coverString);
    }
}

package com;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class TestPredicate {

    public List<String> converList(List<String> list, Predicate<String> predicate) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            if (predicate.test(list.get(i))) {
                result.add(list.get(i));
            }
        }

        return result;
    }

    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("张飞","刘备","贾宝玉","赵云");
        List<String> result = new TestPredicate().converList(stringList,(x) ->x.length() > 2);
        System.out.println(result);
    }
}

其他接口

函数式接口参数类型返回类型用途
BiFunction<T,U,R>T,UR对类型为T,U参数应用操作,返回R类型的结果。包含方法为R apply(T t,U u);
UnaryOperator
(Function子接口)
TT对类型为T的对象进行意愿运算,并返回T类型的结果。包含方法为T apply(T t);
BinaryOperator
(BiFunction子接口)
T,TT对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1,T t2);
BiConsumer<T,U>T,Uvoid对类型为T,U参数应用操作。包含方法为void accept(T t,U u);
ToIntFunction
ToLongFunction
ToDoubleFunction
Tint
long
double
分别计算int,long,double,值的函数
IntFunction
LongFunction
DoubleFunction
int
long
double
R参数分别为int,long,double类型的函数
方法引用与构造器引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符"::"将方法名和对象或类的名字分割开来。

如以下三种主要使用情况

对象::实例方法
类::静态方法
类::实例方法

package com;

import org.junit.Test;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 一.方法引用:
 * 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
 * 方法引用:使用操作符"::"将方法名和对象或类的名字分隔开来。
 * <p>
 * 三种情况:对象::实例方法
 * 类::静态方法
 * 类::实例方法
 * <p>
 * 注意:
 * Lambda体中调用方法的参数列表或返回值类型,必须与函数式接口中抽象方法的函数列表或返回值类型保持一致
 * 当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时:ClassName::methodName(例如:test4)
 * <p>
 * 二.构造器引用
 * 格式:ClassName::new
 * 注意:构造器参数列表要与接口中抽象方法的参数列表一致
 * 三.数据引用
 * 格式:type[]::new
 */
public class TestMethodRef {

    /**
     * 对象::实例方法
     */
    @Test
    public void test1() {

        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("haha");

        Consumer<String> conRef = System.out::println;
        conRef.accept("hehe");
    }

    /**
     * 对象::实例方法
     */
    @Test
    public void test2() {
        Employee employee = new Employee("sky", 30);
        Supplier<String> supplier = () -> employee.getName();
        String str = supplier.get();
        System.out.println(str);

        Supplier<String> suRef = employee::getName;
        System.out.println(supplier.get());
    }

    /**
     * 类::静态方法
     */
    @Test
    public void test3() {
        Comparator<Integer> comparable = (x, y) -> Integer.compare(x, y);
        int result = comparable.compare(5, 6);
        System.out.println("result=" + result);
        Comparator<Integer> comRef = Integer::compare;
        comRef.compare(8, 9);
        System.out.println("result=" + result);
    }

    /**
     * 类::实例方法
     */
    @Test
    public void test4() {
        //当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时,才能使用
        BiPredicate<String, String> bi = (x, y) -> x.equals(y);
        boolean res = bi.test("test1", "test2");
        System.out.println("res=" + res);
        BiPredicate<String, String> biRef = String::equals;
        res = biRef.test("test1", "test2");
        System.out.println("res=" + res);

        Employee employee = new Employee("tom", 20);
        Function<Employee, String> function = (e) -> e.getName();
        String strRes = function.apply(employee);
        System.out.println("strRes=" + strRes);

        Function<Employee, String> funcRef = Employee::getName;
        strRes = function.apply(employee);
        System.out.println("strRes=" + strRes);
    }

    /**
     * 构造器引用
     */
    @Test
    public void test5() {
        Supplier<Employee> supplier = () -> new Employee();
        System.out.println(supplier.get());

        Supplier<Employee> supRef = Employee::new;
        System.out.println(supRef.get());

        Function<Integer, Employee> function1 = (x) -> new Employee(x);
        Function<Integer, Employee> funcRef1 = Employee::new;
        System.out.println(funcRef1.apply(30));

        Function<String, Employee> function2 = (x) -> new Employee(x);
        Function<String, Employee> funcRef2 = Employee::new;
        System.out.println(funcRef2.apply("Ronaldo"));
    }

    /**
     * 数组引用
     */
    @Test
    public void test6() {
        Function<Integer, String[]> function = (x) -> new String[x];
        String[] ss = function.apply(5);
        System.out.println(ss.length);

        Function<Integer, String[]> funRef = String[]::new;

        ss = funRef.apply(15);
        System.out.println(ss.length);
    }
}

接口中的默认方法与静态方法

Java 8 中允许接口中包含具有具体实现的方法,该方法称为"默认方法",默认方法使用default关键修饰。

package com;

public interface ITest1 {

    default String getName() {
        return "男人";
    }

    static void show() {
        System.out.println("this is the method of interface ");
    }
}

接口默认方法"类优先"原则

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时

package com;

public interface ITest2 {

    default String getName() {
        return "ITest2.getName";
    }
}
package com;

public interface ITest3 {

    default String getName() {
        return "ITest2.getName";
    }

    static void show() {
        System.out.println("接口中的静态方法");
    }
}
package com;

public class MyClass {

    public String getName() {
        return "MyClass.getName";
    }
}
package com;

public class SubClass extends MyClass implements ITest2,ITest3 {

    @Override
    public String getName() {
        return ITest3.super.getName();
    }

    public static void main(String[] args) {
        SubClass subClass = new SubClass();
        System.out.println(subClass.getName());
    }
}

接口中的静态方法
public interface ITest3 {

    default String getName() {
        return "ITest2.getName";
    }

    static void show() {
        System.out.println("接口中的静态方法");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值