Lambda表达式的使用

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性,可以使代码变的更加简洁紧凑。

函数式接口

所谓的函数式接口,就是一个接口里面只能有一个抽象方法。但不限于default、static和重载的方法,再jdk8中引入了@FunctionalInterface注解,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。

public class Lambda {
    public static void main(String[] args) {
        String str = "hello lambda";
        // 原始方式
        Lambda.printSomething(str, new Printer() {
            @Override
            public void printer(String str) {
                System.out.println(str);
            }
        });
        // lambad方式
        Lambda.printSomething(str,(String s) ->  {System.out.println(s);});
        // lambda简化
        Lambda.printSomething(str, s ->  System.out.println(s));
        // lambda引用
        Lambda.printSomething(str,System.out::println);
        // 两个参数
        MyMath myMath = (x,y) -> x+y;
        System.out.println(myMath.add(10, 20));
    }
   public static void  printSomething(String str,Printer printer){
        printer.printer(str);
    };
}
// 函数型接口
@FunctionalInterface
interface Printer{
    void printer(String str);
}
@FunctionalInterface
interface MyMath{
    int add(int x,int y);
}

简化表达式

  • 可选参数:参数可以不写类型,当只有一个参数的时候无需定义圆括号,但多个参数需要定义圆括号。

  • 可选大括号:如果主体包含了一个语句,就不需要使用大括号。

  • 可选返回值:如果主体只有一个表达式返回值则编译器会自动返回值,也就是说我们不用显示的返回,可以省略大括号和return

  (String s) -> {System.out.print(s); }可以简化为
  s -System.out.print(s)
  (int a, int b) -> { return a * b; }; 可以简化为
  (a, b) -> a - b;
  • lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

  • 不能在Lambda 表达式前当中不允许声明一个与局部变量同名的参数或者局部变量。

   public static int t1 =1;
      public static void main(String[] args) {
          int  t2 = 1;
          t2 = 2; //报错,相当于加了final
          t1 = 2; // 正确
          int x = 1; //报错,同名变量
          MyMath myMath1 = (x,y)->x+t1;
          MyMath myMath2 = (x,y)->x+t2;
  		int y = 1; //正确
      }

