java.lang.IndexOutOfBoundsException: Index: 25, Size: 25

Estou desenvolvendo um questionário online em JSP, onde, ao usuário seleciona o radio de cada questão a ser validada. Exemplo: um questionário de 25 questões, se o usuário chegar na 25 e clicar na anterior 24 e da um próximo para a 25, gera o erro java.lang.IndexOutOfBoundsException: Index: 25, Size: 25. Estava pesquisando na Internet e encontrei que este erro pode ocorrer, se um método tenta acessar um endereço de memória em um array que não existe, e ou já chegou em seu limite.

Trecho da classe Exam.class que o sistema acusa o erro: //Configuração Funciona, porem, da erro, se o usuário volta na ultima questões do exame e clicar na posterior

for(int i=0;i<taken-1;i++){ 
    System.out.println("i ExamController: "+i+ "taken: "+taken);
    //o erro ocorre aqui!!!!
    if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){
        totalCorrect++;
        System.out.println("totalCorrect ExamController: "+totalCorrect);
    }
}

Trecho do código que chama o método calcularResultado: /O exame será finalizado quando o usuário finalizar ou quando o limite de tempo para o exame é longo./

    else if("Finish Exam".equals(action)||( minute==0 && second==0))
    {   finish=true;
    /*Submetendo o Exame e Avaliação Resultado Exame. Quando o usuário clica no botão Concluir, ExamController
     *chama o método calculateResult () passando o objeto Exame, calculateResult ()*/
        int result=exam.calculateResult(exam,exam.questionList.size());                 
        request.setAttribute("result",result);              
        request.getRequestDispatcher("/jsps/result.jsp").forward(request,response);             
    }

Erro no console:

Número pergunta 0 recuperado Número pergunta 1 recuperado Número pergunta 2 recuperado Número pergunta 3 recuperado Número pergunta 4 recuperado Número pergunta 5 recuperado Número pergunta 6 recuperado Número pergunta 7 recuperado Número pergunta 8 recuperado Número pergunta 9 recuperado Número pergunta 10 recuperado Número pergunta 11 recuperado Número pergunta 12 recuperado Número pergunta 13 recuperado Número pergunta 14 recuperado Número pergunta 15 recuperado Número pergunta 16 recuperado Número pergunta 17 recuperado Número pergunta 18 recuperado Número pergunta 19 recuperado Número pergunta 20 recuperado Número pergunta 21 recuperado Número pergunta 22 recuperado Número pergunta 23 recuperado Número pergunta 24 recuperado Você clicou Botão Anterior Número pergunta 23 recuperado Número pergunta 24 recuperado Você clicou Botão Anterior Número pergunta 23 recuperado Você clicou Botão Anterior Número pergunta 22 recuperado Número pergunta 23 recuperado Número pergunta 24 recuperado

i ExamController: 0taken: 32 totalCorrect ExamController: 1 i ExamController: 1taken: 32 i ExamController: 2taken: 32 i ExamController: 3taken: 32 i ExamController: 4taken: 32 i ExamController: 5taken: 32 i ExamController: 6taken: 32 i ExamController: 7taken: 32 i ExamController: 8taken: 32 i ExamController: 9taken: 32 i ExamController: 10taken: 32 i ExamController: 11taken: 32 totalCorrect ExamController: 2 i ExamController: 12taken: 32 totalCorrect ExamController: 3 i ExamController: 13taken: 32 i ExamController: 14taken: 32 i ExamController: 15taken: 32 i ExamController: 16taken: 32 i ExamController: 17taken: 32 i ExamController: 18taken: 32 i ExamController: 19taken: 32 i ExamController: 20taken: 32

jun 17, 2016 5:52:48 PM org.apache.catalina.core.StandardWrapperValve invoke GRAVE: Servlet.service() for servlet [br.com.tkcsapcd.quiz.controller.ExamController] in context with path [/Tkcsapcd_cadastros] threw exception java.lang.IndexOutOfBoundsException: Index: 25, Size: 25 at java.util.ArrayList.rangeCheck(Unknown Source) at java.util.ArrayList.get(Unknown Source) at br.com.tkcsapcd.quizz.Exam.calculateResult(Exam.java:128) at br.com.tkcsapcd.quiz.controller.ExamController.doPost(ExamController.java:127) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source)

Alguém com experiência poderia me ajudar, por favor! Obrigado!

JosueSantos,

