Java8 Lambda表达式用法

1.Lambda表达式

Lambda是一个匿名函数,可以理解为是一段可以传递的代码

基础语法

Java8中引入的一个新的操作符“->”该操作符称为箭头操作符或者Lambda操作符。

左侧:Lambda 表达式的参数列表

右侧:Lambda 表达式中所需执行的功能,即Lambda体

语法格式一:无参数,无返回值

() -> System.out.println("Hello Lambda!");

语法格式二:有一个参数,且无返回值

(x) -> System.out.println(x);

语法格式三:只有一个参数,可以省略小括号

x -> System.out.println(x);

语法格式四:有两个以上参数,有返回值,且Lambda体中有多条语句

Comparator<Integer> com = (x,y) -> {
    System.out.println("函数式接口");
    return Integer.compare(x,y);
};

语法格式五:Lambda体重只有一条语句,return和大括号都可以省略不写

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”

(Integer x,Integer y) Integer.compare(x,y);//参数类型可省略

2.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 test(T t);

1.Comsumer : 消费型接口,无返回值
void accept(T t);

public void happy(double money, Consumer<Double> com){
    com.accept(money);
}
@Test
public void test(){
    happy(1000,(m) -> System.out.println("去KTV消费了"+m+"元"));
}

2.Supplier : 供给型接口,有返回值,用于获取
T get();

@Test
public void test1(){
    List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
    for (Integer integer : numList) {
        System.out.println(integer);
    }
}

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;
}

3.Function<T,R> : 函数型接口,对传入对象进行操作,返回一个对象
R apply(T t);

 @Test
 public void test2(){
    String str = strHandler("  今年是2020年,我23岁了  ",(s)-> String::trim);
     System.out.println(str);
 }
 public String strHandler(String str, Function<String,String> fun){
    return fun.apply(str);
 }

4.Predicate : 断言型接口,用于判断
boolean test(T t);

@Test
public void test3(){
    List<String> list = Arrays.asList("hello","java","c#","php","c1","c2");
    List<String> stringList = filterStr(list, (s -> s.length() == 2));
    for (String s : stringList) {
        System.out.println(s);
    }
}
public List<String> filterStr(List<String> list, Predicate<String> pre){
    List<String> strList = new ArrayList<>();

    for (String s : list) {
        if (pre.test(s)){
            strList.add(s);
        }
    }
    return strList;
}

其他接口:

函数式接口参数类型返回类型用途
BiFunction<T,U,R>T,UR对类型为T,U参数应用操作,返回R类型的结果。包含方法:R apply(T t,U u);
UnaryOperator Function子接口TT对类型为T的对象进行一元运算,并返回T类型的结果,包含方法:T apply(T t,U u);
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、ToDoubleFunctionTint、long、double分别计算int、long、double值的函数
ToIntFunction、ToLongFunction、ToDoubleFunctionint、long、doubleR参数分别为int、long、double类型的函数

1.方法引用 :

若Lambda体中的内容有方法已经实现,可以使用“方法引用”

主要有三种语法格式

1.对象 ::实例方法名

@Test
public void test4(){
    Employee employee = new Employee("张三",15,5000);
    //原来写法
    Supplier<String> supplier = ()-> employee.getName();
    //对象 ::实例方法名
    Supplier<String> supplier1 = employee::getName;
    System.out.println(supplier1.get());
}

2.类::静态方法名

@Test
public void test5(){
    //原来写法
    Comparator<Integer> comparator = (x,y) ->Integer.compare(x,y);
    //类::静态方法
    Comparator<Integer> comparator1 = Integer::compare;

    System.out.println(comparator.compare(1,2)+","+comparator1.compare(1,2));
}

3.类::实例方法名

@Test
public void test6(){
    //原来写法
    BiPredicate<String,String> bp = (x,y) -> x.equals(y);
    //类::实例方法名
    BiPredicate<String,String> bp1 = String::equals;
    System.out.println(bp.test("a","b")+","+bp1.test("a","b"));
}

注意事项

1.Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值保持一致!

2.Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName ::method;

2.构造器引用

格式:ClassName ::new

@Test
public void test7(){
    //原来写法
    Supplier<Employee> sup = ()-> new Employee();
    //构造器引用
    Supplier<Employee> sup1 = Employee::new;
}

注意事项

当我们使用这方式创建对象时,函数的参数决定了要调用的构造器方法,如果函数中接收的两个参数,则使用对象::new的方式创建对象时将会调用两个参数的构造方法。

需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致!

3.数组引用:

type ::new;

