Java 8 Lambda 表达式 & Stream

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/Callable
    • (2)、Supplier/Consumer
    • (3)、Comparator
    • (4)、Predicate
    • (5)、Function
    • Lambda表达式语法格式总结:
    • 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():对集合元素进行进行匹配,全部元素都符合条件就为true
      • (6)、reduce():对集合元素进行进行求和或者归并处理
      • (7)、skip():跳过集合中某几个元素 limit():一次获取几个元素,两个结合类似于mysql分页操作
      • (8)、sorted():对集合中元素进行排序,接受一个Comparator
      • (9)、mapToInt():将集合中元素转化成一个IntStream mapToDouble():将集合中元素转化成一个DoubleStream mapToLong():将集合中元素转化成一个LongStream
      • (10)、flatMapToInt():将集合中元素转化成一个IntStream flatMapToDouble():将集合中元素转化成一个DoubleStream flatMapToLong():将集合中元素转化成一个LongStream
      • (11)、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 Supplier<T> {  
    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(Supplier<Integer> supplier) {  
      return supplier.get();  
   }  
}

@FunctionalInterface  
public interface Consumer<T> {  
    void accept(T var1);  
  
    default Consumer<T> 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 (Consumer<String> consumer) {  
      consumer.accept("Hello Word!");  
   }  
  
   /**  
    * Consumer中的默认方法-andThen,意思是多个消费者连接起来,各自消费一次  
    *  
    * @param first 第一个消费者  
    * @param second 第二个消费者  
    */  
   private static void consumer (Consumer<String> first, Consumer<String> second) {  
      first.andThen(second).accept("Hello Word!");  
   }  
}

(3)、Comparator

