泛型
1.什么是泛型?
Java 的泛型可以让程序员编写一个类或方法,可以在不指定具体类型的情况下,使用一个类型参数来代替具体的类型,这个参数代表了一个未知的类型,它需要在使用时被指定为一个具体的类型。
2.泛型的优点是?
编译时提高效率,减少类型转化的时间;防止类型转换出现问题,推荐使用各种泛型接口,类
常用的类型占位符:T E K V等。
3.什么是泛型类,泛型接口,泛型方法?
- 泛型类或接口: Java 中可以定义泛型类和泛型接口,泛型类和泛型接口中可以包含泛型方法,这些方法的类型参数可以是泛型类或泛型接口中定义的类型参数,也可以是自己定义的类型参数。我们定义了一个泛型类 Pair,它有两个类型参数 T 和 E,表示成对的两个值的类型。它有一个构造方法,接受两个参数,一个是类型为 T 的第一个值,一个是类型为 E 的第二个值。
public class Pair<T, E> {
private T first;
private E second;
public Pair(T first, E second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public E getSecond() {
return second;
}
public void setFirst(T first) {
this.first = first;
}
public void setSecond(E second) {
this.second = second;
}
}
- 泛型方法:泛型方法可以定义在普通类中,也可以定义在泛型类中。以下是一个泛型方法 printArray 的定义:
public static <T> void printArray(T[] arr) {
for (T t : arr) {
System.out.println(t);
}
}
- 用泛型写一个通用查询方法:
// 利用泛型写通用查询
public static <T> List<T> query(Class<T> tClass,String sql,Object... params){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<T> list = new ArrayList<>();
try {
connection = getConn();
statement = connection.prepareStatement(sql);
setParams(statement,params);
resultSet = statement.executeQuery();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
while(resultSet.next()){
T tObj = tClass.newInstance();//获取T的对象
//获取结果集中各个字段
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
String columnName = resultSetMetaData.getColumnLabel(i);
Object columnValue= resultSet.getObject(i);
//获取字段名对应的实体类型的属性(Field)
Field field = tClass.getDeclaredField(columnName);
field.setAccessible(true);
if(columnValue instanceof Long) {
Long value = (Long) columnValue;
if (field.getType() == int.class) {//如果实体中该字段为int类型
field.set(tObj, value.intValue());//设置属性值,
}
}else if(columnValue instanceof Date){
Date value = (Date) columnValue;
if(field.getType() == LocalDate.class){//如果实体中该字段为int类型
field.set(tObj,value.toLocalDate());//设置属性值,
}
}else{
field.set(tObj, columnValue);//设置属性值
}
}
list.add(tObj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return list;
}
4. 什么是通配符,在泛型中有什么用?
- 通配符:泛型支持通配符,用于表示某个类型的子类或父类,这个通配符用 ? 表示。使用通配符时,我们可以指定一个上界或下界,也可以不指定边界。
- 使用通配符时,我们可以在前面加上 ? extends 表示这个通配符代表一个上界,或者在前面加上 ? super 表示这个通配符代表一个下界。用一个例子看看:
public class TeFruitDemo {
public static void main(String[] args) {
Fruit fruit = new Apple();
Fruit fruit1 = new Banana();
List<Fruit> list1 = new ArrayList<>();
List<Apple> list2 = new ArrayList<>();
List<Banana> list3 = new ArrayList<>();
method1(list1);
method2(list1);
method2(list2);
method2(list3);
method3(list2);
method3(list1);
// method3(list3); 错误的
}
// 如何限定泛型的 边界(范围 )
static void method1(List<Fruit> list){
}
// 可以传递List<Fruit>可以List<Apple>
// 限定泛型上边界:1、Fruit 2、继承自Fruit的子类
static void method2(List<? extends Fruit> list){
}
// 可以传递List<Apple> 或者List<Apple的父类型> 或者 List<Object>
// 限定泛型下边界:1、Apple 2、Apple的父类型
static void method3(List<? super Apple> list){
}
}
Lamdba表达式
1.什么时候使用Lamdba表达式,它有什么作用?
Lamdba表达式:主要用于简化使用函数接口的代码。所谓函数接口就是只有一个抽象方法的接口,而 Lambda 表达式可以实现这种函数接口的实例化与调用。这种特性可以大量简化代码,提高开发效率。
2.Lamdba表达式的语法以及结构有哪些?
- 基本语法如下:parameters 表示参数列表,expression 表示方法体。如果参数列表为空,则可以省略小括号;如果方法体中只有一条语句,则可以省略大括号。
(parameters) -> expression
- 具体示例:
一个参数:
x -> System.out.println(x)
(x) -> System.out.println(x)
(String x) -> System.out.println(x)
多个参数:
(x, y) -> System.out.println(x + " " + y)
没有参数时:
() -> System.out.println("Hello world!")
当方法体有多行代码时:
x -> {
int a = x + 1;
int b = x + 2;
return a + b;
}
3.结合具体场景该如何使用?
- 使用规则:Lambda 表达式通常用于接口实现,或函数式接口(functional interface)的调用。函数式接口指只有一个抽象方法的接口。
- 了解四种类型的函数式接口:①功能型接口:Funcation —有参数有返回值;②消费型接口:Consumer—有参数无返回值③供给型接口:Supplier—无参数有返回值④断言型接口:Predicate—有参数返回Boolean类型。
- 具体使用场景:以供给型为例子,实现字符串的截取。
//方法引用,函数式接口
public class SubStringFsDemo {
public static void main(String[] args) {
// 无参有返回值
Supplier<String> s1 = () -> "hello".toUpperCase();
System.out.println(s1.get());
Supplier<String> s2 = "hello"::toUpperCase;
System.out.println(s2.get());
// 字符串截取
String str = "hello";
String result = str.substring(1);
System.out.println(result);
// 实例方法引用将中
Function<Integer,String> f1 = (start) ->"hello".substring(start);
System.out.println(f1.apply(2));
Function<Integer,String> f2 = "hello"::substring;
System.out.println(f2.apply(2));
//
//Lambda表达式被类的实例方法引用替代的时候
//表达式中的第一个参数作为调用者
//后面的参数全部传递给要引用的方法作为参数
// str1是方法的调用者,start作为lambda体中方法的参数使用
MySubStr sub1 = (str1,start) ->str1.substring(start);
System.out.println(sub1.subStr("abcde", 1));
// 方法的引用
MySubStr sub2 = String::substring;
System.out.println(sub2.subStr("abcde", 1));
}
}
interface MySubStr{
// 参数1:要截取的原始字符串
// 参数2: 截取的开始索引
String subStr(String str,int start);
}
4.方法引入,为何要进行方法引入?
- 方法引入是啥:通过方法名称引用方法的形式可读性更高一些,这种形式就是方法引用。方法引用是一种更简洁易懂的lambda 表达式替换,实现Lamdba表达式的简写。
- 语法规则:方法引用中::后只是方法名。看下边的例子:
list.forEach((s) -> System.out.println(s));
list.forEach(Syetem.out::println);
- 当然的还有对静态方法,实例方法和构造方法的引用。
Stream流
1.什么是Stream流?
Stream(流)是一个来自数据源的元素队列并支持聚合操作。Stream操作还有两个基础的特征:Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格, 可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting);内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
2.如何生成流,如何操作Stream流?
- 生成流:集合接口有两种方式生成流:stream() − 为集合创建串行流,parallelStream() − 为集合创建并行流。
- 操做流的方法:
- 'forEach’来迭代流中的每个数据,使用 forEach 输出了10个随机数:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
- map 方法用于映射每个元素到对应的结果,使用 map 输出了元素对应的平方数:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
- filter 方法用于通过设置的条件过滤出元素,使用 filter 方法过滤出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
- limit 方法用于获取指定数量的流,使用 limit 方法打印出 10 条数据:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
- 并行也有许多方法,接下来以一个实例进行展示:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
public class Java8Tester {
public static void main(String args[]){
System.out.println("使用 Java : ");
// 计算空字符串
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("列表: " +strings);
long count = getCountEmptyStringUsingJava7(strings);
System.out.println("空字符数量为: " + count);
count = getCountLength3UsingJava7(strings);
System.out.println("字符串长度为 3 的数量为: " + count);
// 删除空字符串
List<String> filtered = deleteEmptyStringsUsingJava7(strings);
System.out.println("筛选后的列表: " + filtered);
// 删除空字符串,并使用逗号把它们合并起来
String mergedString = getMergedStringUsingJava7(strings,", ");
System.out.println("合并字符串: " + mergedString);
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取列表元素平方数
List<Integer> squaresList = getSquares(numbers);
System.out.println("平方数列表: " + squaresList);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("列表: " +integers);
System.out.println("列表中最大的数 : " + getMax(integers));
System.out.println("列表中最小的数 : " + getMin(integers));
System.out.println("所有数之和 : " + getSum(integers));
System.out.println("平均数 : " + getAverage(integers));
System.out.println("随机数: ");
// 输出10个随机数
Random random = new Random();
for(int i=0; i < 10; i++){
System.out.println(random.nextInt());
}
System.out.println("使用 Java 8: ");
System.out.println("列表: " +strings);
count = strings.stream().filter(string->string.isEmpty()).count();
System.out.println("空字符串数量为: " + count);
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("字符串长度为 3 的数量为: " + count);
filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选后的列表: " + filtered);
mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Squares List: " + squaresList);
System.out.println("列表: " +integers);
IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
System.out.println("随机数: ");
random.ints().limit(10).sorted().forEach(System.out::println);
// 并行处理
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("空字符串的数量为: " + count);
}
private static int getCountEmptyStringUsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.isEmpty()){
count++;
}
}
return count;
}
private static int getCountLength3UsingJava7(List<String> strings){
int count = 0;
for(String string: strings){
if(string.length() == 3){
count++;
}
}
return count;
}
private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
List<String> filteredList = new ArrayList<String>();
for(String string: strings){
if(!string.isEmpty()){
filteredList.add(string);
}
}
return filteredList;
}
private static String getMergedStringUsingJava7(List<String> strings, String separator){
StringBuilder stringBuilder = new StringBuilder();
for(String string: strings){
if(!string.isEmpty()){
stringBuilder.append(string);
stringBuilder.append(separator);
}
}
String mergedString = stringBuilder.toString();
return mergedString.substring(0, mergedString.length()-2);
}
private static List<Integer> getSquares(List<Integer> numbers){
List<Integer> squaresList = new ArrayList<Integer>();
for(Integer number: numbers){
Integer square = new Integer(number.intValue() * number.intValue());
if(!squaresList.contains(square)){
squaresList.add(square);
}
}
return squaresList;
}
private static int getMax(List<Integer> numbers){
int max = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() > max){
max = number.intValue();
}
}
return max;
}
private static int getMin(List<Integer> numbers){
int min = numbers.get(0);
for(int i=1;i < numbers.size();i++){
Integer number = numbers.get(i);
if(number.intValue() < min){
min = number.intValue();
}
}
return min;
}
private static int getSum(List numbers){
int sum = (int)(numbers.get(0));
for(int i=1;i < numbers.size();i++){
sum += (int)numbers.get(i);
}
return sum;
}
private static int getAverage(List<Integer> numbers){
return getSum(numbers) / numbers.size();
}
}
本篇到此结束,感谢学习。