@Test
public void test8(){
    //原来写法
    Function<Integer,String[]> fun = (x)-> new String[x];
    String[] apply = fun.apply(10);
    System.out.println(apply.length);
    //数组引用
    Function<Integer,String[]> fun2 =  String[]::new;
    String[] apply1 = fun2.apply(10);
    System.out.println(apply1.length);
}

2.Stream

1.什么是流(Stream)?

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,集合讲的是数据,流讲的是计算!

注意事项

1.Stream自己不会存储元素。

2.Stream不会改变源对象,相反会返回一个持有结果的新的Stream。

3.Stream操作时延迟执行的,会等到需要结果的时候才执行。

2.Stream的三个操作步骤:

1.创建Stream
1.通过Collection系列集合提供的stream()或parallelStream()
@Test
public void test(){
    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();
}
2.通过Arrays中的静态方法stream()获取数组流
@Test
public void test1(){
    String[] strings = new String[10];
    Stream<String> stream = Arrays.stream(strings);
}
3.通过Stream类中的静态方法of()
@Test
public void test2(){
    String[] strings = new String[10];
    Stream<String> strings1 = Stream.of(strings);
}
4.创建无限流
通过迭代的方式
@Test
public void test3(){
    Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
    iterate.forEach(System.out::println);
}
生成的方式
@Test
public void test4(){
    Stream.generate(Math::random)
        .forEach(System.out::println);
}
2.中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线终止操作,否则不会执行任何操作,称为“惰性求职”

筛选与切片:

**filter:**接收Lambda,从流中排除某些元素

limit(n):截断流,使其元素不超过给定的数量

skip(n):跳过元素,返回一个扔掉了n个元素的流,若流中不足n个,则返回一个空流,与limit互补

**distinct:**通过流所生成的元素的hashCode()和equals()去除重复元素

方法描述
filter(Predicate p)接收Lambda,从流中排除某些元素
distinct()筛选,通过流所生成元素的hashCode() 和equals()去除重复元素
limit(Long maxSize)截取流,使元素不超过给定数量
skip(Long n)跳过元素,返回一个扔掉了N个元素的流,若流中元素不足N个,则返回一个空流,与limit(n) 互补
@Test
public void test5(){
    List<Employee> employees = Arrays.asList(
        new Employee("张三",18,3500),
        new Employee("王五",28,4500),
        new Employee("赵六",38,5500),
        new Employee("赵柒",38,5500),
        new Employee("赵柒",38,5500)
    );
    employees.stream()
        .filter((e)-> e.getAge()>30)
        .skip(1)
        .distinct()
        .forEach(System.out::println);
}
映射:
map:接收Lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用
到每个元素上,并将其映射成一个新的元素
@Test
public void test6(){
    List<Employee> employees = Arrays.asList(
        new Employee("张三",18,3500),
        new Employee("王五",28,4500),
        new Employee("赵六",38,5500),
        new Employee("赵柒",38,5500),
        new Employee("赵柒",38,5500)
    );
    employees.stream()
        .filter((e)-> e.getAge()>30)
        .map((x)-> "Employee:"+x.getName())
        .forEach(System.out::println);
}
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连成一个流
public static Stream<Character> filterCharacter(String s){
    List<Character> list = new ArrayList<>();
    for (Character character : s.toCharArray()) {
        list.add(character);
    }
    return list.stream();
}
@Test
public void test8(){
    List<String> list = Arrays.asList("aa","bb","cc");
    //map只是一维 1对1 的映射
    Stream<Stream<Character>> streamStream = list.stream().map(StreamDemo::filterCharacter);
    streamStream.forEach(System.out::print);
    //flatmap可以将一个2维的集合映射成一个一维
    Stream<Character> sm = list.stream().flatMap(StreamDemo::filterCharacter);
    sm.forEach(System.out::println);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eDJUqBQ2-1663512486172)(Typora图片/image-20200717142240015.png)]