Pelo código que você colocou, não é possível visualizar o erro, então vou explicar pelo log o que está acontecendo.

exception java.lang.IndexOutOfBoundsException: Index: 25, Size: 25 at java.util.ArrayList.rangeCheck(Unknown Source) at java.util.ArrayList.get(Unknown Source) at br.com.tkcsapcd.quizz.Exam.calculateResult(Exam.java:128) at

Esse log está dizendo que em um array (pode ser um array ou uma lista - arrayList), você está requerendo o 25º termo de uma lista que tem 25 elementos. O problema é que a busca vai de 0 a 24, ou seja, o .get(24) traria o 25º elemento. Então deve está acontecendo um .get(25) em algum lugar. Pelo código, é no método calculateResult da classe Exam… Faça um debug nesse método no passo-a-passo que você propôs acima ou coloque em um post a classe para que possamos olhar melhor, ok?

Falows

2 curtidas

Logusmao, bom dia!

Obrigado, por responder. Irei debugar o método também. Segue a classe com o metodo calculateResult:

/*ExamController é o principal controle de onde nós controlamos o exame. Aqui nós salvar seleções do usuário

  • (o usuário responderam à questão) em um mapa. ExamController também deixa o movimento do usuário através
  • de perguntas clicando seguinte e anterior botão na extremidade traseira é o ExamController que faz
  • a função chama para recuperar perguntas e respostas armazenamento do usuário.*/
    package br.com.tkcsapcd.quiz.controller;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import br.com.tkcsapcd.quizz.Exam;
import br.com.tkcsapcd.quizz.QuizQuestion;

/**

  • Servlet implementation class ExamController
    */
    @WebServlet("/exam")
    public class ExamController extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

     boolean finish=false;
     
     HttpSession session=request.getSession();		
     try
     {
     	if(session.getAttribute("currentExam")==null)
       {  session=request.getSession(); 	
          String selectedExam=(String)request.getSession().getAttribute("exam"); 
        
          Object ob= session.getAttribute("totalNumberOfQuizQuestions");
          
          String sob=(String)ob;
     	 Exam newExam=new Exam(selectedExam,Integer.parseInt(sob));
     	 session.setAttribute("currentExam",newExam);
     	 String sq=(String)request.getSession().getAttribute("totalNumberOfQuizQuestions");
     	
     	 newExam.setTotalNumberOfQuestions(Integer.parseInt(sq));
     	 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss a");
     		Date date = new Date();
     		String started=dateFormat.format(date);
     	  session.setAttribute("started",started);
       }
     
     }catch(Exception e){e.printStackTrace();}
     
     Exam exam=(Exam)request.getSession().getAttribute("currentExam");		
     
     if(exam.currentQuestion==0){	
     	exam.setQuestion(exam.currentQuestion);
         QuizQuestion q=exam.questionList.get(exam.currentQuestion);	
     	session.setAttribute("quest",q);
     }
     	
     	String action=request.getParameter("action");			
     	
     	int minute=-1;
     	int second=-1;
     	/*Atualizando o cronômetro de contagem regressiva na sessão do usuário. Nós recuperar os valores
     	  de minuto e segundo parâmetros enviados para o controlador de Exame e atualizá-lo em sessão users.
     	*/
     	if(request.getParameter("minute")!=null)
     	{			
     	minute=Integer.parseInt(request.getParameter("minute"));
     	second=Integer.parseInt(request.getParameter("second"));
     	request.getSession().setAttribute("min",request.getParameter("minute") );
     	request.getSession().setAttribute("sec",request.getParameter("second") );
     	}
     	
     	String radio=request.getParameter("answer");
     	int selectedRadio=-1;
     	exam.selections.put(exam.currentQuestion, selectedRadio);
     	if("1".equals(radio))
     	{
     		selectedRadio=1;
     		exam.selections.put(exam.currentQuestion, selectedRadio);
     		exam.questionList.get(exam.currentQuestion).setUserSelected(selectedRadio);				
     	}
     	else if("2".equals(radio))
     	{
     		selectedRadio=2;
     		exam.selections.put(exam.currentQuestion, selectedRadio);
     		exam.questionList.get(exam.currentQuestion).setUserSelected(selectedRadio);				
     	}
     	else if("3".equals(radio))
     	{
     		selectedRadio=3;
     		exam.selections.put(exam.currentQuestion, selectedRadio);
     		exam.questionList.get(exam.currentQuestion).setUserSelected(selectedRadio);				
     	}
     	else if("4".equals(radio))
     	{
     		selectedRadio=4;
     		exam.selections.put(exam.currentQuestion, selectedRadio);
     		exam.questionList.get(exam.currentQuestion).setUserSelected(selectedRadio);				
     	}						
     	if("Next".equals(action)){
     		exam.currentQuestion++;
     		exam.setQuestion(exam.currentQuestion);
     	    QuizQuestion q=exam.questionList.get(exam.currentQuestion);	
     	  	session.setAttribute("quest",q);
     	}
     	else if("Previous".equals(action))
     	{   
     		System.out.println("Você clicou Botão Anterior");
     		exam.currentQuestion--;
     		exam.setQuestion(exam.currentQuestion);
     	    QuizQuestion q=exam.questionList.get(exam.currentQuestion);	
     		session.setAttribute("quest",q);				
     	}
     	/*O exame será finalizado quando o usuário finalizar ou quando o limite de tempo para o exame é longo.*/
     	else if("Finish Exam".equals(action)||( minute==0 && second==0))
     	{   finish=true;
     	/*Submetendo o Exame e Avaliação Resultado Exame. Quando o usuário clica no botão Concluir, ExamController
     	 *chama o método calculateResult () passando o objeto Exame, calculateResult ()*/
     		int result=exam.calculateResult(exam,exam.questionList.size());					
     		request.setAttribute("result",result);				
     		request.getRequestDispatcher("/jsps/result.jsp").forward(request,response);				
     	}						
     if(finish!=true){
     request.getRequestDispatcher("/jsps/exam.jsp").forward(request,response);
     }		
    

    }
    }

