java基础之lambda表达式
1 什么是lambda表达式
lambda表达式是一个匿名函数,允许将一个函数作为另外一个函数的参数,将函数作为参数传递(可理解为一段传递的代码)。
2 为什么要用lambda表达式
lambda表达式可以写出更简洁更灵活的代码。先看看下面一段代码
public class TestLambda {//匿名内部类方式@Testpublic void test() {TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2);} });}//lambda方式@Testpublic void test1() {Comparator<Integer> com = (x,y)->Integer.compare(x, y);TreeSet<Integer> set = new TreeSet<>(com); }List<Person> list = Arrays.asList(new Person("小红", 18, 5000.0), new Person("小明", 21, 6000.0),new Person("小刚", 25, 7000.0));// 传统方式获取年龄大于20的人@Testpublic void test2() {for (Person person : list) {if(person.getAge()>20) {System.out.println(person);}}}// lambda方式获取年龄大于20的人@Testpublic void test3() {list.stream().filter((x)-> x.getAge()>20).forEach(System.out::println);}
}
3 lambda语法
java8中引入了操作符“->”,称为箭头操作符或lambda操作符,lambda用于替换匿名函数。
使用lambda表达式的前提:接口(函数式接口)中只能有一个抽象方法。
函数式接口:接口中只有一个抽象方法的接口,通过注解@Functioninterface 限定
lambda操作符将lambda表达式拆成两个部分:
(1)左侧是lambda表达式的参数列表(可以理解为抽象方法的参数)
(2)右侧是lambda表达式中需要执行的功能,即lambda体(可以理解为抽象方法的实现的功能)
3.1 格式一:无参数,无返回值
()->System.out.println("Hello Lambda!");
3.2 格式二:有一个参数,无返回值(如果只有一个参数可以省略(),如果只有一条语法可以省略{})
(x)->System.out.println(x);
3.3 格式三:如果只有一个参数,小括号可以省略不写
x -> System.out.println(x);
3.4 格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
3.5 格式五:如果 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
3.6 格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
(Integer x, Integer y) -> Integer.compare(x, y);
4 内置的四个核心函数式接口
4.1 消费型接口Consumer<T>
抽象方法:void accept(T t);
//消费型接口@Testpublic void test1() {// Consumer<Double> con = (x)-> System.out.print(x);// consumer(100, con);consumer(100,(x)-> System.out.print(x));}public void consumer(double money,Consumer<Double> con){con.accept(money);}
4.2 供给型接口Supplier<T>
抽象方法:T get();
//供给型接口@Testpublic void test2() {List<Integer> randomNum = getRandomNum(10,()->new Random().nextInt(100));System.out.println(randomNum);}/*** @Description 生成指定个数的随机数* @param count* @param su* @return int*/public List<Integer> getRandomNum(int count,Supplier<Integer> su) {List<Integer> list = new ArrayList<>();for(int i = 0;i<count;i++) {list.add(su.get());}return list;}
4.3 函数式接口Function<T,R>
抽象方法:R apply(T t);
//函数式型接口@Testpublic void test3() {List<String> list = toUpperList(new ArrayList<String>(Arrays.asList("abc","df","aa","cc")),(x)-> x.toUpperCase());System.out.println(list);}/*** @Description 将集合里面的字符串转大写* @param list* @param fun* @return List<String>*/public List<String> toUpperList(List<String> list,Function<String,String> fun){for(int i = 0;i < list.size();i++) {String apply = fun.apply(list.get(i));list.set(i, apply);} return list; }
4.4 断言型接口Predicate<T>
抽象方法:boolean test(T t);
//断言型接口@Testpublic void test4() {List<String> list = Remove(new ArrayList<String>(Arrays.asList("abc","df","aa","cc")),(s) -> s.length() < 2);System.out.println(list);}/*** @Description 删除集合中长度小于2的元素* @param list* @param pre* @return List<String>*/public List<String> Remove(List<String> list,Predicate<String> pre) {Iterator<String> it = list.iterator();while(it.hasNext()) {String str = it.next();if(pre.test(str)) {list.remove(str);}}return list;}
5 方法引用
5.1 方法引用
将Lambda体中的功能,已有方法方法提供了实现,可以使用方法引用(方法引用可以理解为Lambda的另一种表现形式)
方法引用分类:
(1)对象的引用::实例方法名
//对象的引用::实例方法名@Testpublic void test1() {Date date = new Date();//传统lambda表达式Supplier<Long> su = ()-> date.getTime();System.out.println(su.get());//对象引用Supplier<Long> su1 = date::getTime;System.out.println(su1.get());}
(2)类名::静态方法名
//类名::静态方法名@Testpublic void test2() {Comparator<Integer> com = (x,y)-> Integer.compare(x, y);System.out.println(com.compare(4, 5));Comparator<Integer> com1 = Integer::compare;System.out.println(com1.compare(4, 5));}
(3)类名::实例方法名
//类名::实例方法名@Testpublic void test3() {Function<Person,String> fun = (x)-> x.show();System.out.println(fun.apply(new Person()));Function<Person,String> fun1 = Person::show;System.out.println(fun.apply(new Person()));}class Person{public String show() {return "aaa";}}
注意:方法引用所引用的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致。若Lambda的参数列表的第一个参数,是实例方法的调用,第二个参数(或无参)是实例方法的参数是,格式:ClassName::MethodName
5.2 构造器引用
构造器中的参数列表需要与函数式中参数列表保持一致
类名::new
//类名 :: new@Testpublic void test4() {Supplier<Person> sup = () -> new Person();System.out.println(sup.get());Supplier<Person> sup2 = Person::new;System.out.println(sup2.get());}
6 Stream
6.1 什么是Stream
Stream流是数据管道,用于操作数据源(集合,数组)所产生的元素序列。
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,需要对元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。Stream是单向的数据只能遍历一次。迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。
注意:①stream自己不会存储元素;②stream不会改变对象,他会返回一个新的stream;③stream的操作是延迟的。
6.2 Stream的操作
操作步骤:①创建Stream;②中间操作;③终止操作
(1)创建流
@Testpublic void test1() {//1.Collection获取流,获取到的是顺序流List<String> list = new ArrayList<>();Stream<String> stream = list.stream();//2.通过Arrays中的stream获取一个数组流String[] arr = new String[5];Stream<String> stream2 = Arrays.stream(arr);//3.通过Stream类中的静态方法ofStream<Integer> of = Stream.of(11,22,33,44,55);//4.创建无限流Stream<Integer> limit = Stream.iterate(0, (x)-> x + 1).limit(20);limit.forEach(System.out::println);//5.用Stream的generate生成Stream<Double> limit2 = Stream.generate(Math::random).limit(20);limit2.forEach(System.out::println);}
(2)中间操作:
常用中间操作方法如下:
方法 | 描述 |
Stream<T> filter(Predicate<? super T> predicate) | 接收Lambda,从流中排除某些元素 |
Stream<T> limit(long maxSize) | 截断流,使元素不超过给定数量 |
Stream<T> skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个流,与limit(n)互补 |
Stream<T> distinct() | 帅选通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
<R> Stream<R> map(Function<? super T,? extends R> mapper) | 接收一个lambda,将元素转成成其他形式或提取信息,接收一个函数作为参数,该函数会被 应用到个元素上,并将其映射成一个新元素 |
(3)终止操作
常用终止操作如下
方法 | 描述 |
boolean allMatch(Predicate<? super T> predicate) | 检查是否匹配所有元素 |
boolean anyMatch(Predicate<? super T> predicate) | 检查是否至少匹配一个元素 |
boolean noneMatch(Predicate<? super T> predicate) | 检查是否没有匹配的元素 |
Optional<T> findFirst() | 返回第一个元素 |
Optional<T> findAny() | 返回当前流中的任意元素 |
long count() | 返回流中元素的总个数 |
Optional<T> max(Comparator<? super T> comparator) | 返回流中最大值 |
Optional<T> min(Comparator<? super T> comparator) | 返回流中最小值 |
案例:
@Testpublic void test2() {List<String> list = Arrays.asList("a","d","e","b","c");//自然排序list.stream().sorted().forEach(System.out::println);//定制排序List<Person> p = new ArrayList<>();p.add(new Person("aa",18,100.0));p.add(new Person("cc",16,150.0));p.add(new Person("bb",20,180.0));p.stream().sorted((e1,e2)->{if(e1.getAge()==e2.getAge()) {return e1.getName().compareTo(e2.getName());}else {return e1.getAge()-e2.getAge();}}).forEach(System.out::println);}class Person {private String name;private int age;private double score;public Person() {}public Person(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}@Overridepublic String toString() {return "Person1 [name=" + name + ", age=" + age + ", score=" + score + "]";}}