Lambda表达式:特殊的匿名内部类,语法更简洁。
Lanbda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。
基本语法:
<函数式接口> <变量名> = (参数1,参数2...) ->{ //方法体 }
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
Lambda需要注意的事项:
语法格式一:
lambda 无参,无返回值
//如何使用lambda表达式 public class Demo1 { public static void main(String[] args) { //线程//匿名实现类对象---以前的写法 // Runnable runnable=new Runnable() { // @Override // public void run() { // System.out.println("hello world!"); // } // }; //lambda表达式写法 Runnable runnable1= ()->System.out.println("hello world!"); new Thread(runnable1).start(); //更简单的写法 new Thread(()->System.out.println("hello world!")).start(); } }
语法格式二:
lambda 有一个参,无返回值
@Test public void test02(){ Consumer<String> con = new Consumer<String>() { @Override public void accept(String s){ System.out.println(s); } }; con.accept("hello world!"); System.out.println("*********************"); //Lambda表达式 Consumer<String> con1 = (String str)-> System.out.println(str); con1.accept("hello world"); }
语法格式三:
数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test public void test03(){ Consumer<String> con1 = (str) -> System.out.println(str); con1.accept("hello world"); }
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
@FunctionalInterface注解检测接口是否符合函数式接口
public class Demo1 { public static void main(String[] args) { USB usb = new USB() { @Override public void show() { System.out.println("我是函数式接口"); } }; USB usb1=()-> System.out.println("你好"); info(()-> System.out.println("你好嘿嘿嘿")); } public static void info(USB usb){ usb.show(); } } //函数式接口 interface USB{ public void show(); }
lambda新增了四个重要的函数式接口:
函数式接口说明
public class Demo2 { public static void main(String[] args) { // Consumer<Double> consumer=t-> System.out.println("吃饭消费掉:"+t); // Consumer<Double> consumer=new Consumer<Double>() { // @Override // public void accept(Double aDouble) { // System.out.println("你消费得金额:"+aDouble); // } // }; Consumer<Double> consumer1=t ->System.out.println("吃饭消费掉:"+t); Consumer<Double> consumer2=t ->System.out.println("唱歌消费掉:"+t); Consumer<Double> consumer3=t ->System.out.println("洗脚消费掉:"+t); hobby(consumer1,1000); hobby(consumer2,2000); hobby(consumer3,4000); Supplier<Integer> supplier=new Supplier<Integer>() { @Override public Integer get() { return new Random().nextInt(10); } }; Supplier<Integer> supplier1=()->new Random().nextInt(10); int[] arr = getArr(supplier1, 5); System.out.println(Arrays.toString(arr)); System.out.println("~~~~~~~~~~~~~~~function~~~~~~~~~~~~~~~~~~~~~~~"); // Function<String,String> function1=new Function<String, String>() { // @Override // public String apply(String s) { // return s.toUpperCase(); // } // }; // Function<String,String> function=s->s.toUpperCase(); // System.out.println(toUpper(function, "hello")); List<String> list=new ArrayList<>(); list.add("zhangsan"); list.add("lisi"); list.add("wangwu"); list.add("zhaoliu"); list.add("tianqi"); // Predicate<String> predicate=new Predicate<String>() { // @Override // public boolean test(String s) { // return s.length()>5; // } // }; Predicate<String> predicate1=s->s.length()>5; List<String> list1 = predicate(predicate1, list); System.out.println(list1); } //断言型接口 返回true/false经常用于判断 public static List<String> predicate(Predicate<String> predicate,List<String> list){ List<String> newList=new ArrayList<>(); for(int i=0;i<list.size();i++){ if(predicate.test(list.get(i))){ newList.add(list.get(i)); } } return newList; } //函数型接口 有参数,且需要返回值 public static String toUpper(Function<String,String> function,String str){ return function.apply(str); } //消费性函数式接口 不需要返回值,有参数,经常用于迭代 public static void hobby(Consumer<Double> consumer,double money){ consumer.accept(money); } //供给型函数式接口 无参数,指定返回值类型,经常用于只注重过程的代码 public static int[] getArr(Supplier<Integer> supplier,int count){ int [] arr=new int[count]; for(int i=0;i<count;i++){ arr[i]=supplier.get(); } return arr; } }
方法引用式Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见的方法引用:
(1)构造器引用
**格式:**类名::new
@Test public void test04(){ //普通写法 Supplier<Emp> supplier=new Supplier<Emp>() { @Override public Emp get() { return new Emp("刘德华"); } }; //类名::new 方法引用 Supplier<Emp> supplier=Emp::new; //必须该类中存在无参构造函数。 System.out.println(supplier.get()); } @Data @AllArgsConstructor @NoArgsConstructor class Emp{ private String name; }
(2)静态方法引用
**格式:**类名::静态方法名
//类::静态方法 int compare(T o1, T o2); //Lambda表达式方法引用 Comparator<Integer> comparator=(o1,o2)->Integer.compare(o1,o2); //静态方法引用Demo Comparator<Integer> comparator=Integer::compare; int compare = comparator.compare(18, 18); System.out.println(compare);
(3)类的方法引用
**格式:**类名::实例方法名
//lambda匿名方法引用 Function<Emp,String> function=e->{ return e.getName(); }; //类名::实例方法 R apply(T t); Function<Emp,String> function=Emp::getName; System.out.println(function.apply(new Emp("刘德华")));
(4)实例对象的方法引用
**格式:**对象::实例方法名
//对象::实例方法 //这里System.out就是一个对象 Consumer<String> consumer2=System.out::println; consumer2.accept("你是刘德华吗?");
流(Stream)中保存对集合或数组数据的操作。和集合类似,但集合中保存的是数据。
特点:
步骤:
创建一个流。
在一个或多个步骤中,将初始化Stream转化到另一个Stream的中间操作。
使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,该Stream就不能使用了。
要注意的是,对流的操作完成后需要进行关闭操作(或者用JAVA7的try-with-resources)。
获取Stream对象的方式
public class Demo1 { public static void main(String[] args) { //1.通过Collection得对象中stream方法或parallelStream List<String> list=new ArrayList<>(); list.add("apple"); list.add("huawei"); list.add("xiaomi"); list.add("vivo"); Stream<String> stream = list.stream();//串行流 //遍历集合(T t)-{}; 方法引用 stream.forEach(e->{ System.out.println(e); }); //方法引用 stream.forEach(System.out::println); Stream<String> stringStream = list.parallelStream(); //并行流 //2.通过Arrays转化为流 int[] arr={2,34,5,6,7,2}; IntStream stream = Arrays.stream(arr); stream.forEach(System.out::println); //3.通过Stream中of,iterator,generator(); Stream<String> list = Stream.of("java01", "java02", "java03"); static <T> UnaryOperator<T> identity() { return t -> t; } UnaryOperator<Integer> unaryOperator=new UnaryOperator<Integer>() { @Override public Integer apply(Integer x) { return x+5; } }; UnaryOperator<Integer> unaryOperator=x->x+5; Stream<Integer> list = Stream.iterate(0,unaryOperator);//0,5,10,15,20,25,30 list.limit(10).forEach(System.out::println); Supplier<T> s Supplier<Integer> s=new Supplier() { @Override public Integer get() { return new Random().nextInt(50); } }; Supplier<Integer> s=()->new Random().nextInt(50); Stream<Integer> stream = Stream.generate(s); Stream<Integer> stream = Stream.generate(()->new Random().nextInt(50)); stream.limit(10).forEach(System.out::println); //IntStream LongStream DoubleStream IntStream stream = IntStream.rangeClosed(0, 90); stream.forEach(System.out::println); } }
中间操作.
filter、limit、skip、distinct、sorted map parallel
代码操作
public class test02 { public static void main(String[] args) { //personList.stream()是创建流,filter()属于中间操作,forEach、count()是终止操作。 List<Person> personList = new ArrayList<>(); personList.add(new Person("欧阳雪",18,"中国",'F')); personList.add(new Person("Tom",24,"美国",'M')); personList.add(new Person("Tom",24,"美国",'M')); personList.add(new Person("Harley",22,"英国",'F')); personList.add(new Person("向天笑",20,"中国",'M')); personList.add(new Person("李康",22,"中国",'M')); personList.add(new Person("小梅",20,"中国",'F')); personList.add(new Person("何雪",21,"中国",'F')); personList.add(new Person("李康",22,"中国",'M')); //找出大于21岁的人 personList.stream().filter((person) -> person.getAge()>21).forEach(System.out::println); System.out.println("----------------------"); //查询中国人有几个 long num = personList.stream().filter(p ->p.getCountry().equals("中国")).count(); System.out.println("中国人有:"+num+"个"); System.out.println("---------------------------"); //从Person列表中取出两个女性。 personList.stream().filter((p) -> p.getSex() == 'F').limit(2).forEach(System.out::println); System.out.println("----------------------------"); //从Person列表中从第2个女性开始,取出所有的女性。 personList.stream().filter((p) -> p.getSex() == 'F').skip(1).forEach(System.out::println); System.out.println("-------------------------------"); //去除掉了一个重复的数据 personList.stream().filter((p) -> p.getSex() == 'M').distinct().forEach(System.out::println); }
测试结果
在这个例子中,personList.stream()是创建流,filter()、limit()、skip()、distinct()属于中间操作,forEach、count()是终止操作。
map举例
例:比如,我们用一个PersonCountry类来接收所有的国家信息:
System.out.println("**************************"); personList.stream().map((p) -> { Person personName = new Person(); personName.setCountry(p.getCountry()); return personName; }).distinct().forEach(System.out::println);
测试结果
自然排序比较好理解,这里只讲一下定制排序,对前面的personList按年龄从小到大排序,年龄相同,则再按姓名排序:
final Stream<Person> sorted = personList.stream().sorted((p1, p2) -> { if (p1.getAge().equals(p2.getAge())) { return p1.getName().compareTo(p2.getName()); } else { return p1.getAge().compareTo(p2.getAge()); } }); sorted.forEach(System.out::println);
运行结果
forEach、min、max、count reduce、collect
allMatch
判断personList中的人是否都是成年人:
final boolean adult = personList.stream().allMatch(p -> p.getAge() >= 18); System.out.println("是否都是成年人:" + adult); final boolean chinaese = personList.stream().allMatch(p -> p.getCountry().equals("中国")); System.out.println("是否都是中国人:" + chinaese);
运行结果
max min
判断最大、最小的人信息
final Optional<Person> maxAge = personList.stream().max((p1, p2) -> p1.getAge().compareTo(p2.getAge())); System.out.println("年龄最大的人信息:" + maxAge.get()); final Optional<Person> minAge = personList.stream().min((p1, p2) -> p1.getAge().compareTo(p2.getAge())); System.out.println("年龄最小的人信息:" + minAge.get());
运行结果
求一个1到100的和
List<Integer> integerList = new ArrayList<>(100); for(int i = 1;i <= 100;i++) { integerList.add(i); } final Integer reduce = integerList.stream().reduce(0, (x, y) -> x + y); System.out.println("结果为:" + reduce);
运行结果
求所有人的年龄之和
final Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum); System.out.println("年龄总和:" + reduce);
年龄总和:193
改写map举例中的的例子,将国家收集起来转换成List
final List<String> collect = personList.stream().map(p -> p.getCountry()).distinct().collect(Collectors.toList()); System.out.println(collect);
输出结果:[中国, 美国, 英国]
计算出平均年龄
final Double collect1 = personList.stream().collect(Collectors.averagingInt(p -> p.getAge())); System.out.println("平均年龄为:" + collect1);
平均年龄为:21.444444444444443
注意流的关闭
try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) { final Optional<Integer> minAge = integerStream.collect(Collectors.minBy(Integer::compareTo)); System.out.println(minAge.get()); }
到此这篇关于Java8常用的新特性详解的文章就介绍到这了,更多相关Java8常用的新特性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
免责声明:本站发布的内容(图片、视频和文字)以原创、来自本网站内容采集于网络互联网转载等其它媒体和分享为主,内容观点不代表本网站立场,如侵犯了原作者的版权,请告知一经查实,将立刻删除涉嫌侵权内容,联系我们QQ:712375056,同时欢迎投稿传递力量。
Copyright © 2009-2022 56dr.com. All Rights Reserved. 特网科技 特网云 版权所有 特网科技 粤ICP备16109289号
域名注册服务机构:阿里云计算有限公司(万网) 域名服务机构:烟台帝思普网络科技有限公司(DNSPod) CDN服务:阿里云计算有限公司 百度云 中国互联网举报中心 增值电信业务经营许可证B2
建议您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流浏览器浏览本网站