/**  
 * 函数式接口-Comparator  
 */public class ComparatorLambda {  
  
   public static void main(String[] args) {  
      List<Integer> 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(Function<String, String> function) {  
      return function.apply("hello");  
   }  
  
   /**  
    * andThen()的意思就是one和two都去处理"10"这个字符串,但是one处理后的结果要作为two的入参,然后再返回two处理的结果  
    *  
    * @param one 第一个函数功能  
    * @param two 第二个函数功能  
    * @return 结果  
    */  
   private static Integer andThenMethod(Function<String, String> one, Function<String, 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 {  
      List<Integer> 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 0x9
  public 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 : INVOKESTATIC
      TestLambda.lambda$main$0(Ljava/lang/Integer;)V, 
      (Ljava/lang/Integer;)V
    ]
    INVOKEINTERFACE java/util/List.forEach (Ljava/util/function/Consumer;)V (itf)

  // access flags 0x100A
  private static synthetic lambda$main$0(Ljava/lang/Integer;)V
   L0
    LINENUMBER 12 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 0
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
    RETURN
   L1
    LOCALVARIABLE i Ljava/lang/Integer; L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 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流对象  
   List<String> list = Arrays.asList("1", "2", "3", "4");  
   Stream<String> stream = list.stream();  
   System.out.println("使用集合对象的stream()获取stream流对象:" + stream);  

(2)、使用集合对象的stream()获取stream流对象

   // 2、使用stream流对象的静态方法of()、generate()、iterate()等方法获取获取stream流对象  
   Stream<List<String>> of = Stream.of(list);  
   System.out.println("使用stream流对象的静态方法of()方法获取获取stream流对象:" + of);  
   Stream<Integer> generate = Stream.generate(() -> 1 + 2);  
   System.out.println("使用stream流对象的静态方法generate()方法获取获取stream流对象:" + generate);  
   Stream<Integer> 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(){  
   List<String> list = Arrays.asList("1", "2", "3", "4");  
   Stream<String> stream = list.stream();  
   stream.forEach(System.out::println);  
}

(2)、count() 方法:统计,计数

/**  
 * stream流对象的count()  
 */
@Test  
public void testStreamAPICount(){  
   List<String> list = Arrays.asList("1", "2", "3", "4");  
   Stream<String> stream = list.stream();  
   long count = stream.count();  
   System.out.println(count);  
}

(3)、distinct():对集合去重

@Test  
public void testStreamAPIDistinct(){  
   List<String> list = Arrays.asList("1", "2", "2", "3", "3", "4", "4");  
   Stream<String> stream = list.stream();  
   Stream<String> distinct = stream.distinct();  
   distinct.forEach(System.out::println);  
}

(4)、map():对集合元素进行中间操作 peek():根据官方文档解释,用于调试使用,不建议使用

@Test  
public void testStreamAPIMap(){  
   List<String> list = Arrays.asList("1", "2", "2", "3", "3", "4", "4");  
   Stream<String> stream = list.stream();  
   Stream<Integer> map = stream.map(str -> str.concat("0")).map(Integer::parseInt);  
   map.forEach(System.out::println);  
  
   Stream<String> stream1 = list.stream();  
   Stream<String> 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(){  
   List<Integer> list = Arrays.asList(1, 2, 3, 4);  
   Stream<Integer> stream = list.stream();  
   Stream<Integer> filter = stream.filter(i -> i > 2);  
   filter.forEach(System.out::println);  
  
   Stream<Integer> stream1 = list.stream();  
   boolean anyMatch = stream1.anyMatch(i -> i == 2);  
   System.out.println("能匹配到一个2?:" + anyMatch);  
  
   Stream<Integer> stream2 = list.stream();  
   boolean allMatch = stream2.allMatch(i -> i == 2);  
   System.out.println("全部元素都是2?:" + allMatch);  
  
   Stream<Integer> stream3 = list.stream();  
   boolean noneMatch = stream3.noneMatch(i -> i == 2);  
   System.out.println("全部元素中没有一个是2?:" + noneMatch);  
}

(6)、reduce():对集合元素进行进行求和或者归并处理

@Test  
public void testStreamAPIReduce(){  
   List<Integer> list = Arrays.asList(1, 2, 3, 4);  
   Stream<Integer> stream = list.stream();  
   // 不指定初始值,返回Optional对象  
   Integer reduce = stream.reduce(Integer::sum).get();  
   System.out.println("求和:" + reduce);  
  
   Stream<Integer> stream1 = list.stream();  
   // 指定初始值为0,当Stream流为空时就返回0,不为空就返回结果。  
   Integer reduce1 = stream1.reduce(0, Integer::sum);  
   System.out.println("求和:" + reduce1);  
  
   Stream<Integer> stream2 = list.stream();  
   // 指定初始值为0,并且将整个过程分成多个子流去处理,并且最后归并多个子流处理的结果(归并操作),当Stream流为空时就返回0,不为空就返回结果。  
   Integer reduce2 = stream2.reduce(0, (a, b) -> a + b, Integer::sum);  
   System.out.println("求和:" + reduce2);  
  
   Stream<String> stream3 = list.stream().map(i -> i.toString());  
   // 指定初始值为0,并且将整个过程分成多个子流去处理,并且最后归并多个子流处理的结果(归并操作),当Stream流为空时就返回0,不为空就返回结果。  
   String reduce3 = stream3.reduce("", (a, b) -> a.concat(b));  
   System.out.println("字符串拼接:" + reduce3);  
   Stream<String> 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(){  
   List<Integer> list = Arrays.asList(1, 2, 3, 4);  
   Stream<Integer> stream = list.stream();  
   Stream<Integer> skip = stream.skip(2);  
   skip.forEach(System.out::println);  
  
   Stream<Integer> stream1 = list.stream();  
   Stream<Integer> limit = stream1.limit(1);  
   limit.forEach(System.out::println);  
}

(8)、sorted():对集合中元素进行排序,接受一个Comparator

@Test  
public void testStreamAPISkip(){  
   List<Integer> list = Arrays.asList(1, 2, 3, 4);  
   Stream<Integer> stream = list.stream();  
   Stream<Integer> sorted = stream.sorted();  
   sorted.forEach(System.out::println);  
  
   Stream<Integer> stream1 = list.stream();  
   Stream<Integer> sorted1 = stream1.sorted((o1, o2) -> o2 - o1);  
   sorted1.forEach(System.out::println);  
}

(9)、mapToInt():将集合中元素转化成一个IntStream mapToDouble():将集合中元素转化成一个DoubleStream mapToLong():将集合中元素转化成一个LongStream

@Test  
public void testStreamAPIMapTo(){  
   List<String> list = Arrays.asList("1", "2", "3", "4");  
   Stream<String> stream = list.stream();  
   IntStream mapToInt = stream.mapToInt(str -> Integer.parseInt(str.concat("0")));  
   mapToInt.forEach(System.out::println);  
  
   Stream<String> stream1 = list.stream();  
   DoubleStream mapToDouble = stream1.mapToDouble(str -> Double.parseDouble(str.concat("0")));  
   mapToDouble.forEach(System.out::println);  
  
   Stream<String> 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(){  
   List<String> list = Arrays.asList("1", "2", "3", "4");  
   Stream<String> stream = list.stream();  
   IntStream flatMapToInt = stream.flatMapToInt(str -> IntStream.of(Integer.parseInt(str.concat("0"))));  
   flatMapToInt.forEach(System.out::println);  
  
   Stream<String> stream1 = list.stream();  
   DoubleStream flatMapToDouble = stream1.flatMapToDouble(str -> DoubleStream.of(Double.parseDouble(str.concat("0"))));  
   flatMapToDouble.forEach(System.out::println);  
  
   Stream<String> 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(){  
   List<String> list = Arrays.asList("1", "2", "3", "4", "4");  
   Stream<String> stream = list.stream();  
   List<String> collectToList = stream.collect(Collectors.toList());  
   collectToList.forEach(System.out::println);  
  
   Stream<String> stream1 = list.stream();  
   Set<String> collectToSet = stream1.collect(Collectors.toSet());  
   collectToSet.forEach(System.out::println);  
  
   Stream<String> stream2 = list.stream();  
   String collectJoining = stream2.collect(Collectors.joining("a"));  
   System.out.println(collectJoining);  
  
   Stream<String> stream3 = list.stream();  
   // 第一个参数:key的生成规则 第二个参数:value的生成规则 第三个参数(可选):当key重复时,value的处理规则  
   Map<Object, Object> collectToMap = stream3.collect(Collectors.toMap(str -> str + "a", str -> str, (o, n) -> n));  
   System.out.println(collectToMap);  
  
   Stream<String> stream4 = list.stream();  
   Map<Object, List<String>> 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", "男");  
  
   List<User> list = Arrays.asList(user1, user2, user3, user4, user5, user6, user7, user8);  
   Stream<User> stream = list.stream();  
   Map<String, List<User>> 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操作,提供了一系列的开箱即用的聚合操作函数。

你可能感兴趣的:(JAVA,学习笔记,java,开发语言,lambda表达式,Stream流)