台州网站seo外包,黑龙江省城乡建设厅网站首页,4500急招一位接送小孩阿姨附近,网站建设 维护 运营情况报告分享一波:程序员赚外快-必看的巅峰干货
介绍
随着java的发展#xff0c;越来越多的企业开始使用 java8 版本。Java8 是自 java5之后最重要的版本#xff0c;这个版本包含语言、编译器、库、工具、JVM等方面的十多个新特性。本次课程将着重学习其中的一些重点特性。
Jdk8新…分享一波:程序员赚外快-必看的巅峰干货
介绍
随着java的发展越来越多的企业开始使用 java8 版本。Java8 是自 java5之后最重要的版本这个版本包含语言、编译器、库、工具、JVM等方面的十多个新特性。本次课程将着重学习其中的一些重点特性。
Jdk8新增的特性如下
Lambda表达式 类似于ES6中的箭头函数
新的日期API Datetime
引入Optional 防止空指针异常
使用Base64
接口的默认方法和静态方法
新增方法引用格式
新增Stream类
注解相关的改变
支持并行parallel数组
对并发类Concurrency的扩展。
JavaFX接口新特性 接口默认方法
当我们去实现某个框架提供的一个接口时需要实现其所有的抽象方法当该框架更新版本在这个借口中加入了新的抽象方法时我们就需要对项目重新编译并且实现其新增的方法。
当实现类太多时操作起来很麻烦。
JDK之前是使用开闭设计模式对扩展开放对修改关闭。即创建一个新的接口继承原有的接口定义新的方法。
但是这样的话原本的那些实现类并没有新的方法
这时候可以使用接口默认方法
关键字使用default进行修饰 方法需要方法体。这样的方法所有的子类会默认实现不用自己写如果想要覆盖重写也可以在实现类中覆盖重写
/** 从java8开始接口当中允许定义default默认方法 修饰符public default(public可以省略default不能省略) */ public interface MyInterface { void method1(); void method2(); default void methodNew() { System.out.println(“接口默认方法执行”); }
}
这里需要注意的是这里的default是jdk8新增的关键字和访问限定修饰符“default”不是一个概念与switch中的default功能完全不同.
与抽象类的不同抽象类更多的是提供一个模板子类之间的某个流程大致相同仅仅是某个步骤可能不一样模板方法设计模式这个时候使用抽象类该步骤定义为抽象方法。而default关键字是用于扩展 接口静态方法
/** 从java8开始接口当中允许定义静态方法 修饰符static xxx 一般类的静态方法用法相同 */ public interface Animal { void eat(); static Animal getAnimal() { return new Cat(); } }
接口的静态方法不会被实现类所继承 函数式接口 概念
函数式接口在Java中是指有且仅有一个抽象方法的接口。
函数式接口即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法Java中的Lambda才能顺利地进行推导。 格式
确保接口中有且只有一个抽象方法即可
Public interface 接口名称 { 返回值 方法名称(); }
FunctionalInterface注解
有的注解是在编译期起作用如Override注解。而FunctionalInterface也是在编译期起作用。该注解是java8专门为函数式接口引入的新的注解作用于一个接口上。
一旦使用该注解来定义接口编译期会强制检查该接口是否符合函数式接口的条件不符合则会报错。需要注意的是即使不使用该注解只要满足函数式接口的定义这就是一个函数式接口。
FunctionalInterface public interface MyFunctionalInterface { void myMethod(); }
自定义函数式接口
public class DemoFunctionalInterface { // 使用自定义的函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {inter.myMethod();
}public static void main(String[] args) {// 调用使用函数式接口的方法doSomething(() - System.out.println(乌鸦坐飞机));
}}
Lambda表达式
在面向对象的基础上java8 通过Lambda表达式与方法引用等为开发者打开了函数式编程的大门。Lambda表达式不是语法糖而是新的语法 语法
三要素参数、箭头、代码
(参数类型 参数1, 参数类型 参数2…) - {代码}
如果参数有多个那么使用逗号分隔。如果参数没有则留空
箭头是固定写法
大括号相当于方法体。使用Lambda表达式的必要前提必须是函数式接口 Lambda 省略规则
参数类型可以省略。但是只能同时省略所有参数的类型或者干脆都不省略。
如果参数有且仅有一个那么小括号可以省略。
如果大括号内的语句有且仅有一条那么无论是否有返回值return、大括号、分号都可以省略Lambda的延迟执行
有些场景的代码执行后结果不一定会被使用从而造成性能浪费。而Lambda表达式是延迟执行的这正好可以作为解决方案提升性能。 性能浪费的案例
public class Demo01Logger { private static void log(int level, String msg) { if (level 1) { System.out.println(msg); } }
public static void main(String[] args) {String msgA Hello;String msgB World;String msgC Java;log(1, msgA msgB msgC);
}}
这段代码存在问题无论级别是否满足要求作为 log 方法的第二个参数三个字符串一定会首先被拼接并传入方法内然后才会进行级别判断。如果级别不符合要求那么字符串的拼接操作就白做了存在性能浪费。
Lambda的优化写法
FunctionalInterface public interface MessageBuilder { String buildMessage(); } public class Demo02LoggerLambda { private static void log(int level, MessageBuilder builder) { if (level 1) { System.out.println(builder.buildMessage()); } }
public static void main(String[] args) {String msgA Hello;String msgB World;String msgC Java;log(1, () - msgA msgB msgC );
}}
这样一来只有当满足条件的时候才会进行三个字符串的拼接。否则不会拼接。
证明Lambda的延迟
public class Demo03LoggerDelay { private static void log(int level, MessageBuilder builder) { if (level 1) { System.out.println(builder.buildMessage()); } }
public static void main(String[] args) {String msgA Hello;String msgB World;String msgC Java;log(2, () - {System.out.println(Lambda执行);return msgA msgB msgC;});
}}
从结果可以看出在不符合要求的情况下lambda将不会执行 使用Lambda作为参数和返回值
如果抛开实现原理不说Java中的Lambda表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数式接口类型那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数其实就是使用函数式接口作为方法参数。
例如 java.lang.Runnable 接口就是一个函数式接口假设有一个 startThread 方法使用该接口作为参数那么就可以使用Lambda进行传参。这种情况其实和 Thread 类的构造方法参数为 Runnable 没有本质区别。
public class Demo04Runnable { private static void startThread(Runnable task) { new Thread(task).start(); }
public static void main(String[] args) {startThread(() - System.out.println(线程任务执行));
}}
类似地如果一个方法的返回值类型是一个函数式接口那么就可以直接返回一个Lambda表达式。当需要通过一个方法来获取一个 java.util.Comparator 接口类型的对象作为排序器时,就可以调该方法获取
public class Demo06Comparator { private static Comparator newComparator() { return (a, b) - b.length() - a.length(); }
public static void main(String[] args) {String[] array {abc, ab, abcd};System.out.println(Arrays.toString(array));Arrays.sort(array, newComparator());System.out.println(Arrays.toString(array));
}}
常用函数式接口
JDK提供了大量的函数式接口以及丰富的Lambda应用场景。下面是最简单的几个接口以及使用实例
Supplier
java.util.function.Supplier 接口仅包含一个无参的方法 T get() 。用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
public class Demo08Supplier { private static String getString(Supplier function) { return function.get(); }
public static void main(String[] args) {String msgA Hello;String msgB World;System.out.println(getString(() - msgA msgB));
}}
练习求数组元素的最小值
public class Demo02Test { //定一个方法,方法的参数传递Supplier,泛型使用Integer public static int getMax(Supplier sup) { return sup.get(); }
public static void main(String[] args) {int arr[] {2, 3, 4, 52, 333, 23};//调用getMax方法,参数传递Lambda int maxNum getMax(() - {//计算数组的最大值 int max arr[0];for (int i : arr) {if (i max) {max i;}}return max;});System.out.println(maxNum);
}}
Consumer接口
java.util.function.Consumer 接口则正好与Supplier接口相反它不是生产一个数据而是消费一个数据
其数据类型由泛型决定。
抽象方法accept意为消费一个指定泛型的数据
public class Demo09Consumer { private static void consumeString(Consumer function) { function.accept(“Hello”); }
public static void main(String[] args) {consumeString(s - System.out.println(s));
}}
默认方法andThen
如果一个方法的参数和返回值全都是 Consumer 类型那么就可以实现效果消费数据的时候首先做一个操作然后再做一个操作实现组合。而这个方法就是 Consumer 接口中的default方法 andThen
要想实现组合需要两个或多个Lambda表达式即可而 andThen 的语义正是“一步接一步”操作。例如两个步骤组合的情况
public class Demo10ConsumerAndThen { private static void consumeString(Consumer one, Consumer two) { one.andThen(two).accept(“Hello”); }
public static void main(String[] args) {consumeString(s - System.out.println(s.toUpperCase()), s - System.out.println(s.toLowerCase()));
}}
练习格式化打印信息
下面的字符串数组当中存有多条信息请按照格式“ 姓名XX。性别XX。 ”的格式将信息打印出来。要求将打印姓名的动作作为第一个 Consumer 接口的Lambda实例将打印性别的动作作为第二个 Consumer 接口的Lambda实例将两个 Consumer 接口按照顺序“拼接”到一起。
public class DemoConsumer { public static void main(String[] args) { String[] array {“迪丽热巴,女”, “古力娜扎,女”, “马尔扎哈,男”}; printInfo(s - System.out.print(“姓名” s.split(,)[0]), s - System.out.println(。性别 s.split(,)[1] “。”), array); }
private static void printInfo(ConsumerString one, ConsumerString two, String[] array) {for (String info : array) {one.andThen(two).accept(info); // 姓名迪丽热巴。性别女。 }
}}
Predicate接口
有时候我们需要对某种类型的数据进行判断从而得到一个boolean值结果。这时可以使用java.util.function.Predicate 接口。
抽象方法test
Predicate 接口中包含一个抽象方法 boolean test(T t) 。用于条件判断的场景
public class Demo15PredicateTest { private static void method(Predicate predicate) { boolean veryLong predicate.test(“HelloWorld”); System.out.println(“字符串很长吗” veryLong); }
public static void main(String[] args) {method(s - s.length() 5);
}}
条件判断的标准是传入lambda表达式逻辑
默认方法and
既然是条件判断就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时可以使用default方法 and
如果要判断一个字符串既要包含大写“H”又要包含大写“W”
public class Demo16PredicateAnd { private static void method(Predicate one, Predicate two) { boolean isValid one.and(two).test(“Helloworld”); System.out.println(“字符串符合要求吗” isValid); }
public static void main(String[] args) {method(s - s.contains(H), s - s.contains(W));
}}
默认方法or
如果希望实现逻辑“字符串包含大写H或者包含大写W”那么代码只需要将“and”修改为“or”名称即可其他都不变
默认方法negate
表示取反
public class Demo17PredicateNegate { private static void method(Predicate predicate) { boolean veryLong predicate.negate().test(“HelloWorld”); System.out.println(“字符串很长吗” veryLong); }
public static void main(String[] args) {method(s - s.length() 5);
}}
练习集合信息筛选
数组当中有多条“姓名性别”的信息如下请通过 Predicate 接口的拼装将符合要求的字符串筛选到集合ArrayList 中需要同时满足两个条件 必须为女生 姓名为4个字。
public class DemoPredicate { public static void main(String[] args) { String[] array {“迪丽热巴,女”, “古力娜扎,女”, “马尔扎哈,男”, “赵丽颖,女”}; List list filter(array, s - “女”.equals(s.split(,)[1]), s - s.split(,)[0].length() 4); System.out.println(list); }
private static ListString filter(String[] array, PredicateString one, PredicateString two) {ListString list new ArrayList();for (String info : array) {if (one.and(two).test(info)) {list.add(info);}}return list;
}}
Function接口
java.util.function.FunctionT,R 接口用来根据一个类型的数据得到另一个类型的数据前者称为前置条件后者称为后置条件。
抽象方法apply
Function 接口中最主要的抽象方法为 R apply(T t) 根据类型T的参数获取类型R的结果。使用的场景例如将 String 类型转换为 Integer 类型
public class Demo11FunctionApply { private static void method(FunctionString, Integer function) { int num function.apply(“10”); System.out.println(num 20); }
public static void main(String[] args) {method(s - Integer.parseInt(s));
}}
默认方法andThen
public class Demo12FunctionAndThen { private static void method(FunctionString, Integer one, FunctionInteger, Integer two) { int num one.andThen(two).apply(“10”); System.out.println(num 20); }
public static void main(String[] args) {method(str - Integer.parseInt(str) 10, i - i * 10);
}}
练习自定义函数模型拼接
请使用 Function 进行函数模型的拼接按照顺序需要执行的多个函数操作为
String str “赵丽颖,20”; 将字符串截取数字年龄部分得到字符串 将上一步的字符串转换成为int类型的数字 将上一步的int数字累加100得到结果int数字。
public class DemoFunction { public static void main(String[] args) { String str “赵丽颖,20”; int age getAgeNum(str, s - s.split(,)[1], s - Integer.parseInt(s), n - n 100); System.out.println(age); }
private static int getAgeNum(String str, FunctionString, String one, FunctionString, Integer two, FunctionInteger, Integer three) {return one.andThen(two).andThen(three).apply(str);
}}
方法引用 冗余的Lambda场景
在使用Lambda表达式的时候我们实际上传递进去的代码就是一种解决方案拿什么参数做什么操作。那么考虑一种情况如果我们在Lambda中所指定的操作方案已经有地方存在相同方案那是否还有必要再写重复逻辑
先看一个简单的函数式接口
FunctionalInterface public interface Printable { void print(String str); }
public class Demo01PrintSimple { private static void printString(Printable data) { data.print(“Hello, World!”); }
public static void main(String[] args) {printString(s - System.out.println(s));
}}
其中 printString 方法只管调用 Printable 接口的 print 方法而并不管 print 方法的具体实现逻辑会将字符串打印到什么地方去。而 main 方法通过Lambda表达式指定了函数式接口 Printable 的具体操作方案为拿到String类型可推导所以可省略数据后在控制台中输出它。 问题分析
这段代码的问题在于对字符串进行控制台打印输出的操作方案明明已经有了现成的实现那就是 System.out对象中的 println(String) 方法。既然Lambda希望做的事情就是调用println(String) 方法那何必自己手动调用呢
能否省去Lambda的语法格式尽管它已经相当简洁呢只要“引用”过去就好了
public class Demo02PrintRef { private static void printString(Printable data) { data.print(“Hello, World!”); }
public static void main(String[] args) {printString(System.out::println);
}}
请注意其中的双冒号 :: 写法这被称为“方法引用”而双冒号是一种新的语法。 方法引用符
双冒号 :: 为引用运算符而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中那么则可以通过双冒号来引用该方法作为Lambda的替代者。
语义分析
例如上例中 System.out 对象中有一个重载的 println(String) 方法恰好就是我们所需要的。那么对printString 方法的函数式接口参数对比下面两种写法完全等效
Lambda表达式写法 s - System.out.println(s);
方法引用写法 System.out::println第一种语义是指拿到参数之后经Lambda之手继而传递给 System.out.println 方法去处理。
第二种等效写法的语义是指直接让 System.out 中的 println 方法来取代Lambda。两种写法的执行效果完全一样而第二种方法引用的写法复用了已有方案更加简洁。
注:Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常
推导与省略
如果使用Lambda那么根据“可推导就是可省略”的原则无需指定参数类型也无需指定的重载形式——它们都将被自动推导。而如果使用方法引用也是同样可以根据上下文进行推导。
函数式接口是Lambda的基础而方法引用是Lambda的孪生兄弟。
下面这段代码将会调用 println 方法的不同重载形式将函数式接口改为int类型的参数
FunctionalInterface public interface PrintableInteger { void print(int str); }
由于上下文变了之后可以自动推导出唯一对应的匹配重载所以方法引用没有任何变化
public class Demo03PrintOverload { private static void printInteger(PrintableInteger data) { data.print(1024); }
public static void main(String[] args) {printInteger(System.out::println);
}}
通过对象名引用成员方法
这是最常见的一种用法与上例相同。如果一个类中已经存在了一个成员方法
public class MethodRefObject { public void printUpperCase(String str) { System.out.println(str.toUpperCase()); } }
那么当需要使用这个 printUpperCase 成员方法来替代 Printable 接口的Lambda的时候已经具有了MethodRefObject 类的对象实例则可以通过对象名引用成员方法代码为
public class Demo04MethodRef { private static void printString(Printable lambda) { lambda.print(“Hello”); }
public static void main(String[] args) {MethodRefObject obj new MethodRefObject();printString(obj::printUpperCase);
}}
通过类名称引用静态方法
由于在 java.lang.Math 类中已经存在了静态方法 abs 所以当我们需要通过Lambda来调用该方法时有两种写法。首先是函数式接口
FunctionalInterface public interface Calcable { int calc(int num); }
第一种写法使用Lambda
public class Demo05Lambda { private static void method(int num, Calcable lambda) { System.out.println(lambda.calc(num)); }
public static void main(String[] args) {method(-10, n - Math.abs(n));
}}
第二种使用方法引用
public class Demo06MethodRef { private static void method(int num, Calcable lambda) { System.out.println(lambda.calc(num)); }
public static void main(String[] args) {method(-10, Math::abs);
}}
两种方式等价 通过super引用成员方法
如果存在继承关系当Lambda中需要出现super调用时也可以使用方法引用进行替代。首先是函数式接口
FunctionalInterface public interface Greetable { void greet(); }
父类Human的内容
public class Human { public void sayHello() { System.out.println(“Hello!”); } }
子类Man的内容
public class Man extends Human { Override public void sayHello() { System.out.println(“大家好,我是Man!”); }
//定义方法method,参数传递Greetable接口
public void method(Greetable g) {g.greet();
}public void show() {//调用method方法,使用Lambda表达式 method(() - {//创建Human对象,调用sayHello方法 new Human().sayHello();});//简化Lambda method(() - new Human().sayHello());//使用super关键字代替父类对象 method(() - super.sayHello());
}}
但是如果使用方法引用会更好
public class Woman extends Human { Override public void sayHello() { System.out.println(“大家好,我是Man!”); }
public void method(Greetable g) {g.greet();
}public void show() {method(super::sayHello);
}}
通过this引用成员方法
this代表当前对象如果需要引用的方法就是当前类中的成员方法那么可以使用“this::成员方法”的格式来使用方法引用。首先是简单的函数式接口
FunctionalInterface public interface Richable { void buy(); }
public class Husband { private void marry(Richable lambda) { lambda.buy(); }
public void beHappy() {marry(() - System.out.println(买套房子));
}}
开心方法 beHappy 调用了结婚方法 marry 后者的参数为函数式接口 Richable 所以需要一个Lambda表达式。但是如果这个Lambda表达式的内容已经在本类当中存在了则可以对 Husband 丈夫类进行修改
public class Husband { private void buyHouse() { System.out.println(“买套房子”); }
private void marry(Richable lambda) {lambda.buy();
}public void beHappy() {marry(this::buyHouse);
}}
Stream流
说到Stream便容易想到I/O Stream而实际上在Java 8中得益于Lambda所带来的函数式编程引入了一个全新的Stream概念用于解决已有集合类库既有的弊端。
Stream流式操作性能比传统的For循环要低就性能而言传统的for循环最高 传统集合的遍历代码
几乎所有的集合如 Collection 接口或 Map 接口等都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候除了必需的添加、删除、获取外最典型的就是集合遍历。例如
public class Demo01ForEach { public static void main(String[] args) { List list new ArrayList(); list.add(“张无忌”); list.add(“周芷若”); list.add(“赵敏”); list.add(“张强”); list.add(“张三丰”); for (String name : list) { System.out.println(name); } } }
循环遍历的弊端
Java 8的Lambda让我们可以更加专注于做什么What而不是怎么做How这点此前已经结合内部类进行了对比说明。现在我们仔细体会一下上例代码可以发现
for循环的语法就是“怎么做”
for循环的循环体才是“做什么”为什么使用循环因为要进行遍历。但循环是遍历的唯一方式吗遍历是指每一个元素逐一进行处理而并不是从第一个到最后一个顺次处理的循环。前者是目的后者是方式。
试想一下如果希望对集合中的元素进行筛选过滤
将集合A根据条件一过滤为子集B
然后再根据条件二过滤为子集C。那怎么办在Java 8之前的做法可能为
public class Demo02NormalFilter { public static void main(String[] args) { List list new ArrayList(); list.add(“张无忌”); list.add(“周芷若”); list.add(“赵敏”); list.add(“张强”); list.add(“张三丰”); List zhangList new ArrayList(); for (String name : list) { if (name.startsWith(“张”)) { zhangList.add(name); } } List shortList new ArrayList(); for (String name : zhangList) { if (name.length() 3) { shortList.add(name); } } for (String name : shortList) { System.out.println(name); } } }
这段代码中含有三个循环每一个作用不同 首先筛选所有姓张的人 然后筛选名字有三个字的人 最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候总是需要进行循环、循环、再循环。这是理所当然的么不是。循环是做事情的方式而不是目的。另一方面使用线性循环就意味着只能遍历一次。如果希望再次遍历只能再使用另一个循环从头开始。
那Lambda的衍生物Stream能给我们带来怎样更加优雅的写法呢 Stream更优写法
public class Demo03StreamFilter { public static void main(String[] args) { List list new ArrayList(); list.add(“张无忌”); list.add(“周芷若”); list.add(“赵敏”); list.add(“张强”); list.add(“张三丰”); list.stream().filter(s - s.startsWith(“张”)) .filter(s - s.length() 3) .forEach(System.out::println); } }
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义获取流、过滤姓张、过滤长度为3、逐一打印。代码中并没有体现使用线性循环或是其他任何算法进行遍历我们真正要做的事情内容被更好地体现在代码中。 获取流
java.util.stream.Stream 是Java 8新加入的最常用的流接口。这并不是一个函数式接口。
获取一个流非常简单有以下几种常用的方式
所有的 Collection 集合都可以通过 stream 默认方法获取流
Stream 接口的静态方法 of 可以获取数组对应的流。根据Collection获取流
首先 java.util.Collection 接口中加入了default方法 stream 用来获取流所以其所有实现类均可获取流。
public class Demo04GetStream { public static void main(String[] args) { List list new ArrayList(); Stream stream1 list.stream(); Set set new HashSet(); Stream stream2 set.stream(); } }
根据Map获取流
java.util.Map 接口不是 Collection 的子接口且其K-V数据结构不符合流元素的单一特征所以获取对应的流
需要分key、value或entry等情况
public class Demo05GetStream { public static void main(String[] args) { MapString, String map new HashMap(); Stream keyStream map.keySet().stream(); Stream valueStream map.values().stream(); StreamMap.EntryString, String entryStream map.entrySet().stream(); } }
根据数组获取流
如果使用的不是集合或映射而是数组由于数组对象不可能添加默认方法所以 Stream 接口中提供了静态方法
of 使用很简单
public class Demo06GetStream { public static void main(String[] args) { String[] array {“张无忌”, “张翠山”, “张三丰”, “张一元”}; Stream stream Stream.of(array); } }
常用方法 逐一处理forEach
虽然方法名字叫forEach但是与for循环不同
基本使用
public class Demo12StreamForEach { public static void main(String[] args) { Stream stream Stream.of(“张无忌”, “张三丰”, “周芷若”); stream.forEach(name - System.out.println(name)); } }
过滤filter
可以通过 filter 方法将一个流转换成另一个子集流
public class Demo07StreamFilter { public static void main(String[] args) { Stream original Stream.of(“张无忌”, “张三丰”, “周芷若”); Stream result original.filter(s - s.startsWith(“张”)); } }
在这里通过Lambda表达式来指定了筛选的条件必须姓张。 映射map
如果需要将流中的元素映射到另一个流中可以使用 map 方法。方法签名
public class Demo08StreamMap { public static void main(String[] args) { Stream original Stream.of(“10”, “12”, “18”); Stream result original.map(str - Integer.parseInt(str)); } }
这段代码中 map 方法的参数通过方法引用将字符串类型转换成为了int类型并自动装箱为 Integer 类对象。 统计个数count
public class Demo09StreamCount { public static void main(String[] args) { Stream original Stream.of(“张无忌”, “张三丰”, “周芷若”); Stream result original.filter(s - s.startsWith(“张”)); System.out.println(result.count()); } }
取用前几个limit
public class Demo10StreamLimit { public static void main(String[] args) { Stream original Stream.of(“张无忌”, “张三丰”, “周芷若”); Stream result original.limit(2); System.out.println(result.count()); } }
跳过前几个skip
public class Demo11StreamSkip { public static void main(String[] args) { Stream original Stream.of(“张无忌”, “张三丰”, “周芷若”); Stream result original.skip(2); System.out.println(result.count()); } }
组合concat
如果有两个流希望合并成为一个流那么可以使用 Stream 接口的静态方法 concat
public class Demo12StreamConcat { public static void main(String[] args) { Stream streamA Stream.of(“张无忌”); Stream streamB Stream.of(“张翠山”); Stream result Stream.concat(streamA, streamB); } }
练习集合元素处理传统方式
现在有两个 ArrayList 集合存储队伍当中的多个成员姓名要求使用传统的for循环或增强for循环依次进行以下若干操作步骤 第一个队伍只要名字为3个字的成员姓名存储到一个新集合中。 第一个队伍筛选之后只要前3个人存储到一个新集合中。 第二个队伍只要姓张的成员姓名存储到一个新集合中。 第二个队伍筛选之后不要前2个人存储到一个新集合中。 将两个队伍合并为一个队伍存储到一个新集合中。 根据姓名创建 Person 对象存储到一个新集合中。 打印整个队伍的Person对象信息。
代码如下
public class DemoArrayListNames { public static void main(String[] args) { ArrayList one new ArrayList(); one.add(“迪丽热巴”); one.add(“宋远桥”); one.add(“苏星河”); one.add(“石破天”); one.add(“石中玉”); one.add(“老子”); one.add(“庄子”); one.add(“洪七公”); ArrayList two new ArrayList(); two.add(“古力娜扎”); two.add(“张无忌”); two.add(“赵丽颖”); two.add(“张三丰”); two.add(“尼古拉斯赵四”); two.add(“张天爱”); two.add(“张二狗”); // 第一个队伍只要名字为3个字的成员姓名ListString oneA new ArrayList();for (String name : one) {if (name.length() 3) {oneA.add(name);}}// 第一个队伍筛选之后只要前3个人 ListString oneB new ArrayList();for (int i 0; i 3; i) {oneB.add(oneA.get(i));}// 第二个队伍只要姓张的成员姓名 ListString twoA new ArrayList();for (String name : two) {if (name.startsWith(张)) {twoA.add(name);}}// 第二个队伍筛选之后不要前2个人 ListString twoB new ArrayList();for (int i 2; i twoA.size(); i) {twoB.add(twoA.get(i));}// 将两个队伍合并为一个队伍 ListString totalNames new ArrayList();totalNames.addAll(oneB);totalNames.addAll(twoB);// 根据姓名创建Person对象 ListPerson totalPersonList new ArrayList();for (String name : totalNames) {totalPersonList.add(new Person(name));}}}
public class Person { private String name;
public Person() {
}public Person(String name) {this.name name;
}}
练习集合元素处理Stream方式
public class DemoStreamNames { public static void main(String[] args) { List one new ArrayList(); List two new ArrayList(); // 第一个队伍只要名字为3个字的成员姓名 // 第一个队伍筛选之后只要前3个人 Stream streamOne one.stream().filter(s - s.length() 3).limit(3); // 第二个队伍只要姓张的成员姓名 // 第二个队伍筛选之后不要前2个人 Stream streamTwo two.stream().filter(s - s.startsWith(“张”)).skip(2); // 将两个队伍合并为一个队伍 // 根据姓名创建Person对象 // 打印整个队伍的Person对象信息。 Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println); } }
*************************************优雅的分割线 **********************************
分享一波:程序员赚外快-必看的巅峰干货
如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程
请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更新