Stream API

  • Stream常见操作

    • filter§ 过滤元素
    • map ()映射处理元素(返回新list)
    • sort (comparator)排序元素
	list.stream().sorted((p11, p22) -> (p11.getAge() - p22.getAge()))
	list.stream().sorted(Comparator.comparing(Person::getAge))
  • foreach 遍历获取元素
	forEach相当于for循环,遍历每一个直接元素(对象引用)
	 Consumer<Person> p = i -> i.setAge(i.getAge()+3);
     list.stream().forEach(p);
  • toArray(Integer[] :: new) 结果转数组
  • count() 输出元素个数
  • summaryStatistics() 配合mapToInt,[count,sum,min,average,max]
  • sum,min,average,max 同上
  • max(comparator)、min(comparator) 求出元素最大最小值,返回Optional
  • limit(x) 取出前x个元素
  • skip(x) 取出跳过前x个元素
  • distinct() 去重元素[对象去重需要实现hashcode和equals按顺序比较,同HashSet]
  • anyMatch§ 查看是否包含一个元素符合条件,返回boolean
  • allMatch§ 查看是否所有元素都符合条件,返回boolean
     allMatch:有一个为false即为false,全为true即为true,
     anyMatch: 有一个为true即为true,全为false即为false
     noneMatch:  有一个为true即为false,全为false即为true,
     如果你for循环要跳出可以采用allMatch
       list.stream().allMatch(i->{
   	    System.out.println("do something");
   	    return i.equals('条件')
       }
  • noneMatch§ 查看是否所有元素都不符合条件,返回booleanp
  • findFirst() 获取集合的第一个元素,返回Optional,通过**get()**方法可以获取Optional的元素,无则抛出异常;**isPresent()**方法可以判断Optional中是否有值;**ifPresent(handle)**方法可以当存在值时对其进行操作,**orElse(new T())**如果没有元素存在则返回一个默认值
	of()传入值不可以为null,ofNullable可以
    使用get()可以获取值,但前提是值不能为null,否则抛异常
    你可以通过isPresent()判断值是否为空,null为false,否则trueifPresent(……)写你的逻辑,当前对象为参数,只有对象不为空的时候才会执行逻辑
    orElse() 如果Optional入的值为null,则返回参数值,否则返回传入的值
    orElseGet(Person::new) ;orElseGet(()->p);
    上述两种方式在对象为空时都会执行参数,但如果参数不为空,orElse也会执行参数,而orElseGet不会
    Person person = Optional.ofNullable(p1).orElseGet(()->get());
    Person person2 = Optional.ofNullable(p1).orElse(get());
    orElseThrow() 当对象为空时将会抛出异常,否则返回原参数对象
    Optional.of(get()).orElseThrow(()->new RuntimeException("666"));
    fPresentOrElse(Consumer,Runnable)。如果对象不为null,会执行 Consumer 的动作,否则运行 Runnable。
    Optional.ofNullable(p1).ifPresentOrElse(i->{
        System.out.println("a");
    },()->{
        System.out.println("b");
    });
    当filter条件为真时继续返回this,否则返回空对象
    Optional.ofNullable(p1).filter(i->i.getAge()>20).orElseThrow(()->new RuntimeException("小于20"));
    map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中
    flatMap() 也需要函数作为参数,并对值调用这个函数,自己返回Optional对象
    list.stream().findFirst()……
  • parallel() 并行操作,不建议对filter,map等有状态即依赖元素进行操作,可能会导致数据结果不正确,默认为**sequential()**串行

  • Collectors 常见操作

    • toList / toSet 转集合
    • toMap 转map(Key,Value,[ Key冲突],[Map类型])
	Collectors.toCollection(LinkedList::new)//可以指定返回List的类型
   Map<String, Person> collect = list.stream().collect(Collectors.toMap(Person::getName, Function.identity(),(v1,v2)->v2));
   //以name作为key,本身作为值( Function.identity()等价于i->i),如果key冲突,覆盖
  • joining(delimiter,prefix,suffix) 连接为字符串
  • groupingBy 分组,可以返回单个属性,也可以返回多个属性以对象的形式(重写equals)
List<String> MyList1 = Arrays.asList("kobe", "jams", "curry", "cyyt");
MyList1.stream()
    .filter(s -> s.startsWith("c")) //过滤
    .map(String::toUpperCase) //映射处理
    .sorted((o1, o2) -> o2.compareTo(o1)) // 排序 
    .collect(Collectors.toList()); //转list 
MyList1.stream().forEach( i -> System.out.println(i)); // 遍历
MyList1.stream().collect(Collectors.joining()); // 输出 kobejamscurrycyyt
MyList1.stream().collect(Collectors.joining(",")); // 输出 kobe,jams,curry,cyyt
MyList1.stream().collect(Collectors.joining(",","[","]")); // 输出 [kobe,jams,curry,cyyt]
MyList1.stream().limit(2).collect(Collectors.toList()); // 输出[kobe, jams]
MyList1.stream().skip(2).collect(Collectors.toList()); // 输出[curry, cyyt]
Arrays.asList(MyList1.stream().collect(Collectors.joining(",")).split(",")) 
//输出字符串后再转为list集合  
list.stream().map(Person::getName).collect(Collectors.joining(",")) // 集合以逗号分隔连接成字符串

Filter与谓词逻辑

Employee e1 = new Employee(1, 89, "M", "Jack", "Marry");
Employee e2 = new Employee(2, 24, "F", "Rose", "Tom");
Employee e3 = new Employee(3, 29, "M", "Davil", "Bob");
Employee e4 = new Employee(4, 35, "F", "Join", "Rern");
List<Employee> employees = Arrays.asList(e1, e2, e3, e4);
        employees.stream().filter(Employee.ageAndGenderF).forEach(e -> System.out.println(e));
        System.out.println("******或or********");
        employees.stream().filter(Employee.ageAndGenderM.or(Employee.ageAndGenderF)).forEach(e -> System.out.println(e));
        System.out.println("*******与and********");
        employees.stream().filter(Employee.ageAndGenderM.and(Employee.ageAndGenderF)).forEach(e -> System.out.println(e));
        System.out.println("*******非1<> 整体取反********");
        employees.stream().filter(Employee.ageAndGenderM.and(Employee.ageAndGenderF).negate()).forEach(e -> System.out.println(e));
        System.out.println("*******非2<> 局部取反********");
        employees.stream().filter(Employee.ageAndGenderM.and((Employee.ageAndGenderF).negate())).forEach(e -> System.out.println(e));

public class Employee {
    private Integer id;
    private Integer age;
    private String gender;
    private String firstName;
    private String lastName;
    //谓词逻辑
    public static Predicate<Employee> ageAndGenderF = e -> e.getAge() > 15 && e.getGender().equals("F");

    public static Predicate<Employee> ageAndGenderM = e -> e.getAge() > 15 && e.getGender().equals("M");
    public static Predicate<Employee> ageAndGenderFM = ageAndGenderM.or((ageAndGenderF).and(ageAndGenderM))
}        

Map

返回整数
List<String> strings = Arrays.asList("Moner", "JacK", "Tom");
int[] ints = strings.stream().mapToInt(String::length).toArray();[5,4,3]
如果返回只和传的参数是同一对象可以是用peek,注意该操作会修改原来的集合
 List<Employee> collect1 = employees.stream().map(i -> {
            i.setId(i.getId() + 1);
            return i;
        }).collect(Collectors.toList());
        List<Employee> collect = employees.stream().peek(i -> i.setId(i.getId() + 1)).collect(Collectors.toList());

排序

最后一个配合.thenComparing()可以实现多个条件的排序

 employees.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList()); //排序1
