java8遍历map使用foreach遍历,map.foreach((k,v)->XXXX)
一: 实现Runnable线程案例
使用() -> {} 替代匿名类:
java8之前:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8 ");
}
}).start();
java8之后:
new Thread( () -> System.out.println("In Java8!") ).start();
类名::方法名的引用:
例如
表达式:
person -> person.getAge();
可以替换成
Person::getAge
表达式
() -> new HashMap<>();
可以替换成
HashMap::new
这种[方法引用]或者说[双冒号运算]对应的参数类型是Function<T,R> T表示传入类型,R表示返回类型。比如表达式person -> person.getAge(); 传入参数是person,返回值是person.getAge(),那么方法引用Person::getAge就对应着Function<Person,Integer>类型。
下面这段代码,进行的操作是,把List<String>里面的String全部大写并返还新的ArrayList<String>,在前面的例子中我们是这么写的:
List<String> collected = new ArrayList<();
collected.add("alpha");
collected.add("beta");
collected = collected.stream().map(str-> str.toUpperCase()).collect(Collectors.toList());
collected = collected.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));//注意发生的变化
str->str.toUpperCase()等同于String::toUpperCase //前面为传入的参数类型,后面表示返回值。
Java8中的Function:
Function接口为函数式接口(函数式接口就是只能有一个抽象方法)此注解跟@override类似,仅仅作为一个提示和编译检查的作用,也可以省略不写 R apply(T t); //将Function对象应用到输入的参数上,然后返回计算结果。
compose 和 andThen 的不同之处是函数执行的顺序不同。compose 函数先执行参数,然后执行调用者,而 andThen 先执行调用者,然后再执行参数。
//andThen返回一个先执行当前函数对象apply方法再执行after函数对象apply方法的函数对象。
//compose返回一个先执行before函数对象apply方法再执行当前函数对象apply方法的函数对象
Function< T, R >接收T对象,返回R对象
Function<Integer, Integer> name = e -> e * 2;
Function<Integer, Integer> square = e -> e * e;
int value = name.andThen(square).apply(3); //andThen value=36
System.out.println("andThen value=" + value);
int value2 = name.compose(square).apply(3);
System.out.println("compose value2=" + value2);
//返回一个执行了apply()方法之后只会返回输入参数的函数对象
Object identity = Function.identity().apply("huohuo");
System.out.println(identity);
二:使用Lambda表达式遍历List集合
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
java8之前:
for (String feature : features) {
System.out.println(feature);
}
java8之后:n代表要循环迭代的元素
features.forEach(n -> System.out.println(n));
features.forEach(System.out::println); //方法引用是使用两个冒号::这个操作符号。
三:使用Lambda表达式和函数接口,利用filter进行过滤
为了支持函数编程,Java 8加入了一个新的包java.util.function,其中有一个接口java.util.function.Predicate是支持Lambda函数编程:
Stream API 的filter方法能够接受 Predicate参数, 能够允许测试多个条件;
List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
languages.stream().filter(item->item.startWith("J")).forEach((item)->System.out.println(item);)
四: 复杂的结合Predicate 使用,java.util.function.Predicate提供and(), or() 和 xor()可以进行逻辑操作,比如为了得到一串字符串中以"J"开头的4个长度:
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
languages.stream().filter(startsWithJ.and(fourLetterLong)).forEach((item)->System.out.println(item);)
languages.stream().filter(item->item.startWith("J").and(item->item.length()==4)).forEach((item)->System.out.println(item);)
languages.stream().allMatch(item->item.startWith("J"))
五:使用Lambda实现Map 和 Reduce
最流行的函数编程概念是map,它允许你改变你的对象,在这个案例中,我们将costBeforeTeax集合中每个元素改变了增加一定的数值,我们将Lambda表达式 x -> x*x传送map()方法,这将应用到stream中所有元素。然后我们使用 forEach() 打印出这个集合的元素. 通过map可以修改需要迭代的元素类型,通过Reduce是将集合中所有值结合在一个里面。reduce 操作可以实现从Stream中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。
reduce() 函数可以将所有值合并成一个,因为其功能,reduce 又被称为折叠操作
reduce() 是将集合中所有值结合进一个,Reduce类似SQL语句中的sum(), avg() 或count(),
Map阶段:对集合中的元素进行操作
Reduce阶段:将上一步得到的结果进行合并得到最终的结果
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + 0.12*cost).forEach(System.out::println);
java8之前使用循环求和
for (Integer cost :costBeforeTax) {
double price = cost + 0.12*cost;
total = total + price;
}
java8之后
double bill = costBeforeTax.stream().map((cost) -> cost + 0.12*cost).reduce((sum, cost) -> sum + cost).get();
六:通过filtering 创建一个字符串String的集合,将迭代之后的结果通过collect收集起来:parallelStream是并行流
Filtering是对大型Collection操作的一个通用操作,Stream提供filter()方法,接受一个Predicate对象,意味着你能传送lambda表达式作为一个过滤逻辑进入这个方法:
List<String> filtered = strList.stream().filter(x -> x.length()> 2) //将结果收集为一个集合
.collect(Collectors.toList());
Map<String,String> filtered = strList.stream().filter(x -> x.length()> 2) //将结果收集为一个HashMap集合
.collect(Collectors.toMap(item->item.getId(),item->item));
String G7Countries = G7.stream().map(x -> x.toUpperCase()) //通过Collectors.joining()将结果用,拼接为一个字符串
.collect(Collectors.joining(", "));
List<Integer> distinct = numbers.stream().map( i -> i*i).distinct() //通过distinct进行过滤掉迭代中重复的值
.collect(Collectors.toList());
计算List中的元素的最大值,最小值,总和及平均值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x)
.summaryStatistics();
stats.getMax()获取最大值29 stats.getMin()获取最小值2 stats.getSum() 获取总和129 stats.getAverage()获取平均数12.9
七:并行流在从stream和parallelStream方法中进行选择时,需要考虑以下几个问题:
并行的速度是串行的三四倍
是否需要并行?
任务之间是否是独立的?是否会引起任何竞态条件?
结果是否取决于任务的调用顺序?
如果任务之间是独立的,并且代码中不涉及到对同一个对象的某个状态或者某个变量的更新操作,那么就表明代码是可以被并行化的。
当任务涉及到I/O操作并且任务之间不互相依赖时,那么并行化就是一个不错的选择
八:比较器Comparator的使用集合的排序
public class User(){
private String name;
private int age;
//get set 方法
}
List<User> Users =new ArrayList<User>();
User.sort(Comparator.comparingInt(Users::getId).reversed());//按照倒序排序
Users.sort((User user1, User user2)->user1.getAge()-user2.getAge());//按照age年龄大小升序排列 有return时需要带上{}表示一个整体
Users.sort((user1, user2)->{ //也是按照age年龄大小升序排列 有return时需要带上{}表示一个整体
int age1=left.getAge();
int age2=right.getAge();
if(age1==age2){
String name1=left.getName();
String name2=right.getName();
if(name1.length()>name2.length()){
return 1;
}else{
return -1;
}
return 0;
}else {
return age1-age2;
}
});
Collections.sort(Users, (left, right) -> {
int age1=left.getAge();
int age2=right.getAge();
if(age1==age2){
String name1=left.getName();
String name2=right.getName();
if(name1.length()>name2.length()){
return 1; //如果返回值大于0两个值就交换顺序
}else{
return -1;
}
return 0;
}else {
return age1-age2; //如果返回值大于0两个值就交换顺序 如果return age2-age1就是降序
}
List<String> names=Arrays.aslist("b","d","c","a");
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}
Comparator<User> c = Comparator.comparingInt(User::getAge()) .thenComparing(User::getName).reversed();
reversed()代表逆序排序
或者用:
Comparator<User> c = (l, r)-> ArrayUtils.compareIntArrays(l.getAge(), r.getAge());
Arrays.sort(Users,c);
map与flatMap的比较:
map:对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。
flatMap:每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中
map中迭代的还是一个元素只是属性发生了改变但是改变之后的还是单个,flatMap迭代之后将一个元素转换成多个元素,相当于之前的每个元素都是一个新的流。
map只能单一转换,单一只的是只能一对一进行转换,指一个对象可以转化为另一个对象但是不能转换成对象数组(map返回结果集不能直接使用from/just再次进行事件分发,一旦转换成对象数组的话,再处理集合/数组的结果时需要利用for一一遍历取出,而使用RxJava就是为了剔除这样的嵌套结构,使得整体的逻辑性更强。)
flatmap既可以单一转换也可以一对多/多对多转换,flatmap要求返回Observable,因此可以再内部进行from/just的再次事件分发,一一取出单一对象(转换对象的能力不同)
map返回的是结果集,flatmap返回的是包含结果集的Observable
map函数的用法,顾名思义,将一个函数传入map中,然后利用传入的这个函数,将集合中的每个元素处理,并将处理后的结果返回。而flatMap与map唯一不一样的地方就是传入的函数在处理完后返回值必须是List,其实这也不难理解,既然是flatMap,那除了map以外必然还有flat的操作,所以需要返回值是List才能执行flat这一步。,flatMap往往是在map之后使用的。
String[] strings = {"Hello", "World"};
List stringList = Arrays.asList(strings).stream().
map(str -> str.split("")).
flatMap(str -> Arrays.stream(str))
.collect(Collectors.toList());
下面这个和这个的功能是一样的:如果要对flatMap之后的流进行操作则需要用map再进行迭代。
List stringList = Arrays.asList(strings).stream().
map(str -> str.split("")).
flatMap(str -> Arrays.asList(str).stream()).map(item->"ni"+item)
.collect(Collectors.toList());
System.out.println(Arrays.toString(stringList.toArray()));