Java8 Lamda的基本使用
Lamda的基本使用
https://www.cnblogs.com/htyj/p/10133883.html
https://segmentfault.com/q/1010000011200292
Java 8 lambda Collectors优雅的使用方式-超详细
https://blog.csdn.net/hu10131013/article/details/108368809
————————————————————————————————————————————————————————————————————————————————————————————————————
//排序 先升序后降序
// 关键 thenComparing、Comparator.reverseOrder() // 1.先以年龄升序 2.当年龄相同时,在以薪资降序 List<User> userList = lists.stream() .sorted(Comparator.comparing(User::getAge).thenComparing(User::getSalary,Comparator.reverseOrder())) .collect(Collectors.toList());
//int数组转成串 int[] ints= new int[] {1,2,3,4,5}; //方法1: List<String> lists=Arrays.stream(ints).boxed().map(t->t+"").collect(Collectors.tolist()); System.out.println(String.join("",lists)); //方法2: List<String> lists2=Arrays.stream(ints).boxed().map(t->t+"").collect(java.util.stream.joining("")); System.out.println(String.join("",lists));
KeyInput.java
/* 1、输出信息到控制台: System.out.println(...); 2、在java中怎么接受键盘的输入? 在面向对象章节才能理解,现在先了解。 前提:java.util.Scanner s = new java.util.Scanner(System.in); 接收一个字符串: String str = s.next(); 接收一个正整数: int i = s.nextInt(); */ public class KeyInput{ public static void main(String[] args){ // 创建一个键盘扫描器对象 // s是变量名可以修改。 java.util.Scanner s = new java.util.Scanner(System.in); // 接收用户的输入,从键盘上接收一个int类型的数据 // 代码执行到这的时候会暂停下来等待用户的输入,用户可以 // 用户可以从键盘上输入一个整数,然后回车,回车之后i变量 // 就有值了,并且i变量中保存的这个值是用户输入的数字。 int i = s.nextInt(); System.out.println("您输入的数字是:"+i); int j = s.nextInt(); System.out.println("您输入的数字是:"+j); // 从键盘上接收一个字符串 String str = s.next(); System.out.println("您输入的字符串是:"+str); System.out.print("请输入您的用户名:"); String name = s.next(); System.out.println("欢迎"+name+"回来"); } }
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
1、Collection
Java 8 为Iterable接口新增了一个forEach(Consumer action)默认方法,该方法所需参数的类型是一个函数式接口,而Iterable接口是Collection接口的父接口,因此Collection集合也可以直接调用该方法。
当程序调用Iterable的forEach(Consumer action)遍历集合元素时,程序会依次将集合元素传给Consumer的accept(T t)方法(该接口中唯一的抽象方法)。正因为Consumer是函数式接口,因此可以使用Lambda表达式来遍历集合元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import java.util.Collection; import java.util.HashSet; import java.util.function.*; public class CollectionEach{ public static void main(String []args){ //创建一个集合 Collection<String> c= new HashSet<String>(); //需要泛型,否则提示警告:使用了未经检查或不安全的操作,可以直接运行 c.add( "ni" ); c.add( "hao" ); c.add( "java" ); c.forEach( new Consumer<String>(){ public void accept(String t){ System.out.println( "集合元素是:" +t); } }); //不使用lambda表达式和两种使用lambda表达式方式 c.forEach(t->System.out.println( "集合元素是:" +t)); c.forEach(System.out::println); } } |
2、Iterator
java 8 为Iterator新增了一个forEachRemaining(Consumer action)方法,该方法所需的Consumer参数同样也是函数式接口。当程序调用Iterator的forEachRemaining(Consumer action)遍历集合元素时,程序会一次将集合元素传递给Consumer的accept(T t)方法(该接口中唯一的抽象方法)。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import java.util.Collection; import java.util.Iterator; import java.util.HashSet; public class IteratorEach{ public static void main(String []args){ Collection<String> c= new HashSet<String>(); c.add( "ni" ); c.add( "hao" ); c.add( "java" ); Iterator<String> it=c.iterator(); //使用泛型 it.forEachRemaining(System.out::println); } } |
forEach的使用
1
2
|
Random random = new Random(); random.ints().limit( 10 ).forEach(System.out::println); |
但是forEach并没有返回值,所以有时候在对集合进行循环,使用map()函数更为方便:
final List<String> friends = Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott"); friends.stream().map(name -> name.toUpperCase()).forEach(name -> System.out.print(name + " ")); System.out.println();
老式遍历和新式遍历的区别:
java8之前的增强for这种方式的迭代是使用Iterator接口来实现的,调用了它的hasNext和next方法。 这两种方式都属于外部迭代器,它们把如何做和想做什么揉到了一起。我们显式的控制迭代,告诉它从哪开始到哪结束;第二个版本则在底层通过Iterator的方法来做这些。显式的操作下,还可以用break和continue语句来控制迭代。 第二个版本比第一个少了点东西。如果我们不打算修改集合的某个元素的话,它的方式比第一个要好。不过这两种方式都是命令式的,在现在的Java中应该摒弃这种方式。 改成函数式原因有这几个:
- for循环本身是串行的,很难进行并行化。
- 这样的循环是非多态的;所得即所求。我们直接把集合传给for循环,而不是在集合上调用一个方法(支持多态)来执行特定的操作。
- 从设计层面来说,这样 写的代码违反了“Tell,Don't Ask”的原则 。我们请求执行一次迭代,而不是把迭代留给底层库来执行。
是时候从老的命令式编程转换到更优雅的内部迭代器的函数式编程了。使用内部迭代器后我们把很多具体操作都扔给了底层方法库来执行,你可以更专注于具体的业务需求。底层的函数会负责进行迭代的。我们先用一个内部迭代器来枚举一下名字列表。
Iterable接口在JDK8中得到加强,它有一个专门的名字叫forEach,它接收一个Comsumer类型的参数。如名字所说,Consumer的实例正是通过它的accept方法消费传递给它的对象的。
这个forEach方法是一个高阶函数,它接收一个lambda表达式或者代码块,来对列表中的元素进行操作。在每次调用的时候 ,集合中的元素会绑定到name这个变量上。底层库托管了lambda表达式调用的活。它可以决定延迟表达式的执行,如果合适的话还可以进行并行计算。内部迭代器的版本更为简洁。而且,使用它的话我们可以更专注每个元素的处理操作,而不是怎么去遍历——这可是声明式的。
不过这个版本还有缺陷。一旦forEach方法开始执行了,不像别的两个版本,我们没法跳出这个迭代。(当然有别的方法能搞定这个)。
在这个例子里,Java编译器通过上下文分析,知道name的类型是String。它查看被调用方法forEach的签名,然后分析参数里的这个函数式接口。接着它会分析这个接口里的抽象方法,查看参数的个数及类型。即便这个lambda表达式接收多个参数,我们也一样能进行类型推导,不过这样的话所有参数都不能带参数类型;在lambda表达式中,参数类型要么全不写,要写的话就得全写。
Java编译器对单个参数的lambda表达式会进行特殊处理:如果你想进行类型推导的话,参数两边的括号可以省略掉。
这里有一点小警告:进行类型推导的参数不是final类型的。在前面显式声明类型例子中,我们同时也把参数标记为final的。这样能防止你在lambda表达式中修改参数的值。通常来说,修改参数的值是个坏习惯,这样容易引起BUG,因此标记成final是个好习惯。不幸的是,如果我们想使用类型推导的话,我们就得自己遵守规则不要修改参数,因为编译器可不再为我们保驾护航了。
fiter过滤器的使用
示例:
List<Person> javaProgrammers = new ArrayList<Person>() { { add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000)); add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500)); add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800)); add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600)); add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200)); add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900)); } };
- 单个条件过滤
1
2
|
String s = comRepayInfo.getLoanOrderId() + String.valueOf(repayNum1); List<CompensatVO> collect = temporaryList.stream().filter((CompensatVO vo1) -> (vo1.getLoanOrderId()+vo1.getRepayNum()).equals(s)).collect(Collectors.toList()); |
- 多条件重过滤
// 定义 filters Predicate<Person> ageFilter = (p) -> (p.getAge() > 25); Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400); Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender())); System.out.println("下面是年龄大于 24岁且月薪在$1,400以上的女PHP程序员:"); phpProgrammers.stream() .filter(ageFilter) .filter(salaryFilter) .filter(genderFilter) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
System.out.println("最前面的3个女性 Java programmers:"); javaProgrammers.stream() .filter(genderFilter) .limit(3) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
System.out.println("根据 name 排序,并显示前5个 Java programmers:"); List<Person> sortedJavaProgrammers = javaProgrammers .stream() .sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName()))) .limit(5) .collect(toList());
- 选择某个字段最大的和最小的值
使用这种方法不需要先排序
System.out.println("工资最低的 Java programmer:"); Person pers = javaProgrammers .stream() .min((p1, p2) -> (p1.getSalary() - p2.getSalary())) .get(); System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary()) System.out.println("工资最高的 Java programmer:"); Person person = javaProgrammers .stream() .max((p, p2) -> (p.getSalary() - p2.getSalary())) .get(); System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())
List排序:
- 升序排序:
1
2
3
|
1 .Collections.sort(dataList,(p1,p2)->p1.getInstallmentNo().compareTo(p2.getInstallmentNo())); //dataList是需要排序的集合 2 .Collections.sort(dataList,Comparator.comparing(RepayPlanDTO::getInstallmentNo)); //dataList是需要排序的集合 3 .dataList.stream.sorted(Comparator.comparing((Apple a) -> a.getWeight())).collect(Collectors.toList()); <br> //或者等价于 <br> dataList.stream.sorted(Comparator.comparing(Apple::getWeight)).collect(Collectors.toList());//dataList是需要排序的集合 |
1
|
<em id= "__mceDel" > 4 .userList.stream.sort((String s1, String s2) -> (s1.length() - s2.length())); //根据名称的长度进行排序</em> |
- 降序排序
1
2
|
1 .Collections.sort(dataList,(p1,p2)->p2.getInstallmentNo().compareTo(p1.getInstallmentNo())); 2 .dataList.stream.sorted(Comparator.comparing(Apple::getWeight).reversed()).collect(Collectors.toList()); |
- 多参数排序
1
|
1 .dataList.sort(Comparator.comparing(RepayPlanDetailFileVO::getLoanOrderId).thenComparing(RepayPlanDetailFileVO::getRepayNum)); |
list转map的操作
示例:
List<User> list =new ArrayList<>(); User user1=new User("fgg",2); User user2=new User("ghj",1); User user3=new User("dft",4); User user4=new User("abc",3); User user5=new User("ads",5); list.add(user1); list.add(user2); list.add(user3); list.add(user4); list.add(user5);
- 用年龄作为map的key,名字作为map的value:
Map<Integer, User> collect3 = collect2.stream().collect(Collectors.toMap(User::getAge, User:getName));
- 用年龄作为map的key,user对象作为map的value:
Map<Integer, User> collect3 = collect2.stream().collect(Collectors.toMap(User::getAge, user -> user)); Map<Integer, User> collect5 = collect2.stream().collect(Collectors.toMap(User::getAge, Function.identity()));这两种用法是等价的
- 但是如果做为key的字段有重复的上面的写法就不行了,在执行程序时就会报错,但我们可以用下面的方式来解决:
Map<Integer, User> collect3 = collect2.stream().collect(Collectors.toMap(User::getAge, user -> user,(key1, key2) -> key2));//这种写法只是在出现两个一样的key值时,暴力的用后面一个key的value值覆盖前面相同的key的value值 Map<Integer, List<User>> collect5 = collect2.stream().collect(Collectors.groupingBy(User::getAge));//这种写法是当遇到相同的key值时,会自动的将相同key值的value值组装成一个集合
Map<Integer, User> collect3 = collect2.stream().collect(Collectors.toMap(User::getAge, user -> user,(key1, key2) -> key2,LinkedHashMap::new));//这种写法是我们可以执行特定的map类型来接受我们的结果
- 使用map()函数进行转换
System.out.println("将 PHP programmers 的 first name 拼接成字符串:"); String phpDevelopers = phpProgrammers .stream() .map(Person::getFirstName) .collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token) System.out.println("将 Java programmers 的 first name 存放到 Set:"); Set<String> javaDevFirstName = javaProgrammers.stream().map(Person::getFirstName).collect(Collectors.toSet());
System.out.println("将 Java programmers 的 first name 存放到 TreeSet:"); TreeSet<String> javaDevLastName = javaProgrammers .stream() .map(Person::getLastName) .collect(toCollection(TreeSet::new));
Map排序:
1
2
3
|
Map<String ,Integer> map= new HashMap<>(); LinkedHashMap<String, Integer> collect = map.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue()).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue(), (k, v) -> k, LinkedHashMap:: new )); |
public Map<String, Integer> sortedByKeys(Map<String, Integer> map) { Map<String, Integer> result = new LinkedHashMap<>(); map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> result.put(x.getKey(), x.getValue())); return result; }
- comparingByKey() //利用key值进行排序,但要求key值类型需要实现Comparable接口。
- comparingByValue() //利用value值进行排序,但要求key值类型需要实现Comparable接口。
- comparingByKey(Comparator) //利用key值进行排序,但key值并没有实现Comparable接口,需要传入一个Comparator比较器。
- comparingByValue(Comparator) //利用value值进行排序,但value值并没有实现Comparable接口,需要传入一个Comparator比较器。
Map合并
示例:
Map<String, Employee> map1 = new HashMap<>();
Map<String, Employee> map2 = new HashMap<>();
Employee employee1 = new Employee(1L, "Henry"); Employee employee2 = new Employee(22L, "Annie"); Employee employee3 = new Employee(8L, "John"); map1.put(employee1.getName(), employee1); map1.put(employee2.getName(), employee2); map1.put(employee3.getName(), employee3); Employee employee4 = new Employee(2L, "George"); Employee employee5 = new Employee(3L, "Henry"); map2.put(employee4.getName(), employee4); map2.put(employee5.getName(), employee5);
Map<String, Employee> map3 = new HashMap<>(map1);
- 使用Merge将map2合并到map3中:
Java8为 java.util.Map接口新增了merge()函数。merge() 函数的作用是: 如果给定的key之前没设置value 或者value为null, 则将给定的value关联到这个key上.否则,通过给定的remaping函数计算的结果来替换其value。如果remapping函数的计算结果为null,将解除此结果。First, let’s construct a new HashMap by copying all the entries from the map1:
map2.forEach( (key, value) -> map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())) );
其中(v1, v2) -> new Employee(v1.getId(),v2.getName())是当出现key相同时的合并策略,示例中的key值出现相同的情况时的合并策略是:id来自map3而name来自map2.
- 使用Stream.concat()进行合并:
Java8的Stream API 也为解决该问题提供了较好的解决方案。
Map<String, Employee> result=Stream.concat(map1.entrySet().stream(), map2.entrySet().stream()).collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(value1, value2) -> new Employee(value2.getId(), value1.getName())));;
- 使用Stream.of()进行合并:
通过Stream.of()方法不需要借助其他stream就可以实现map的合并。
Map<String, Employee> map3 = Stream.of(map1, map2).flatMap(map -> map.entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,(v1, v2) -> new Employee(v1.getId(), v2.getName())));
- 使用Simple Streaming进行合并:
借助stream的管道操作来实现map合并
Map<String, Employee> map3 = map2.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,(v1, v2) -> new Employee(v1.getId(), v2.getName()),() -> new HashMap<>(map1)));
- 使用StreamEx进行合并:
我们还可以使Stream API 的增强库
Map<String, Employee> map3 = EntryStream.of(map1).append(EntryStream.of(map2)).toMap((e1, e2) -> e1);
注意:(e1, e2) -> e1 表达式来处理重复key的问题,如果没有该表达式依然会报IllegalStateException异常.
Predicate和Function的使用
目前,已经出现了两种类型的函数式接口(Functional Interface)。它们分别是filter方法使用的Predicate和map方法使用的Function。
在上面我们讲filter的多条件过滤时,我们把过滤的条件单独拿了出来,可以方便方法内的其他filter复用,但是如果我们在进行某种过滤时只是传的值不通过滤条件是相同的,遇到这种情况我们是否需要再增加个过滤条件呢,很显然要是这样做了重复代码就太多了,我们可以如下来做:
第一种做法:
public static Predicate<Integer> checkAge(final Integer letter) { return (p) -> (p.getAge() >letter);
}
第二种方式:
final Function<Integer, Predicate<Integer>> checkAgeResult= (Integer letter) -> { Predicate<Integer> checkAge = (Integer age) -> age>letter; return checkAge; };
或者
final Function<Integer, Predicate<Integer>> checkAgeResult = (Integer letter) -> (Integer age) -> age>letter;
或者
final Function<Integer, Predicate<Integer>> checkAgeResult = letter -> age -> age>letter;
这三者是等价的
使用示例:
final Function<Integer, Predicate<User>> checkAge = letter -> age -> age.getAge()>letter; final Function<String, Predicate<User>> checkName = letter -> name -> name.getName().contains(letter); List<User> abc = list.stream().filter(checkAge.apply(2).and(checkName.apply("abc"))).collect(Collectors.toList());
注意:在使用的时候Function<Integer,President<User>>中的User对应的就是最终集合中的类型,而Integer对应的是参数“letter”的数据类型
计算
mapToInt方法得到的是一个Stream类型的子类型IntStream的实例,与IntStream类似,还有LongStream和DoubleStream类型,用于简化相关的操作。而通常和这些方法联合使用的除了sum()方法还有max(),min(),average()等一系列方法用来实现常用的归约。
reduce方法的工作原理,可以这样概括:在对一个集合中的元素按照顺序进行两两操作时,根据某种策略来得到一个结果,得到的结果将作为一个元素参与到下一次操作中,最终这个集合会被归约成为一个结果。这个结果也就是reduce方法的返回值。
- 计算支付金额的总和,可以使用并行Stream提高效率
System.out.println("计算付给 Java programmers 的所有money:"); int totalSalary = javaProgrammers .parallelStream() .mapToInt(p -> p.getSalary()) .sum();
- 获取某个数据的统计数据
//计算 count, min, max, sum, and average for numbers List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); IntSummaryStatistics stats = numbers .stream() .mapToInt((x) -> x) .summaryStatistics(); System.out.println("List中最大的数字 : " + stats.getMax()); System.out.println("List中最小的数字 : " + stats.getMin()); System.out.println("所有数字的总和 : " + stats.getSum()); System.out.println("所有数字的平均值 : " + stats.getAverage());
- reduce归约
final Optional<String> aLongName = friends.stream() .reduce((name1, name2) -> name1.length() >= name2.length() ? name1 : name2); aLongName.ifPresent(name -> System.out.println(String.format("A longest name: %s", name)));
第一次执行两两操作时,name1和name2代表的是集合中的第一个和第二个元素,当第一个元素的长度大于等于第二个元素时,将第一个元素保留下来,否则保留第二个元素。 第二次执行两两操作时,name1代表的是上一次操作中被保留下来的拥有较长长度的元素,name2代表的是第三个元素。 以此类推...最后得到的结果就是集合中第一个拥有最长长度的元素了。
实际上,reduce方法接受的Lambda表达式的行为被抽象成了BinaryOperator接口:
@FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T,T,T> { // others... } @FunctionalInterface public interface BiFunction<T, U, R> { /** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u); // others... }
源码也反映了BinaryOperator和另一个函数式接口BiFunction之间的关系,当BiFunction接口中接受的三个参数类型一致时,也就成为了一个BinaryOperator接口。因此,前者实际上是后者的一个特例。
另外需要注意的几点:
- reduce方法返回的对象类型时Optional,这是因为待操作的集合可能是空的。
- 当集合只有一个元素时,reduce会立即将该元素作为实际结果以Optional类型返回,不会调用传入的Lambda表达式。
- reduce方法是会按照集合的顺序对其元素进行两两操作的,可以额外传入一个值作为“基础值”或者“默认值”,那么在第一次进行两两操作时,第一个操作对象就是这个额外传入的值,第二个操作对象是集合中的第一个元素。
比如,以下代码为reduce方法传入了默认值:
final String steveOrLonger = friends.stream() .reduce("Steve", (name1, name2) -> name1.length() >= name2.length() ? name1 : name2);
- 复制不同的值
// 用所有不同的数字创建一个正方形列表 List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4); List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); System.out.printf("Original List : %s, Square Without duplicates : %s %n", numbers, distinct);
- 元素链接
// 将字符串换成大写并用逗号链接起来 List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada"); String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", ")); 或者
String result=names.stream().map(String::toUpperCase).collect(Collectors.joining(", "));
可见collect方法并不自己完成归约操作,它会将归约操作委托给一个具体的Collector,而Collectors类型则是一个工具类,其中定义了许多常见的归约操作,比如上述的joining Collector
学习链接:
java8中Comparable与Comparator的区别
java8新特性 lambda Stream map(函数式编程)
______________________________________________________________________________________________________________________________
//记录一下相关的转换,以备后续学习
public static void main(String[] args){
String[] a = stripAll("1","2","3","4");//org.apache.commons.lang3.StringUtils
String[] b = stripAll(new String[]{"1","2","3","4"},"/");
System.out.println(strip("/123/123 /","/"));
System.out.println(Arrays.toString(a));
String start = "'";
String end = "'";
String link = ",";
int[] arr = {1,2,3,4};
String[] arr2 = {"1","2","3","4"};
//forEach函数实现内部迭代
StringBuilder sb = new StringBuilder();
Arrays.asList(arr2).forEach(o -> { if (sb.length() > 0) {sb.append(link);} sb.append(start + o + end);});//forEach函数实现内部迭代
System.out.println(sb);
//map collect
String str1 = Arrays.stream(arr).boxed().map(i -> start+i.toString()+end).collect(Collectors.joining(link));
String str1_1 = Arrays.stream(arr2).map(i -> start+i.toString()+end).collect(Collectors.joining(link));
System.out.println("str1:"+str1);
System.out.println("str1_1:"+str1_1);
//map reduce
String str2 = Arrays.stream(arr).boxed().map(i -> start+i.toString()+end).reduce("/", String::concat);
System.out.println("str2:"+str2);
// 方法引用Object::toString
String str3 = Arrays.stream(arr).boxed().map(Object :: toString).reduce("/", String::concat);
System.out.println("str3:"+str3);
}
————————————————
版权声明:本文为CSDN博主「曼_雨_馨_渼」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hr952909686/article/details/80678316
________________________________________________________________________________________________________________________
Java 8 Stream peek 与 map的区别
刚接触java8 Stream的时候,经常会感觉分不清楚 peek 与 map方法的区别其实了解一下λ表达式就明白了
首先看定义
Stream<T> peek(Consumer<? super T> action); peek方法接收一个Consumer的入参。 了解λ表达式的应该明白 Consumer的实现类 应该只有一个方法,该方法返回类型为void。 Consumer<Integer> c = i -> System.out.println("hello" + i);
而map方法的入参为 Function。 <R> Stream<R> map(Function<? super T, ? extends R> mapper); Function 的 λ表达式 可以这样写 Function<Integer,String> f = x -> {return "hello" + i;};
我们发现Function 比 Consumer 多了一个 return。
这也就是peek 与 map的区别了。
总结:peek接收一个没有返回值的λ表达式,可以做一些输出,外部处理等。map接收一个有返回值的λ表达式,之后Stream的泛型类型将转换为map参数λ表达式返回的类型
文章目录
Collectors.toMap介绍
深入Collectors.toMap
常见的java.lang.IllegalStateException: Duplicate key 问题处理
Collectors.toMap介绍
在真实的业务场景中有很多集合转map的操作,例如 :
@Data public class House { private Integer id; //id private Integer ownerid; //家主编号 private String housename; //家庭名称 private String address; //家庭地址 }
/** * @description: List 转 Map 操作 */ public class ListToMap { public static void main(String[] args) { House house = new House(1,1,"aa","北京海淀"); House house1 = new House(2,2,"bb","湖北武汉"); House house2 = new House(3,3,"cc","浙江杭州"); ArrayList<House> houses = new ArrayList<>(); houses.add(house); houses.add(house1); houses.add(house2); //在实际项目中我们经常会用到 List 转 Map 操作 ->过去是for循环的操作,现在可以学习如下的方法Collectors.toMap /** * 我们收集一下集合中每个对象的两个单独的属性 */ Map<String, String> mapHouse = houses.stream().collect(Collectors.toMap(House::getHousename, House::getAddress)); System.out.println(mapHouse); //{aa=湖北武汉, bb=浙江杭州, cc=北京海淀} /** * 前后的属性的数据类型要对应 一般时间业务中收集带有唯一表示的业务数据 */ Map<Integer, String> map = houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename)); System.out.println(map); //{1=aa, 2=bb, 3=cc} /** * 收集一下属性和对象本身 */ Map<Integer, House> houseMap = houses.stream().collect(Collectors.toMap(House::getOwnerid, o -> o)); Map<Integer, House> houseMap1 = houses.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity())); System.out.println(houseMap); /** * {1=House{id=1, ownerid=1, housename='aa', address='北京海淀'}, * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'}, * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}} */ //业务场景:一般会根据具体的键值 取具体的对象 System.out.println(houseMap.get(1)); //House{id=1, ownerid=1, housename='aa', address='北京海淀'} //此处的效果同houseMap System.out.println(houseMap1); /** * {1=House{id=1, ownerid=1, housename='aa', address='北京海淀'}, * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'}, * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}} */ } }
Java8-Optional.ofNullable使用
public static void main(String[] args) { TestDemo testDemo = new TestDemo(); getCount(testDemo); } private static void getCount(TestDemo testDemo) { //if判断:判断好多层 int count1 = 1; if(testDemo != null){ if(testDemo.getCount() != null){ count1 = testDemo.getCount(); } } System.out.println(count1); //三目运算符:嵌套层数深,可读性不好 int count2 = testDemo != null ? (testDemo.getCount() != null ? testDemo.getCount() : 1) : 1; System.out.println(count2); //Java8-Optional:优雅,可读性较好 int count3 = Optional.ofNullable(testDemo).map(item -> item.getCount()).orElse(1); System.out.println(count3); } private static class TestDemo { private Integer count; public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } }
public static void main(String[] args) {
List<String> list = null;
List<String> newList = Optional.ofNullable(list).orElse(Lists.newArrayList());
newList.forEach(x -> System.out.println(x));
}
1、简单两个List<String> 交、并、差集
/** * 简单类型的处理 */ public static void showSimpleDeal() { List<String> list1 = new ArrayList<>(); list1.add("1111"); list1.add("2222"); list1.add("3333"); List<String> list2 = new ArrayList<>(); list2.add("3333"); list2.add("4444"); Set<String> list1Set = new HashSet<>(list1); Set<String> list2Set = new HashSet<>(list2); // 交集 List<String> intersection = list1.stream().filter(list2Set::contains).collect(Collectors.toList()); System.out.println("---得到交集 intersection---"); intersection.parallelStream().forEach(System.out::println); // 差集 (list1 - list2) List<String> reduce1 = list1.stream().filter(item -> !list2Set.contains(item)).collect(Collectors.toList()); System.out.println("---得到差集 reduce1 (list1 - list2)---"); reduce1.parallelStream().forEach(System.out::println); // 差集 (list2 - list1) List<String> reduce2 = list2.stream().filter(item -> !list1Set.contains(item)).collect(Collectors.toList()); System.out.println("---得到差集 reduce2 (list2 - list1)---"); reduce2.parallelStream().forEach(System.out::println); // 并集 List<String> listAll = list1.parallelStream().collect(Collectors.toList()); List<String> listAll2 = list2.parallelStream().collect(Collectors.toList()); listAll.addAll(listAll2); System.out.println("---得到并集 listAll---"); listAll.parallelStream().forEach(System.out::println); // 去重并集 list1Set.addAll(list2Set); List<String> listDistinctAll = new ArrayList<>(list1Set); System.out.println("---得到去重并集 listDistinctAll---"); listDistinctAll.parallelStream().forEach(System.out::println); System.out.println("---原来的List1---"); list1.parallelStream().forEach(System.out::println); System.out.println("---原来的List2---"); list2.parallelStream().forEach(System.out::println); }
2、List<T> 与List<String>交、差集
static class User { public String name = ""; public int age=0; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public static void main(String[] args) { List<User> list1 = new ArrayList(); User user1=new User(); user1.setName("A运营"); user1.setAge(12); list1.add(user1); User user2=new User(); user2.setName("B运营"); user2.setAge(22); list1.add(user2); User user3=new User(); user3.setName("E运营"); user3.setAge(32); list1.add(user3);; List<String> list2 = new ArrayList(); list2.add("B运营"); list2.add("C运营"); list2.add("D运营"); List<String> nameList= list1.stream().map(User::getName).collect(Collectors.toList()); // 交集 List<User> intersection = list1.stream().filter(item -> list2.contains(item.getName())).collect(Collectors.toList()); System.out.println("---得到交集 intersection---"); //intersection.parallelStream().forEach(System.out::println); for (User user: intersection) { System.out.println(user.getName()); } // 差集 (list1 - list2) List<User> reduceUser1=list1.stream().filter(user -> !list2.contains(user.getName())).collect(Collectors.toList()); System.out.println("---得到差集 reduce1 (list1 - list2)---"); for (User user: reduceUser1) { System.out.println(user.getName()); } //reduceUser1.parallelStream().forEach(System.out::println); // 差集 (list2 - list1) list1.stream().map(user -> user.getName()).collect(Collectors.toList()); List<String> reduce2 = list2.stream().filter(item -> !nameList.contains(item)).collect(Collectors.toList()); System.out.println("---得到差集 reduce2 (list2 - list1)---"); reduce2.parallelStream().forEach(System.out::println); }
3 两个相同类型List<T> 交、并、差集
/** * 对象类型的处理 */ public static void showObjectDeal() { List<User> list1 = new ArrayList<>(); list1.add(new User("name1",11)); list1.add(new User("name2",22)); list1.add(new User("name3",33)); List<User> list2 = new ArrayList<>(); list2.add(new User("name3",33)); list2.add(new User("name4",44)); Set<User> list1Set = new HashSet<>(list1); Set<User> list2Set = new HashSet<>(list2); // 交集 List<User> intersection = list1.stream().filter(list2Set::contains).collect(Collectors.toList()); System.out.println("---得到交集 intersection---"); intersection.parallelStream().forEach(System.out::println); // 差集 (list1 - list2) List<User> reduce1 = list1.stream().filter(item -> !list2Set.contains(item)).collect(Collectors.toList()); System.out.println("---得到差集 reduce1 (list1 - list2)---"); reduce1.parallelStream().forEach(System.out::println); // 差集 (list2 - list1) List<User> reduce2 = list2.stream().filter(item -> !list1Set.contains(item)).collect(Collectors.toList()); System.out.println("---得到差集 reduce2 (list2 - list1)---"); reduce2.parallelStream().forEach(System.out::println); // 并集 List<User> listAll = list1.parallelStream().collect(Collectors.toList()); List<User> listAll2 = list2.parallelStream().collect(Collectors.toList()); listAll.addAll(listAll2); System.out.println("---得到并集 listAll---"); listAll.parallelStream().forEach(System.out::println); // 去重并集 list1Set.addAll(list2Set); List<User> listDistinctAll = new ArrayList<>(list1Set); System.out.println("---得到去重并集 listDistinctAll---"); listDistinctAll.parallelStream().forEach(System.out::println); System.out.println("---原来的List1---"); list1.parallelStream().forEach(System.out::println); System.out.println("---原来的List2---"); list2.parallelStream().forEach(System.out::println); }
4、list去重
//List去重 List<User> userList = list1.stream() .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(user -> user.getName()))), ArrayList::new)); System.out.println("---List去重---"); for (User user: userList) { System.out.println(user.getName()); }
java中给对象的List集合去重的几种方法(Lambda)
https://blog.csdn.net/weixin_42655088/article/details/109305494
Java通过Lambda表达式根据指定字段去除重复数据(集合去重)
https://blog.csdn.net/weixin_45692705/article/details/128144013
//SQL在lambda中如何实现 Select COUNT(employee_id), department_id from employee GROUP BY department_id HAVING COUNT(employee_id) > 1 import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; Map<Long, Long> map = employees.stream() .collect(collectingAndThen(groupingBy(Employee::getDeptId, counting()), m -> { m.values().removeIf(v -> v <= 1L); return m; }));
//SQL在lambda中如何实现Select COUNT(employee_id), department_id from employeeGROUP BY department_idHAVING COUNT(employee_id) > 1
import static java.util.stream.Collectors.collectingAndThen;import static java.util.stream.Collectors.counting;import static java.util.stream.Collectors.groupingBy;Map<Long, Long> map = employees.stream() .collect(collectingAndThen(groupingBy(Employee::getDeptId, counting()), m -> { m.values().removeIf(v -> v <= 1L); return m; }));
______________________________________________________________________________________________________________
【Java 8 新特性】使用Collectors.toList()方法将Map转化成List的示例
https://blog.csdn.net/m0_66557301/article/details/124098350
文章目录
1.使用`Lambda`表达式将`Map`转化成`List`
2.简单`Map`转化成`List`示例
3.用户对象`Map`转化成`List`示例
参考文献
在这个页面上,我们将提供 Java8转换 Map到 List的方法 Collectors.toList()示例。
一个映射有键和值,我们可以将所有键和值作为列表来获取。
如果我们想在一个类属性中设置key和value,然后把这个对象添加到List中,我们可以用java8的一行代码来实现Collectors.toList().
现在让我们看看怎么做。
1.使用Lambda表达式将Map转化成List
在Collectors.toList()方法中使用lambda表达式将Map转换为List,如下示例
List<String> valueList = map.values().stream().collect(Collectors.toList());
如果我们想在放入List之前对值进行排序,我们将按如下方式进行。
List<String> sortedValueList = map.values().stream()
.sorted().collect(Collectors.toList());
我们还可以使用给定的比较器(Comparator.comparing())将Map转换为用户对象List
List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey()))
.map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());
这里的Person是一个用户类。我们也可以使用Map.Entry获取Map的键和值如下。
List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue))
.map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());
作为比较,我们也可以使用Map.Entry.comparingByValue()和Map.Entry.comparingByKey()分别根据值和键对数据进行排序。
List<Person> list = map.entrySet().stream().sorted(Map.Entry.comparingByKey())
.map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());
2.简单Map
转化成List
示例
SimpleMapToList.java
package com.concretepage; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class SimpleMapToList { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(23, "Mahesh"); map.put(10, "Suresh"); map.put(26, "Dinesh"); map.put(11, "Kamlesh"); System.out.println("--Convert Map Values to List--"); List<String> valueList = map.values().stream().collect(Collectors.toList()); valueList.forEach(n -> System.out.println(n)); System.out.println("--Convert Map Values to List using sort--"); List<String> sortedValueList = map.values().stream() .sorted().collect(Collectors.toList()); sortedValueList.forEach(n -> System.out.println(n)); System.out.println("--Convert Map keys to List--"); List<Integer> keyList = map.keySet().stream().collect(Collectors.toList()); keyList.forEach(n -> System.out.println(n)); System.out.println("--Convert Map keys to List using sort--"); List<Integer> sortedKeyList = map.keySet().stream() .sorted().collect(Collectors.toList()); sortedKeyList.forEach(n -> System.out.println(n)); } }
输出
--Convert Map Values to List-- Mahesh Suresh Dinesh Kamlesh --Convert Map Values to List using sort-- Dinesh Kamlesh Mahesh Suresh --Convert Map keys to List-- 23 10 26 11 --Convert Map keys to List using sort-- 10 11 23 26
3.用户对象Map
转化成List
示例
MapToListOfUserObject.java
package com.concretepage; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MapToListOfUserObject { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(23, "Mahesh"); map.put(10, "Suresh"); map.put(26, "Dinesh"); map.put(11, "Kamlesh"); List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())) .map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList()); list.forEach(l -> System.out.println("Id: "+ l.getId()+", Name: "+ l.getName())); } }
Person.java
package com.concretepage; public class Person { private Integer id; private String name; public Person(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public String getName() { return name; } } 输出 Id: 10, Name: Suresh Id: 11, Name: Kamlesh Id: 23, Name: Mahesh Id: 26, Name: Dinesh 如果我们需要按键来排序的话,我们可以使用键来排序 Comparator.comparing(e -> e.getValue()) 然后输出如下。 Id: 26, Name: Dinesh Id: 11, Name: Kamlesh Id: 23, Name: Mahesh Id: 10, Name: Suresh 参考文献 【1】Java 8 Convert Map to List using Collectors.toList() Example