employees.stream().sorted(Comparator.comparing(Employee::getAge)).collect(Collectors.toList());//排序2
employees.stream().sorted(Comparator.comparing(Employee::getAge).reversed()[thenComparing(...)]).collect(Collectors.toList());//排序3倒序
list.stream().sorted(Comparator.comparing(Person::getAge).thenComparing(Comparator.comparing(Person::getName).reversed())).collect(Collectors.toList());
// 按年龄升序,如果一样按姓名降序

关于reversed的使用
  • 都是正序,无需
  • 都是倒序,最后加reversed
  • 先倒后正,先加reversed后不加
  • 先正后到,先加reversed后也加,代表第一个倒序,然后最后一个都是倒序,第一个就变成了正序

归并

  • 第一个参数为初始值,total为结果,i为当前元素
 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
 	// 可以不加初始值,不加默认是第一个元素,返回Optional
    int reduce1 = list.stream().reduce(10, (total, i) -> total + i);
    int reduce2 = list.stream().reduce(10, Integer::sum/max/min);
    int reduce3 = employees.stream().map/mapToInt(Employee::getAge).reduce(10, (total, i) -> total + i);// 集合操作,先转为int
    int reduce3 = employees.stream().mapToInt(Employee::getAge).sum()/max()/min()/average() // 使用mapToInt进行数值运算
	int reduce3 = employees.stream().reduce(10, (total, i) -> total + i.getAge(), Integer::sum);
// 下面两句等价
list.stream().map(Person::getAge).reduce(BigDecimal.ZERO, (sum, i) -> sum.add(i));
list.stream().map(Person::getAge).reduce(BigDecimal.ZERO, BigDecimal::add);
// 你还可以自定义逻辑
list.stream().map(Person::getAge).reduce(BigDecimal.ZERO,Client1::add);
public static BigDecimal add(BigDecimal o1,BigDecimal o2){
      // 代码
       return o1.add(o2);
 }

方法引用

  • 构造器引用 类名::new i -> new 构造方法(i)

  • 静态方法引用 类名::方法名 i -> 类名.staticMethod(i)

  • 实例方法引用 对象::方法名 i -> i.method()[需要为i类的无参方法]

分组

java分组将会调用分组条件的equals条件进行比较,相同即为一组

list.stream().collect(Collectors.groupingBy(Person::getSex));//按照性别分组
list.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.counting()));// 分组并得到每组的数量
list.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.maxBy(Comparator.comparing(Person::getAge))));// 取出每组年龄最大的
 list.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.summingInt(Person::getAge)))// 分组求和
 // 多字段分组
 list.stream().collect(Collectors.groupingBy(i -> Arrays.asList(i.getName(), i.getSex())));// 多字段分组
 list.stream().collect(Collectors.groupingBy(i -> i.getName() + i.getSex()));// 自定义分组条件

其他操作

  • 数组使用Stream
    • Stream.of(…value)
    • Arrays.stream(Array[])
    • Arrays.stream(Array[],start,end) // 带截取功能的转换,含头不含尾,同Arrays.copyOfRange(Array[],start,end)
Stream.of(1, 2, 3, 4).reduce(0, Integer::max); // 可变参数
Integer[] arr = {1,2,3,4};
Stream.of(1,2,3,4).collect(Collectors.toList()); // 数组转list等价于of(arr)
Arrays.stream(arr).collect(Collectors.toList()); // 效果同上
  • 数值流转换为流(int[]->Integer[])
    • Stream stream = intStream.boxed();
  • 使用Stream的静态方法:iterate()、generate()、range()
Integer[] ints = Stream.iterate(10, x -> x + 1).limit(10).toArray(Integer[]::new);
List<Double> lists = Stream.generate(Math::random).limit(10).collect(Collectors.toList());
IntStream.range(1,5).forEach(i->{……})// 创建一个1-5(含头不含尾)的数值流
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信息技术王凤龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值