模拟斗地主洗牌发牌
1.1 案例介绍
按照斗地主的规则,完成洗牌发牌的动作。
具体规则:
1. 组装54张扑克牌
2. 将54张牌顺序打乱
3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
4. 查看三人各自手中的牌(按照牌的大小排序)、底牌
手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3
1.2 案例需求分析
准备牌:
完成数字与纸牌的映射关系:
使用双列Map(HashMap)集合,完成一个数字与字符串纸牌的对应关系(相当于一个字典)。
洗牌:
通过数字完成洗牌发牌
发牌:
将每个人以及底牌设计为ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
存放的过程中要求数字大小与斗地主规则的大小对应。
将代表不同纸牌的数字分配给不同的玩家与底牌。
看牌:
通过Map集合找到对应字符展示。
通过查询纸牌与数字的对应关系,由数字转成纸牌字符串再进行展示。
代码:
package com.oracle.doudizhu;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Demo01 {
public static void main(String[] args) {
//封装Map
Map<Integer,String> pooker=new HashMap<Integer,String>();
//扑克序号
ArrayList<Integer> pookernumber=new ArrayList<Integer>();
//准备花色
String[] color={"♥","♠","♣","♦"};
//准备牌号
String[] number={"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
//准备下标
int index=2;
for(String n:number){
for(String c:color){
//装到map字典中
pooker.put(index, c+n);
pookernumber.add(index);
index++;
}
}
//封装大小王
pooker.put(0, "?");
pooker.put(1, "?");
//添加给pookernumber
pookernumber.add(0);
pookernumber.add(1);
//查看测试扑克牌
//System.out.println(pooker);
//洗牌
Collections.shuffle(pookernumber);
//System.out.println(pookernumber);
//创建三个玩家以及底牌容器
ArrayList<Integer> player1=new ArrayList<Integer>();
ArrayList<Integer> player2=new ArrayList<Integer>();
ArrayList<Integer> player3=new ArrayList<Integer>();
ArrayList<Integer> bottom=new ArrayList<Integer>();
for(int i=0;i<pookernumber.size();i++){
if(i<3){
bottom.add(pookernumber.get(i));
}else if(i%3==0){
player1.add(pookernumber.get(i));
}else if(i%3==1){
player2.add(pookernumber.get(i));
}else if(i%3==2){
player3.add(pookernumber.get(i));
}
//排序
Collections.sort(player1);
Collections.sort(player2);
Collections.sort(player3);
Collections.sort(bottom);
}
//看牌
lookpooker("玩家一",player1,pooker);
lookpooker("玩家二",player2,pooker);
lookpooker("玩家三",player3,pooker);
lookpooker("底牌",bottom,pooker);
}
public static void lookpooker(String playerName,ArrayList<Integer> player,Map<Integer,String> pooker){
//遍历
System.out.print(playerName+":");
for(int pook:player){
System.out.print(pooker.get(pook)+" ");
}
System.out.println();
}
}
运行结果:
第2章 异常
在Java中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置、原因等)
2.1 异常的继承体系
2.2 异常与错误的区别
异常:指程序在编译、运行期间发生了某种异常(XxxException),我们可以对异常进行具体的处理。若不处理异常,程序将会结束运行。
l 异常的产生演示如下:
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[0]);
System.out.println(arr[3]);
// 该句运行时发生了数组索引越界异常ArrayIndexOutOfBoundsException,由于没有处理异常,导致程序无法继续执行,程序结束。
System.out.println("over"); // 由于上面代码发生了异常,此句代码不会执行
}
错误:指程序在运行期间发生了某种错误(XxxError),Error错误通常没有具体的处理方式,程序将会结束运行。Error错误的发生往往都是系统级别的问题,都是jvm所在系统发生的,并反馈给jvm的。我们无法针对处理,只能修正代码。
错误的产生演示如下:
public static void main(String[] args) {
int[] arr = new int[1024*1024*100];
//该句运行时发生了内存溢出错误OutOfMemoryError,开辟了过大的数组空间,导致JVM在分配数组空间时超出了JVM内存空间,直接发生错误。
}
2.3 异常的产生过程解析
先运行下面的程序,程序会产生一个数组索引越界异常ArrayIndexOfBoundsException。我们通过图解来解析下异常产生的过程。
l 工具类
class ArrayTools{
//对给定的数组通过给定的角标获取元素。
public static int getElement(int[] arr,int index) {
int element = arr[index];
return element;
}
}
测试类
class ExceptionDemo2 {
public static void main(String[] args) {
int[] arr = {34,12,67};
int num = ArrayTools.getElement(arr,4)
System.out.println("num="+num);
System.out.println("over");
}
}
上述程序执行过程图解:
2.4 抛出异常throw
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?
1,创建一个异常对象。封装一些提示信息(信息可以自己编写)。
2,需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象;
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
格式:
Throw new 异常类名(参数)
throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
异常类ArrayIndexOutOfBoundsException与NullPointerException的构造方法
class ArrayTools{
//通过给定的数组,返回给定的索引对应的元素值。
public static int getElement(int[] arr,int index) {
/*
若程序出了异常,JVM它会打包异常对象并抛出。但是它所提供的信息不够给力。想要更清晰,需要自己抛出异常信息。
下面判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
if(arr==null){
throw new NullPointerException("arr指向的数组不存在");
}
if(index<0 || index>=arr.length){
throw new ArrayIndexOutOfBoundsException("错误的角标,"+index+"索引在数组中不存在");
}
int element = arr[index];
return element;
}
}
测试类:
class ExceptionDemo3 {
public static void main(String[] args) {
int[] arr = {34,12,67}; //创建数组
int num = ArrayTools.getElement(null,2);// 调用方法,获取数组中指定索引处元素
//int num = ArrayTools.getElement(arr,5);// 调用方法,获取数组中指定索引处元素
System.out.println("num="+num);//打印获取到的元素值
}
}
2.5 声明异常throws
声明:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2… { }
声明异常的代码演示:
class Demo{
/*
如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明。
*/
public void show(int x)throws Exception {
if(x>0){
throw new Exception();
} else {
System.out.println("show run");
}
}
}
2.6 捕获异常try…catch…finally
捕获异常格式:
try {
//需要被检测的语句。
}
catch(异常类 变量) { //参数。
//异常的处理语句。
}
finally {
//一定会被执行的语句。
}
try:该代码块中编写可能产生异常的代码。
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
2.7 运行时期异常(RuntimeExceptio和子类)
编译时期异常 Exception以及非RuntimeExceptio的子类
运行时期异常:
无需thwos以及trycatch处理,一旦发生,程序员修改代码
编译时期异常两种处理方式:
1.throws JVM处理 一旦发生异常,终止程序
2.try-catch-finally 发生异常以后 程序继续
RuntimeException和他的所有子类异常,都属于运行时期异常。NullPointerException,ArrayIndexOutOfBoundsException等都属于运行时期异常.
运行时期异常的特点:
方法中抛出运行时期异常,方法定义中无需throws声明,调用者也无需处理此异常
运行时期异常一旦发生,需要程序人员修改源代码. 无需throws声明 无需处理此异常
class ExceptionDemo{
public static void main(String[] args){
method();
}
public static void method(){
throw new RuntimeException();
}
}
2.8 异常中常用方法
getMessage方法:返回该异常的详细信息字符串,即异常提示信息
toString方法:返回该异常的名称与详细信息字符串
printStackTrace:在控制台输出该异常的名称与详细信息字符串、异常出现的代码位置
try {
Person p= null;
if (p==null) {
throw new NullPointerException(“出现空指针异常了,请检查对象是否为null”);
}
} catch (NullPointerException e) {
String message = e.getMesage();
System.out.println(message );
String result = e.toString();
System.out.println(result);
e.printStackTrace();
}
第3章 自定义异常
这个异常体系具备一个特有的特性:可抛性:即可以被throw关键字操作。
格式:
Class 异常名 extends Exception{ //或继承RuntimeException
public 异常名(){
}
public 异常名(String s){
super(s);
}
}
package com.oracle.zidingyi;
public class FuShuException extends RuntimeException {
public FuShuException(String s){
super(s);
}public FuShuException(){
super();
}
}
package com.oracle.zidingyi;
import java.util.Map.Entry;
public class Demo01 {
public static void main(String[] args) {
double avg=avg(1,2,-3,4,-5,6);
System.out.println(avg);
}
//求平均成绩
public static double avg(double...score){
double sum=0;
for(double s:score){
if(s<0){
throw new FuShuException("该"+s+"为负数");
}
sum+=s;
}
return sum/score.length;
}
}
运行结果:
总结:
构造函数到底抛出这个NoAgeException是继承Exception呢?还是继承RuntimeException呢?
继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会继续执行。
继承RuntimeExcpetion,不需要throws声明的,这时调用是不需要编写捕获代码的,因为调用根本就不知道有问题。一旦发生NoAgeException,调用者程序会停掉,并有jvm将信息显示到屏幕,让调用者看到问题,修正代码。