排序:
sorted():自然排序(Comparable)
@Test
public void test9(){
    List<String> list = Arrays.asList("ccc","bbb","ddd","aaa");
    list.stream().sorted().forEach(System.out::println);
}
sorted(Comparator com):定制排序(Comparator)
@Test
public void test10(){
    List<Employee> employees = Arrays.asList(
        new Employee("张三",18,3500),
        new Employee("王五",28,4500),
        new Employee("赵六",38,5500),
        new Employee("赵柒",38,5500)
    );
    employees.stream().sorted((e1,e2)->{
        if (e1.getAge() != e2.getAge()){
            return Integer.compare(e1.getAge(), e2.getAge());
        }else {
            return e1.getName().compareTo(e2.getName());
        }
    }).forEach(System.out::println);
3.终止操作
方法描述
count()返回流中元素总数
max(Comparator c)返回流中的最大值
min(Comparator c)返回流中的最小值
forEach(Consumer c)内部迭代(使用Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代——帮用户把迭代做了)
1.查找与匹配
allMatch:检查是否匹配所有元素
List<Employee> employees = Arrays.asList(
    new Employee("张三",18,3500),
    new Employee("王五",28,4500),
    new Employee("赵六",38,5500),
    new Employee("赵柒",38,5500),
    new Employee("赵柒",38,5500)
);
@Test
public void test(){
    boolean b = employees.stream().allMatch((e) -> e.getAge() < 88);
    System.out.println(b);
}
//结果为true
anyMatch:检查是否至少匹配一个元素
List<Employee> employees = Arrays.asList(
    new Employee("张三",18,3500),
    new Employee("王五",28,4500),
    new Employee("赵六",38,5500),
    new Employee("赵柒",38,5500),
    new Employee("赵柒",38,5500)
);
@Test
public void test(){
    boolean b = employees.stream().anyMatch((e) -> e.getAge() == 18);
    System.out.println(b);
}
//结果为true
noneMatch:检查是否没有匹配所有元素
@Test
public void test(){
    boolean b = employees.stream().noneMatch((e) -> e.getAge() == 18);
    System.out.println(b);
}
//结果为false
findFirst:返回第一个元素
@Test
public void test(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    Optional<Integer> first = list.stream().sorted().findFirst();
    System.out.println(first.get());
}
//结果为1
findAny:返回当前流中的任意元素
@Test
public void test(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    Optional<Integer> first = list.stream().findAny();
    System.out.println(first.get());
}
count:返回流中所有元素的总个数
@Test
public void test(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    long count = list.stream().count();
    System.out.println(count);
}
//结果为5
max:返回流中最大值
@Test
public void test(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    Optional<Integer> max = list.stream().max(Integer::compare);
    System.out.println(max.get());
}
//结果为45
min:返回流中最小值
@Test
public void test(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    Optional<Integer> min = list.stream().min(Integer::compare);
    System.out.println(min.get());
}
//结果为1
2.归约
方法描述
reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回Optional
reduce(T identity,BinaryOperator) /reduce(BinaryOperator):将流中元素反复结合起来,得到一个值
@Test
public void test2(){
    List<Integer> list = Arrays.asList(45,1,2,22,5);
    Integer sum = list.stream().reduce(0, (x, y) -> x + y);
    System.out.println(sum);
===============================================================================
    Optional<Integer> reduce = list.stream().reduce(Integer::sum);
    System.out.println(reduce.get());
}
//结果为75
3.收集

collect:将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

方法描述
collect(Collector c)将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test(){
    //把所有员工的姓名收集成一个List集合
    List<String> collect = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toList());
    collect.forEach(System.out::println);

    //把所有的员工姓名收集成一个set集合
    Set<String> collect1 = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toSet());
    collect1.forEach(System.out::println);

    //把所有员工姓名收集成一个HshSet
    HashSet<String> collect2 = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(HashSet::new));
    collect2.forEach(System.out::println);
}
@Test
public void test1(){
    //收集总数
    Long collect = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.counting());
    System.out.println(collect);
    //平均值
    Double collect1 = employees.stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println(collect1);

    //最大值
    Optional<Employee> max = employees
        .stream()
        .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
    System.out.println(max);

    //最小值
    Optional<Double> min = employees.stream()
        .map(Employee::getSalary)
        .collect(Collectors.minBy(Double::compare));
    //总和
    Double sum  = employees
        .stream()
        .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println(sum);
    
    //一次获取多个值的方法
    DoubleSummaryStatistics collect = employees.stream()
        .collect(Collectors.summarizingDouble(Employee::getSalary));
    System.out.println(collect.getMax());
    System.out.println(collect.getAverage());
    System.out.println(collect.getMax());
}
@Test
public void test(){
    //分组
    Map<String, List<Employee>> collect = employees.stream()
        .collect(Collectors.groupingBy(Employee::getSex));
    System.out.println(collect);


    //多级分组
    Map<String, Map<Integer, List<Employee>>> collect1 = employees.stream()
        .collect(Collectors
                 .groupingBy(Employee::getSex, Collectors.groupingBy(Employee::getAge)));
    System.out.println(collect1);
}
//分区
Map<Boolean, List<Employee>> collect = employees.stream()
    .collect(Collectors.partitioningBy((x) -> x.getAge() > 30));
System.out.println(collect);
@Test
public void test1(){
    //把所有的员工姓名收集成一个字符串
    String collect = employees.stream()
        .map(Employee::getName)
        .collect(Collectors.joining(","));
    System.out.println(collect);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值