///---------------------------------------------------------

/*Quando o usuário clica no botão de exame start para iniciar o exame, vamos criar uma nova
*instância de exame passando o tipo de teste para, por exemplo. Java, PHP, CSS etc. Assim,
cada usuário terá uma instância diferente da classe Exame (que representa um exame individual)./
package br.com.tkcsapcd.quizz;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import br.com.tkcsapcd.quizz.CreateDOM;

public class Exam {
Document dom;
public int currentQuestion=0;
public int totalNumberOfQuestions=0;
public int quizDuration=0;

public List<Integer> quizSelectionsList=new ArrayList<Integer>();	

public List<Integer> getQuizSelectionsList() {
	return quizSelectionsList;
}

public Map<Integer,Integer> selections=new LinkedHashMap<Integer,Integer>();

public ArrayList<QuizQuestion> questionList;

public Exam(String test,int totalNumberOfQuestions) throws SAXException,ParserConfigurationException,IOException, URISyntaxException{
	dom=CreateDOM.getDOM(test);
	for(int i=0;i<totalNumberOfQuestions;i++){
		selections.put(i,-1);
	}
	questionList=new ArrayList<QuizQuestion>(totalNumberOfQuestions);		
}

public Document getDom(){
	return dom;
}	
	
public void setQuestion(int i)
{ 
	int number=i;
	String options[]=new String[4];
    String question=null;
    int correct=0;
  
	NodeList qList=dom.getElementsByTagName("question");
    NodeList childList=qList.item(i).getChildNodes();	    

    int counter=0;
    
    for (int j = 0; j < childList.getLength(); j++) {
        Node childNode = childList.item(j);
        if ("answer".equals(childNode.getNodeName()))
        {
            options[counter]=childList.item(j).getTextContent();
            counter++;
        }
        else if("quizquestion".equals(childNode.getNodeName()))
        {
        	question=childList.item(j).getTextContent();
        }
        else if("correct".equals(childNode.getNodeName()))
        {
        	correct=Integer.parseInt(childList.item(j).getTextContent());
        }            
    }	  
	
	QuizQuestion q=new QuizQuestion();
	q.setQuestionNumber(number);
	q.setQuestion(question);
	q.setCorrectOptionIndex(correct);
	q.setQuestionOptions(options);			
	questionList.add(number,q);		
}	

public ArrayList<QuizQuestion> getQuestionList(){
	return this.questionList;
}

public int getCurrentQuestion(){return currentQuestion;}

public Map<Integer,Integer> getSelections(){
	return this.selections;
}

/* calculateResult () compara as respostas do 
 *usuário com a opção correta para a pergunta e retorna quantas respostas corretas um usuário tem.*/
