深圳购物网站建设,上饶网站开发,江苏建设通网站,豆芽网站建设lambda表达式和Stream流是JDK8新增加的新特性#xff0c;研究本文内容或者运行本文中的demo示例必须安装并使用JDK8以上的JDK版本。demo地址#xff1a;https://gitee.com/huannzi/bigdataframework/tree/master/src/main/java/com/orkasgb/java 文章目录1、什么是Lambda表达… lambda表达式和Stream流是JDK8新增加的新特性研究本文内容或者运行本文中的demo示例必须安装并使用JDK8以上的JDK版本。demo地址https://gitee.com/huannzi/bigdataframework/tree/master/src/main/java/com/orkasgb/java 文章目录1、什么是Lambda表达式2、Lambda表达式初体验1、简单的使用Lambda表达式2、Lambda表达式作为参数传递3、Lambda表达式作为返回值2、Lambda表达式高级体验--函数式接口1、Runnable/Callable2、Supplier/Consumer3、Comparator4、Predicate5、FunctionLambda表达式语法格式总结lambda表达式底层原理3、Stream流3.1、Stream流的获取1、使用集合对象的stream()获取stream流对象2、使用集合对象的stream()获取stream流对象3、使用集合对象的stream()获取stream流对象3.2、Stream流的常用方法1、forEach()方法代替for循环2、count() 方法统计计数3、distinct()对集合去重4、map()对集合元素进行中间操作 peek()根据官方文档解释用于调试使用不建议使用5、filter()对集合元素进行进行过滤根据过滤条件过滤复合要求的数据 anyMatch()对集合元素进行进行匹配只要有一个元素符合条件就为true allMatch()对集合元素进行进行匹配全部元素都符合条件就为true6、reduce()对集合元素进行进行求和或者归并处理7、skip()跳过集合中某几个元素 limit()一次获取几个元素两个结合类似于mysql分页操作8、sorted()对集合中元素进行排序接受一个Comparator9、mapToInt()将集合中元素转化成一个IntStream mapToDouble()将集合中元素转化成一个DoubleStream mapToLong()将集合中元素转化成一个LongStream10、flatMapToInt()将集合中元素转化成一个IntStream flatMapToDouble()将集合中元素转化成一个DoubleStream flatMapToLong()将集合中元素转化成一个LongStream11、Collectors.toList()将集合中元素转化成一个List Collectors.toSet()将集合中元素转化成一个Set Collectors.joining()将集合中每一个元素拼接一个字符串 Collectors.toMap将集合元素按照给定的规则转化成一个Map Collectors.groupingBy将集合元素按照给定的规则分组12、stream流综合测试总结1、什么是Lambda表达式
Lamdba表达式是JDK8加入的一种新特性属于一种响应式编程体验是一种关于函数定义输入量输出量的推演计算。简单的来说Lambda就是函数式编程。
2、Lambda表达式初体验
public interface DemoFactory { Object getDemo();
} /** * 具体的实现类 */
class DemoFactoryImpl implements DemoFactory{ Override public Object getDemo() { return new Demo(); }/** * Lambda表达式作为参数 * * param factory 接口参数 * return 实体 */ public static Object getDemo(DemoFactory factory) { return factory.getDemo(); }/** * Lambda表达式作为返回值 * * return 实体 */ public static DemoFactory getDemo1() { return () - new Demo(); }
} /** * 实体类 */
class Demo { private String call Hello Word!; public Demo() { System.out.println(this.call); }
}1、简单的使用Lambda表达式
/** * 调用类 */
class Main { public static void main(String[] args) { DemoFactory demo () - new Demo(); // 使用Lamdba表达式创建具体的实体对象System.out.println(demo.getDemo()); }
}2、Lambda表达式作为参数传递
/*** 调用类 */
class Main { public static void main(String[] args) { DemoFactoryImpl.getDemo(() - new Demo()); // 使用Lamdba表达式作为参数}
}3、Lambda表达式作为返回值
/*** 调用类 */
class Main { public static void main(String[] args) { DemoFactory factory DemoFactoryImpl.getDemo1();// Lambda作为返回值 factory.getDemo();}
}2、Lambda表达式高级体验–函数式接口
函数式接口指的是只有一个抽象方法且使用FunctionalInterface注解注释的接口称之为函数式接口。常见的函数式接口有以下几种
1、Runnable/Callable
FunctionalInterface
public interface Runnable { void run();
}public class RunnableLambda { public static void main(String[] args) { new Thread(() - System.out.println(RunnableLambda), thread1).start(); }
}2、Supplier/Consumer
FunctionalInterface
public interface SupplierT { T get();
}/** * 函数式接口--Supplier */public class SupplierLambda { public static void main(String[] args) { int[] arr new int[]{1, 2, 3, 4, 5}; int max getMax(() - Arrays.stream(arr).max().getAsInt()); System.out.println(最大值 max); } private static int getMax(SupplierInteger supplier) { return supplier.get(); }
}FunctionalInterface
public interface ConsumerT { void accept(T var1); default ConsumerT andThen(Consumer? super T after) { Objects.requireNonNull(after); return (t) - { this.accept(t); after.accept(t); }; }
}/** * 函数式接口--Consumer */public class ConsumerLambda { public static void main(String[] args) { consumer(s - System.out.println(s)); consumer(s - System.out.println(s.toLowerCase()), s - System.out.println(s.toUpperCase())); } /** * Consumer中的抽象方法-accept意思是消费一次 * * param consumer */ private static void consumer (ConsumerString consumer) { consumer.accept(Hello Word!); } /** * Consumer中的默认方法-andThen意思是多个消费者连接起来各自消费一次 * * param first 第一个消费者 * param second 第二个消费者 */ private static void consumer (ConsumerString first, ConsumerString second) { first.andThen(second).accept(Hello Word!); }
}3、Comparator
/** * 函数式接口-Comparator */public class ComparatorLambda { public static void main(String[] args) { ListInteger arr Arrays.asList(1, 2, 3, 4, 5); /** * sort()方法需要传入一个Comparator的实现默认是按照自然排序。 */ arr.sort((o1, o2) - o2 - o1); System.out.println(arr); }
}4、Predicate
/** * 函数式接口-Predicate */public class PredicateLambda { public static void main(String[] args) { addMethod(str - str.toString().equals(HelloWord!), str - str.toString().equals(HelloWord!)); notMethod(str - !str.toString().equals(HelloWord!)); orMethod(str - !str.toString().equals(HelloWord!), str - str.toString().equals(HelloWord!)); } /** * Predicate的and()方法意思是两个判断都要满足条件 * * param one 第一个断言 * param two 第二个断言 */ private static void addMethod (Predicate one, Predicate two) { String result one.and(two).test(HelloWord!) ? 字符串符合要求 : 字符串不符合要求; System.out.println(addMethod: result); } /** * Predicate的not()方法意思是当前判断结果取反 * * param one 第一个断言 */ private static void notMethod (Predicate one) { Predicate.not(one).test(true); String result String.valueOf(Predicate.not(one).test(true));; System.out.println(notMethod: result); } /** * Predicate的or()方法意思是两个判断只要有一个满足条件就可以 * * param one 第一个断言 * param two 第二个断言 */ private static void orMethod (Predicate one, Predicate two) { String result one.or(two).test(HelloWord!) ? 字符串符合要求 : 字符串不符合要求; System.out.println(orMethod: result); }
}5、Function
/** * 函数式接口-Function */public class FunctionLambda { public static void main(String[] args) { String result getUpCase(str - str.toUpperCase()); System.out.println(getUpCase: result); String result1 String.valueOf(andThenMethod(str - str.concat(0), str - Integer.valueOf(str) * 20)); System.out.println(andThenMethod: result1); } /** * apply(hello)的意思就是去处理hello这个字符串然后返回处理的结果 * * param function 函数功能 * return 返回处理的结果 */ private static String getUpCase(FunctionString, String function) { return function.apply(hello); } /** * andThen()的意思就是one和two都去处理10这个字符串但是one处理后的结果要作为two的入参然后再返回two处理的结果 * * param one 第一个函数功能 * param two 第二个函数功能 * return 结果 */ private static Integer andThenMethod(FunctionString, String one, FunctionString, Integer two) { return one.andThen(two).apply(10); }
}Lambda表达式语法格式总结
1、可选的{}当Lambda表达式的函数体只有一句的时候{}可以省略。
(String str) - System.out.println(str);2、可选的()当Lambda表达式的参数只有一个的时候()可以省略。
str - System.out.println(str);3、可选的return关键字当Lambda表达式的函数体只有一句的时候且返回值匹配的时候可以省略return关键字。
(int a, int b) - a b;4、可选的参数类型声明Lambda表达式可以省略参数类型声明因为参数动态进行推断。
(a, b) - return a b;lambda表达式底层原理
创建TestLambda.java文件简单的编写一个循环打印数组的测试代码。 1、使用 javac TestLambda.java编译TestLambda.java文件将会生成TestLambda.class文件。 2、使用 javap -v -p TestLambda反编译TestLambda.class文件。 3、使用 java -Djdk.internal.lambda.dumpProxyClasses TestLambda执行TestLambda程序并会生成TestLambda$$Lambda$1.class文件该文件是JAVA在运行时生成的由jvm生成的类实际上就是由lambda表达式生成的内部类的具体实现。
// TestLambda.java
public class TestLambda { static { System.setProperty(jdk.internal.lambda.dumpProxyClasses, .); } public static void main(String[] args) throws CloneNotSupportedException { ListInteger arr Arrays.asList(1, 2, 3, 4, 5); arr.forEach(i - System.out.println(i)); }
}// TestLambda.class字节码文件中删除了部分内容只保留了有用的地方
// class version 55.0 (55)
// access flags 0x21
public class TestLambda {// access flags 0x9public static main([Ljava/lang/String;)V throws java/lang/CloneNotSupportedException java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;// arguments:(Ljava/lang/Object;)V, // handle kind 0x6 : INVOKESTATICTestLambda.lambda$main$0(Ljava/lang/Integer;)V, (Ljava/lang/Integer;)V]INVOKEINTERFACE java/util/List.forEach (Ljava/util/function/Consumer;)V (itf)// access flags 0x100Aprivate static synthetic lambda$main$0(Ljava/lang/Integer;)VL0LINENUMBER 12 L0GETSTATIC java/lang/System.out : Ljava/io/PrintStream;ALOAD 0INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)VRETURNL1LOCALVARIABLE i Ljava/lang/Integer; L0 L1 0MAXSTACK 2MAXLOCALS 1
}// TestLambda$$Lambda$1.class
final class TestLambda$$Lambda$1 implements Consumer { private TestLambda$$Lambda$1() { } Hidden public void accept(Object var1) { TestLambda.lambda$main$0((Integer)var1); }
} **总结TestLambda.class中多出了一个private static synthetic lambda$main$0(Ljava/lang/Integer;)方法根据JAVA的特性这是一个动态生成的函数而在forEach参数里面由原本的lambda表达式变成了由Consumer强转的具体的实现由此说明lambda就是一个匿名内部类对象因为forEach接收的是一个Consumer所以这里原本的lambda表达式变成了由Consumer强转的具体的实现。 ambda表达式变成了由Consumer强转的具体的实现中有一个TestLambda.lambda$main$0(Ljava/lang/Integer;)V 参数而这个参数指向的就是TestLambda.class中多出来的那个private static synthetic lambda$main$0(Ljava/lang/Integer;)。 TestLambda$$Lambda$1.class是由JVM在运行时生成并通过特定参数保存下来的lambda表达式的具体实现的文件可以看出TestLambda$$Lambda$1实现了Consumer接口并重写了accept方法。而该方法中刚好调用的就是TestLambda.lambda$main$0((Integer)var1);。那么也就是说JVM在运行的时候将lambda表达式的方法体封装成一个具体的方法如private static synthetic lambda$main$0(Ljava/lang/Integer;)而将lambda表达式变成了由对应接口强转的具体的实现实现中将生成的该方法作为参数传入如TestLambda.lambda$main$0(Ljava/lang/Integer;)V 后续在生成具体实现的在重写的接口方法中直接调用该该方法如该例中accept方法中直接就调用了传入的TestLambda.lambda$main$0参数进而完成lambda表达式的功能。
3、Stream流
Stream流是专注于提供对容器的操作比如遍历过滤统计等操作提供了串行/并行两种模式使用Fork/Join框架对任务任务拆分已达到简化代码提高编程效率与可读性的目的。
3.1、Stream流的获取
1、使用集合对象的stream()获取stream流对象 // 1、使用集合对象的stream()获取stream流对象 ListString list Arrays.asList(1, 2, 3, 4); StreamString stream list.stream(); System.out.println(使用集合对象的stream()获取stream流对象 stream); 2、使用集合对象的stream()获取stream流对象 // 2、使用stream流对象的静态方法of()、generate()、iterate()等方法获取获取stream流对象 StreamListString of Stream.of(list); System.out.println(使用stream流对象的静态方法of()方法获取获取stream流对象 of); StreamInteger generate Stream.generate(() - 1 2); System.out.println(使用stream流对象的静态方法generate()方法获取获取stream流对象 generate); StreamInteger iterate Stream.iterate(10, i - i 2); System.out.println(使用stream流对象的静态方法iterate()方法获取获取stream流对象 iterate); 3、使用集合对象的stream()获取stream流对象 // 3、使用Arrays.stream()方法获取stream流对象 int[] arr {1,2,3}; IntStream stream1 Arrays.stream(arr); System.out.println(使用Arrays.stream()方法获取stream流对象 stream1);
3.2、Stream流的常用方法
1、forEach()方法代替for循环
/** * stream流对象的forEach方法 */
Test
public void testStreamAPIForEach(){ ListString list Arrays.asList(1, 2, 3, 4); StreamString stream list.stream(); stream.forEach(System.out::println);
}2、count() 方法统计计数
/** * stream流对象的count() */
Test
public void testStreamAPICount(){ ListString list Arrays.asList(1, 2, 3, 4); StreamString stream list.stream(); long count stream.count(); System.out.println(count);
}3、distinct()对集合去重
Test
public void testStreamAPIDistinct(){ ListString list Arrays.asList(1, 2, 2, 3, 3, 4, 4); StreamString stream list.stream(); StreamString distinct stream.distinct(); distinct.forEach(System.out::println);
}4、map()对集合元素进行中间操作 peek()根据官方文档解释用于调试使用不建议使用
Test
public void testStreamAPIMap(){ ListString list Arrays.asList(1, 2, 2, 3, 3, 4, 4); StreamString stream list.stream(); StreamInteger map stream.map(str - str.concat(0)).map(Integer::parseInt); map.forEach(System.out::println); StreamString stream1 list.stream(); StreamString peek stream1.peek(str - str.concat(0)).peek(Integer::parseInt); peek.forEach(System.out::println);
}5、filter()对集合元素进行进行过滤根据过滤条件过滤复合要求的数据 anyMatch()对集合元素进行进行匹配只要有一个元素符合条件就为true allMatch()对集合元素进行进行匹配全部元素都符合条件就为true
Test
public void testStreamAPIFilter(){ ListInteger list Arrays.asList(1, 2, 3, 4); StreamInteger stream list.stream(); StreamInteger filter stream.filter(i - i 2); filter.forEach(System.out::println); StreamInteger stream1 list.stream(); boolean anyMatch stream1.anyMatch(i - i 2); System.out.println(能匹配到一个2 anyMatch); StreamInteger stream2 list.stream(); boolean allMatch stream2.allMatch(i - i 2); System.out.println(全部元素都是2 allMatch); StreamInteger stream3 list.stream(); boolean noneMatch stream3.noneMatch(i - i 2); System.out.println(全部元素中没有一个是2 noneMatch);
}6、reduce()对集合元素进行进行求和或者归并处理
Test
public void testStreamAPIReduce(){ ListInteger list Arrays.asList(1, 2, 3, 4); StreamInteger stream list.stream(); // 不指定初始值返回Optional对象 Integer reduce stream.reduce(Integer::sum).get(); System.out.println(求和 reduce); StreamInteger stream1 list.stream(); // 指定初始值为0当Stream流为空时就返回0不为空就返回结果。 Integer reduce1 stream1.reduce(0, Integer::sum); System.out.println(求和 reduce1); StreamInteger stream2 list.stream(); // 指定初始值为0并且将整个过程分成多个子流去处理并且最后归并多个子流处理的结果归并操作当Stream流为空时就返回0不为空就返回结果。 Integer reduce2 stream2.reduce(0, (a, b) - a b, Integer::sum); System.out.println(求和 reduce2); StreamString stream3 list.stream().map(i - i.toString()); // 指定初始值为0并且将整个过程分成多个子流去处理并且最后归并多个子流处理的结果归并操作当Stream流为空时就返回0不为空就返回结果。 String reduce3 stream3.reduce(, (a, b) - a.concat(b)); System.out.println(字符串拼接 reduce3); StreamString stream4 list.stream().map(i - i.toString()); String reduce4 stream4.reduce(, String::concat); System.out.println(字符串拼接 reduce4);
}7、skip()跳过集合中某几个元素 limit()一次获取几个元素两个结合类似于mysql分页操作
Test
public void testStreamAPISkipAndLimit(){ ListInteger list Arrays.asList(1, 2, 3, 4); StreamInteger stream list.stream(); StreamInteger skip stream.skip(2); skip.forEach(System.out::println); StreamInteger stream1 list.stream(); StreamInteger limit stream1.limit(1); limit.forEach(System.out::println);
}8、sorted()对集合中元素进行排序接受一个Comparator
Test
public void testStreamAPISkip(){ ListInteger list Arrays.asList(1, 2, 3, 4); StreamInteger stream list.stream(); StreamInteger sorted stream.sorted(); sorted.forEach(System.out::println); StreamInteger stream1 list.stream(); StreamInteger sorted1 stream1.sorted((o1, o2) - o2 - o1); sorted1.forEach(System.out::println);
}9、mapToInt()将集合中元素转化成一个IntStream mapToDouble()将集合中元素转化成一个DoubleStream mapToLong()将集合中元素转化成一个LongStream
Test
public void testStreamAPIMapTo(){ ListString list Arrays.asList(1, 2, 3, 4); StreamString stream list.stream(); IntStream mapToInt stream.mapToInt(str - Integer.parseInt(str.concat(0))); mapToInt.forEach(System.out::println); StreamString stream1 list.stream(); DoubleStream mapToDouble stream1.mapToDouble(str - Double.parseDouble(str.concat(0))); mapToDouble.forEach(System.out::println); StreamString stream2 list.stream(); LongStream mapToLong stream2.mapToLong(str - Long.parseLong(str.concat(0))); mapToLong.forEach(System.out::println);
}10、flatMapToInt()将集合中元素转化成一个IntStream flatMapToDouble()将集合中元素转化成一个DoubleStream flatMapToLong()将集合中元素转化成一个LongStream
Test
public void testStreamAPIFlatMapTo(){ ListString list Arrays.asList(1, 2, 3, 4); StreamString stream list.stream(); IntStream flatMapToInt stream.flatMapToInt(str - IntStream.of(Integer.parseInt(str.concat(0)))); flatMapToInt.forEach(System.out::println); StreamString stream1 list.stream(); DoubleStream flatMapToDouble stream1.flatMapToDouble(str - DoubleStream.of(Double.parseDouble(str.concat(0)))); flatMapToDouble.forEach(System.out::println); StreamString stream2 list.stream(); LongStream flatMapToLong stream2.flatMapToLong(str - LongStream.of(Long.parseLong(str.concat(0)))); flatMapToLong.forEach(System.out::println);
}11、Collectors.toList()将集合中元素转化成一个List Collectors.toSet()将集合中元素转化成一个Set Collectors.joining()将集合中每一个元素拼接一个字符串 Collectors.toMap将集合元素按照给定的规则转化成一个Map Collectors.groupingBy将集合元素按照给定的规则分组
Test
public void testStreamAPICollect(){ ListString list Arrays.asList(1, 2, 3, 4, 4); StreamString stream list.stream(); ListString collectToList stream.collect(Collectors.toList()); collectToList.forEach(System.out::println); StreamString stream1 list.stream(); SetString collectToSet stream1.collect(Collectors.toSet()); collectToSet.forEach(System.out::println); StreamString stream2 list.stream(); String collectJoining stream2.collect(Collectors.joining(a)); System.out.println(collectJoining); StreamString stream3 list.stream(); // 第一个参数key的生成规则 第二个参数value的生成规则 第三个参数可选当key重复时value的处理规则 MapObject, Object collectToMap stream3.collect(Collectors.toMap(str - str a, str - str, (o, n) - n)); System.out.println(collectToMap); StreamString stream4 list.stream(); MapObject, ListString collectGroupingBy stream4.collect(Collectors.groupingBy(str - str)); System.out.println(collectGroupingBy);
}12、stream流综合测试
Test
public void test(){ User user1 new User(name1, 18, dep1, 女); User user2 new User(name2, 15, dep2, 男); User user3 new User(name3, 28, dep2, 女); User user4 new User(name4, 30, dep4, 男); User user5 new User(name5, 20, dep1, 男); User user6 new User(name6, 20, dep1, 女); User user7 new User(name6, 20, dep1, 女); User user8 new User(name8, 20, dep1, 男); ListUser list Arrays.asList(user1, user2, user3, user4, user5, user6, user7, user8); StreamUser stream list.stream(); MapString, ListUser test stream .distinct() // 去重 .filter(user - 女.equals(user.getSex())) // 过滤性别为女的 .peek(user - user.setSalary(2000 * 0.3 6000)) // 设置薪资属性的值 .sorted((u1, u2) - u2.getAge() - u1.getAge()) // 按照年龄从小到大排序 .limit(5) // 分页一次只取5条数据 .collect(Collectors.groupingBy(User::getDep)); // 按照部门分组 System.out.println(test);
} /** * 用户测试类 */
Data
class User { /** * 姓名 */ private String name; /** * 年龄 */ private int age; /** * 薪资 */ private Double salary; /** * 部门 */ private String dep; /** * 性别 */ private String sex; /** * 有参构造函数 * * param name 姓名 * param age 年龄 * param dep 部门 * param sex 性别 */ public User(String name, int age, String dep, String sex) { this.name name; this.age age; this.dep dep; this.sex sex; } Override public String toString() { return User{ name name \ , age age , dep dep \ , sex sex \ , salary salary \ }; }
}总结
1、lambda表达式可以简化匿名内部类的写法让编码更加便捷。 2、Stream流提供了一系列对容器或者集合API操作提供了一系列的开箱即用的聚合操作函数。