public int calculateResult(Exam exam,int taken){
	
	int totalCorrect=0;
	Map<Integer,Integer> userSelectionsMap=exam.selections;		
	List<Integer> userSelectionsList=new ArrayList<Integer>();
	
	for (Map.Entry<Integer, Integer> entry :userSelectionsMap.entrySet()) {
		userSelectionsList.add(entry.getValue());
	}
	
	quizSelectionsList=userSelectionsList;		
	List<QuizQuestion> questionList=exam.questionList;		
	List<Integer> correctAnswersList=new ArrayList<Integer>();
	
	for(QuizQuestion question: questionList){
		correctAnswersList.add(question.getCorrectOptionIndex());
	}		
	
	/*
	//Configuração Funciona mas ocorre erro, porque o usuário é obrigado e deve selecionar todas questões!
	for(int i=0;i<selections.size();i++){
		System.out.println("userSelectionsList: "+userSelectionsList.get(i)+" --- "+"correctAnswersList: "+correctAnswersList.get(i));
		System.out.println("ExamController(i): "+i);
		if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){
			totalCorrect++;
		}
	}
	*/		
			
	//Configuração Funciona, porem, da erro, se o usuário volta na ultima questões do exame e clicar na posterior
	for(int i=0;i<taken-1;i++){	
		System.out.println("i ExamController: "+i+ "taken: "+taken);
		if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){
			totalCorrect++;
			System.out.println("totalCorrect ExamController: "+totalCorrect);
		}
	}		
	return totalCorrect;
}	

public int getUserSelectionForQuestion(int i){
	Map<Integer,Integer> map=getSelections();		
	return (Integer) map.get(i);
}		

public int getTotalNumberOfQuestions(){
	return totalNumberOfQuestions;
}

public void setTotalNumberOfQuestions(int i){
	this.totalNumberOfQuestions=i;
}	

}

Jsjosue8,

Olhando para essa parte do código, não consigo encontrar algum erro claro. Alguns ajustes são necessários, pois podem trazer problemas posteriores, mas nenhum justifica o erro. Então vamos juntar o log de erro. Note o seguinte:

for(int i=0;i<taken-1;i++){ System.out.println("i ExamController: "+i+ "taken: "+taken); if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){ totalCorrect++; System.out.println("totalCorrect ExamController: "+totalCorrect); } } return totalCorrect;

Aqui tem algo interessante. Esse taken é setado para percorrer duas listas que tem tamanho específico. Se o taken for maior do que o desejado (como você ter um taken = 32 e listas com tamanhos de 25), a exceção IndexOutOfBoundsException será frequente. Eu não entendo porque setou 32 se os questionários são definidos com 25 questões e o chamado do método é

int result=exam.calculateResult(exam,exam.questionList.size());

(chutaria aqui que antigamente eram 32 questões e foram reduzidas para 25, sem a devida alteração no sistema).

Nesse caso, seria ideal você verificar se esse questionList é para ter um tamanho de 32 ou 25. No caso do erro, como as listas são iguais, eu recomendaria algo assim

for(int i=0;i<userSelectionsList.size();i++){ ...

Ou seja, você limita o for a percorrer a quantidade de posições das listas. Caso haja necessidade de percorrer as 32 posições por algum motivo que não consigo visualizar neste momento, precisa tratar isso dentro do for essa chamada do método get na lista, como

for(int i=0;i<taken-1;i++){ System.out.println("i ExamController: "+i+ "taken: "+taken); if((i < userSelectionsList.size()) && (i < correctAnswersList.size()){ if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){ totalCorrect++; System.out.println("totalCorrect ExamController: "+totalCorrect); } } } return totalCorrect;

Falows

Logusmao, boa tarde!

Problema solucionado com sucesso depois da sua ajuda. Não poderia deixar de agradecer, e por isso estou respondendo aqui. Utilizei a segunda sugestão que me forneceu e agora posso percorrer qualquer posição no array, que não dar erro:

for(int i=0;i<taken-1;i++){
System.out.println("i ExamController: "+i+ "taken: "+taken);
if((i < userSelectionsList.size()) && (i < correctAnswersList.size()){
if((userSelectionsList.get(i)-1)==correctAnswersList.get(i)){
totalCorrect++;
System.out.println("totalCorrect ExamController: "+totalCorrect);
}
}
}
return totalCorrect;

Muito obrigado, e parabéns pelo conhecimento e poder ajudar ao próximo!

Abraços!!!

1 curtida