Estas notas não são exaustivas e não são o suficiente para passar o exame. Há que estudar bastante para lá chegar. Obviamente que os que programam em Java à bastante tempo estão em significativa vantagem para fazer o exame.
Alguns pontos são básicos, outros mais complexos, mas todos servem para reforçar alguns aspectos que na utilização diária passam despercebidos. Parte dos títulos das notas estão em inglês pois são de uso comum na comunidade e não faz sentido traduzir as mesmas, pois o exame é em inglês.
Antes de mais recomendo vivamente o livro SCJP Sun Certified Programmer for Java 6 Study Guide
que serve tanto para a certificação OCPJP6 como para a OCMJ6D - Oracle Certified Master, Java SE 6 Developer (ex-SCJD6).
E sem mais demoras as notas de estudo.
Identificadores legais:
- todos os começados por letras
- $ (dólar)
- _ (sublinhado)
- const
- goto
- native
- strictfp
- assert
- enum
- há mais...
native: apenas pode ser aplicado a métodos, e a sua declaração é semelhante a um método abstract.
Não há conflitos possíveis entre:
- Nomes de classes
- Type parameter placeholders
- Identificadores de variáveis
JavaBeans property naming rules:
- As assinaturas dos métodos setter têm de ser
- public
- retornar void
- ter um argumento que representa o tipo da propriedade
- As assinaturas dos métodos getter têm de ser
- public
- não têm argumentos de entrada
- tipo de retorno igual ao tipo de argumento do método setter para essa propriedade
- Os nomes dos métodos dos listeners usados para "registar" um listener com uma fonte de evento tem de usar o prefixo add, seguido do tipo de listener [ex: addActionListener(ActionListener al)]
- As regas para remover ("desregistar") são iguais ás do add excepto que o prefixo é remove [ex: removeMyListener(MyListener m)]
- O tipo de listener a adicionar ou remover tem de ser passado como argumento do método
- Os nomes dos métodos do listener têm de terminar com a palavra "Listener"
- Pode haver apenas uma classe pública no ficheiro fonte
- Pode haver mais do que uma classe não pública num ficheiro fonte
- Num ficheiro sem classes públicas, o nome do ficheiro pode ser diferente de quaisquer classes nele contidas
Qualquer classe no mesmo pacote | Qualquer classe (não subclasse) fora do pacote | Própria classe | Subclasse no mesmo pacote | Subclasse pacote diferente | |
---|---|---|---|---|---|
* Através de herança | |||||
default | OK | NA | OK | OK | NA |
public | OK | OK | OK | OK | OK |
private | NA | NA | OK | NA | NA |
protected | OK | NA | OK | OK | OK (*) |
O modificador de acesso protected tem um efeito nas classes que pertençam a pacotes diferentes da superclasse, que é estes serem visíveis apenas através de herança. Isto é, se uma subclasse que esteja num pacote diferente da superclasse instanciar a superclasse e através desta referência tentar aceder a um membro protected, irá surgir um erro de compilação.
Declaração de Interfaces:
Todos os métodos declarados numa interface são automaticamente:
- public
- abstract
Todas as variáveis definidas numa interface têm de ser:
- public
- static
- final
Encapsulation:
- Protecção dos dados (com modificadores de acesso)
- Proteger as variáveis de instância
- Assessores públicos ao invés de acesso directo a variáveis de instância (usando a metodologia dos Javabeans)
Variable argument list (var-args)
Uso: tipo... variável
Só pode existir um var-arg na assinatura de um método e o var-arg tem de ser o último parâmetro.
Intervalos para os primitivos
Regra geral para intervalos
Positivos: 2(nº bits -1) - 1
Negativos: -2 (nº bits -1)
Tipo | Bits | Intervalo Menor | Intervalo Maior |
---|---|---|---|
byte | 8 | -27 | 27 - 1 |
short | 16 | -215 | 215 - 1 |
int | 32 | -231 | 231 - 1 |
long | 64 | -263 | 253 - 1 |
float | 32 | NA | NA |
double | 64 | NA | NA |
char | 16 | NA | 216 - 1 (sem sinal) |
O tipo char é representado em Unicode. Pode-se indicar o valor do carácter directamente em unicode. ex: \uxxxx ao invés de representar o carácter directamente. Cada carácter numa String é representado como um char.
O tipo double é a representação por defeito para números de vírgula flutuante. Podem opcionalmente ser terminados em D ou d.
O tipo float tem de ter F ou f na terminação.
Um literal inteiro é sempre um int implicitamente
O resultado de uma expressão envolvendo qualquer coisa do tamanho int ou inferior é sempre int. Por exemplo: a soma de dois byte é sempre um int.
Modificadores possíveis em variáveis e métodos
Variáveis Locais e Method Local Inner Classes | Variáveis Não Locais | Métodos e Inner Classes |
---|---|---|
1- Não aplicável a Inner Classes 2 - Só aplicável a Method Local Inner Classes | ||
final abstract 2 | final public protected static transient volatile | final public protected private static1 abstract synchronized1 strictfp native1 |
Ao contrário das variáveis não locais, as variáveis locais não têm inicializações por defeito.
A inicialização de uma variável final tem de ocorrer antes do construtor(es) terminar(em).
Declaração de Arrays
Constituição de um array:
int[] xpto = new int[4] {1, 2, 3, 4} ;
_______ __________ __________
Declaração Construção Inicialização
Regras gerais:
- Na parte da construção é obrigatório indicar o tamanho do array se não existir a parte da inicialização; se tiver inicialização então é opcional
- A parte parte da construção pode ser omitida se a inicialização vier no mesmo statement
Os [] podem estar intercalados com o identificador.
O tamanho do array apenas pode ser declarado na inicialização do mesmo, isto é, à direita do =.
Ex: int[] array = new int[10];
Declaração de enumerados
enum xpto {X, Y, Z};
Só podem ser declarados:
- na sua própria classe
- como um membro da classe
- tal como uma classe dentro de um ficheiro de uma classe pública
Tal como numa não inner classe (quando o enum é declarado como tal), apenas se pode aplicar os modificadores:
- public
- default
A ordem pela qual os valores no enum são declarados conta! Isto porque o método values() presente em todos os enums, retorna um array do tipo do enum com os valores pela ordem da declaração.
Num enum é possível fazer override a métodos do próprio enum.
Exemplo:
enum Xpto{ A(1), B(2){ // Este bloco denomina-se: Constant Specific Class Body public String getXptoza(){ return "ABC"; } }; Xpto(int i){ this.i = i; } private int i; public String getXptoza(){ return "Z"; } } |
Uma classe que implemente uma interface:
- Não pode declarar novas checked exceptions para os métodos implementados
- Não pode declarar excepções que são mais abrangentes que as excepções declaradas no método da interface
- Pode declarar Runtime Exceptions em qualquer método da interface independentemente da declaração da interface
- Não é obrigatório declarar todas as excepções da interface (pode mesmo não declarar nenhuma)
HAS-A: Baseado no uso e não na herança. Ou seja, uma classe has-a outra se o código da primeira classe tiver uma referência para uma instância da segunda.
Herança, Overriding, Overloading e Polimorfismo
Invocação de métodos polimórficos aplica-se apenas a métodos de instância overrriden! Apenas métodos de instância overriden são invocados dinamicamente baseados no tipo real de objecto.
A escolha de qual método overloaded invocar não é decidida dinamicamente em runtime. O tipo de referência (não o tipo de objecto) determina o método overloaded que é invocado.
O compilador apenas "olha" para o tipo de referência e não ao tipo de instância.
Os métodos abstract, quando concretizados pelas subclasses, são sempre do tipo override.
Os métodos static não podem ser overriden!
As variáveis de instância também podem ser overrided.
Resumindo:
- overriding: decidido em runtime baseado no tipo de objecto
- overloading: baseado no tipo de referência do argumento passado em tempo de compilação
Não esquecer: O código tem de ser retro-compatível sempre! Por isso comportamentos anteriores são sempre preferidos!
- widening é preferido sobre o boxing
- widening é preferido sobre var-args
- boxing é preferido sobre var-args
- var-args é sempre o último recurso
Regras para o método que está a fazer o override em relação ao método overriden:
- Modificador de acesso
- Não pode ter um modificador de acesso mais restritivo
- Pode ter um modificador menos restritivo
- Retorno
- O tipo de retorno tem de ser o mesmo, ou um subtipo do tipo declarado
- Excepções (em relação às excepções declaradas na assinatura do método overriden)
- Pode lançar quaisquer excepções não checadas (que estendam RuntimeException)
- Não pode atirar novas excepções checked
- Não pode atirar excepções que sejam mais abrangentes
- Pode atirar excepções que sejam subclasses
- Pode lançar (declarar) menos ou nenhuma excepção
- upcasting - o cast é implícito, é opcional fazer o cast
- downcasting - o cast é obrigatório. É verificado apenas se o cast é possível, isto é, se os tipos estão na árvore de herança. Se não estiverem na árvore de herança dá erro de compilação.
- Seguir todas as regras para os overrides legais
extends tem de preceder implements caso uma classe use os dois.
Se uma superclasse implementar uma interface, e se uma subclasse indicar explicitamente que também implementa a mesma interface, a subclasse não tem de voltar a implementar os métodos da interface, quando a superclasse já o fez. Não faz mal voltar a tornar explícito a indicação de implementação da interface.
Regras para construtores
- Pode existir um método com o mesmo nome da classe, mas este não ser um construtor (basta retornar algo)
- O construtor por defeito e sem argumentos apenas é automaticamente criado pelo compilador, se nenhum outro construtor for declarado
- A chamada a outro construtor ou a um construtor da superclasse é o primeiro statement (a primeira instrução) de cada construtor. O compilador pode inserir a chamada a super() caso não exista nenhuma chamada a outro construtor
- Não pode ser efectuada nenhuma chamada a métodos de instância ou acesso a variáveis de instância até depois do super construtor ter corrido (o construtor da superclasse). (Daí a chamada a outros construtores ter de estar na primeira linha)
- O uso de variáveis estáticas e métodos estáticos é permitido na chamada a outros construtores da classe
- As classes abstract têm construtores que são sempre chamados quando uma subclasse concreta é instanciada
- Um construtor apenas pode ser invocado dentro de outro
- Os construtores não são herdados!
- Os construtores não podem ser marcados como:
- static
- final
- abstract
- Tem o mesmo modificador de acesso da classe
- Incluí ele próprio uma chamada a super()
static e o compilador
No acesso a coisas static, o compilador apenas tem em atenção o tipo declarado da variável que está a aceder ao static, ou seja, é independente da variável de instância (o que conta é o tipo da variável de referência e não o tipo de objecto).
Coupling e Cohesion
Coupling - Até que ponto uma classe está ligada às demais. Ou seja, até que ponto alterações numa classe afectam outras.
Cohesion - Como é que uma dada classe é desenhada. Até que ponto uma classe tem um único e bem focado propósito.
Heap e Stack
Heap - Onde estão as variáveis de instância e os objectos.
Stack - Onde estão as variáveis locais.
Números octais, decimais e hexadecimais
Números octais - Todos os números inteiros começados por 0 (zero) podem ter até 21 dígitos.
Números hexadecimais - Todos os números começados por 0x (zero x). Podem ter até 16 dígitos (a representação das letras não é case sensitive).
Por defeito, os números em octal, decimal, ou hexadecimal são ints, a não ser que sejam terminados por L ou l (L minúsculo) sendo então longs.
Narrowing e Widening
Sendo Maior e Menor tipos de dados :
Maior ------------ Narrowing (cast obrigatório) ----------------- > Menor
Maior <-----------Widening (cast opcional. é implícito) ---------- Menor
"Escala":
double > float > long > int > short > byte
Existe o caso especial do char. Uma vez que o char é um inteiro sem sinal de 16 bits só é possível fazer widening a partir de int. Todo e qualquer cast de outro tipo de dados numérico (double, float, long, int, short ou byte) para char é sempre narrowing. Detalhes completos disponíveis na especificação.
Os operadores de atribuição compostos (+=, -=, *=, /=) colocam automaticamente um cast, não sendo necessário, por isso, escrevê-lo.
Valores por defeito de variáveis não locais atribuídos pelo compilador
- Referência para objecto: null
- byte, short, int, long: 0 (zero)
- float, double: 0 (zero)
- boolean: false
- char: '\u0000' (u seguido de zeros)
Todas as variáveis locais têm de ser inicializadas antes de serem usadas. Caso não sejam usadas não é obrigatório inicializadas.
Arrays
Arrays são sempre objectos!
Blocos de inicialização
- Estáticos
- de Instância - correm imediatamente depois de todos os super construtores terem corrido. Correm pela ordem que aparecem no ficheiro fonte
As classes wrapper (de tipos primitivos como por exemplo Integer) tal como a classe String são imutáveis. O seu valor depois de atribuído não pode ser alterado.
Exceptuando a classe Character cujo construtor apenas recebe um char, todos os outros construtores das outras classes wrapper podem receber uma String ou o tipo que fazem wrap.
A partir do Java 5, o objecto Boolean pode ser usado num teste booleano.
Criação de objectos wrapper:
- Usando um construtor
- Usando o método estático valueOf() [tomar em atenção que a classe Character não tem este método]
- xxxValue()
- parseXxx() [estático]
Boolean | Byte | Character | Double | Float | Integer | Long | Short | |
---|---|---|---|---|---|---|---|---|
xxxValue | X | X | X | X | X | X | ||
parseXxx | X | X | X | X | X | X | ||
parseXxx com radix | X | X | X | X | ||||
valueOf | X | X | X | X | X | X | X | |
valueOf com radix | X | X | X | X | ||||
toString(primitivo) | X | X | X | X | X | X | X | X |
toString(primitivo) com radix | X | X | ||||||
toXxxString Octal, hex ou bin | X | X |
Para o exame é necessário saber bem estes métodos, em que classes existem, etc.
Boxing e Autoboxing
Ao invés de se ter de:
- criar o wrapper
- tirar o primitivo de dentro do wrapper
- usar o primitivo
- voltar a criar um wrapper
No caso dos operadores != e ==, a comparação entre um primitivo e um objecto wrapped é feita do seguinte modo:
- Os objectos são unwrapped e a comparação será primitivo a primitivo
- Boolean
- Byte
- Character -> de \u0000 (0) a \u007F (127)
- Short -> de -128 a 127
- Integer -> de -128 a 127
O Boxing e o unboxing funcionam, de um modo geral, nos mesmos locais onde normalmente se usam primitivos ou um objecto wrapped.
As classes wrapper não podem fazer widden umas para as outras.
O que é e não é permitido (no boxing e widening):
- widden seguido de box não é permitido
- box seguido de widen é permitido
O Garbage Collector (GC) limpa apenas a heap (no que ao exame diz respeito).
Método finalize()
- Para qualquer objecto, finalize() será apenas chamado uma e uma só vez no máximo pelo GC
- Chamar o método finalize() pode fazer com que o objecto não seja apagado
- Poderá nunca ser executado
Nos operadores compostos (+=, -=, *=, /=) a expressão à direita tem sempre precedência.
Na comparação entre um carácter com outro ou com um numérico é usado o valor unicode do carácter como valor numérico.
Com os operadores == ou != apenas de pode comparar tipos compatíveis.
Nos enum == ou equals() dão o mesmo resultado.
instanceof não pode ser usado para testar duas classes hierárquicas diferentes (dá erro de compilação).
Operador condicional :
variável = (expressão_booleana) ? valor_a_atribuir_ se_Verdade : valor_a_atribuir_se_Falso;
&& - short-circuit AND & - non-short-circuit AND
!! - short-circuit OR | - non-short-circuit OR
Switch
switch (expression) {
case constant1: code block
case constant1: code block
default: code block
}
Uma expressão (expression) no switch tem de ser avaliada como: char, byte, short, int ou enum, ou seja, apenas enums e variáveis que possam implicitamente ser promovidas a int podem ser usadas!
A constante do case tem de ser avaliada tal qual a expressão (expression) do switch e ainda tem de ser uma constante em tempo de compilação!
O default case pode vir em qualquer posição do case.
Ciclo for
No ciclo for todas as partes da declaração são opcionais.
Na parte da inicialização todas as variáveis têm de ser do mesmo tipo. Na parte da condição o resultado tem de ser booleano. Na parte do incremento qualquer statement é válido!
No uso de continue e break com labels, ambos têm de estar dentro do loop que tem o mesmo nome da label. Caso contrário código não compila.
Assertions
Quando se usa assertions presume-se sempre que algo (o que se testa) é verdadeiro. Caso não seja uma AssertionError é lançada.
- assert (boolean_expression);
- assert (boolean_expression) : expressão_que_retorna_um_valor
assert só pode ser usado como identificador se o código for compilado com a opção: -source 1.3
A opção de runtime -ea ou -enableassertions activa as assertions.
Apeser de por defeito as assertions estarem desligadas, as opções de runtime -da ou -disableassertions inactivam as assertions também.
A opção -dsa desliga as assertions para as classes de sistema.
Pode-se combinar as opções de ligar e desligar assertions.
Pode-se ligar/desligar as assertions do seguinte modo:
- sem argumentos -> Todas as classes excepto as de sistema
- com nome de pacote -> Todas as classes do pacote indicado e também, subpacotes
- nome da classe -> Classe indicada
Mais informação em:
Excepções
Unchecked Exceptions
- RuntimeException (e subclasses)
- Error (e subclasses)
Excepção | Descrição | Normalmente Lançada Por |
---|---|---|
IllegalStateException | Atirada quando o estado do ambiente não corresponde à operação que se está a tentar | Programaticamente |
ExceptionInInitializerError | Atirada quando se tenta inicializar uma variável ou bloco de inicialização estático | JVM |
String Constant Pool
Zona de memória onde são guardadas as Strings pela JVM. Se uma dada String já existir, a JVM apenas coloca uma referência extra para a String, e um novo objecto não é criado.
Métodos mais importantes na classe String
É imprescindível para o exame saber de cor vários métodos em várias classes. Não há consulta disponível por isso tem de se decorar a API.
- char charAt(int)
- String concat (String)
- String replace(char o, char n)
- String toLowerCase()
- String toUpperCase()
- String trim()
- boolean equalsIgnoreCase(String)
- int length()
- String substring(int)
- String substring(int b, int e) - O e é exclusive
- Strint toString()
Métodos mais importantes na classe StringBuilder e StringBuffer
- StringXxx append(...)
- StringXxx delete(int s, int e) - O e é exclusive
- StringXxx insert(int o, ...)
- StringXxx reverse()
- String toString()
- boolean equals(Object) - Não compara os valores pois não é overriden!
Métodos principais na classe java.io.File
Um objecto do tipo File pode representar ou um ficheiro ou uma directoria.
O construtor da classe File não cria o ficheiro/directoria fisicamente. Apenas cria o nome do ficheiro/directoria.
- File(File, String)
- File(String, String)
- File(String)
- boolean createNewFile() - cria um ficheiro se ainda não existir
- boolean mkdir() - cria a directoria se ainda não existir
- boolean isFile()
- boolean isDirectory()
- boolean exists()
- boolean delete() - não apaga uma directoria se esta não estiver vazia
- String[] list()
- boolean renameTo(File)
- FileWriter(File) -> Cria o ficheiro fisicamente
- FileWriter(String) -> Cria o ficheiro fisicamente
- close()
- write(...)
- flush()
- BufferedWriter(Writer)
- close()
- newLine()
- flush()
- write(...)
- PrintWriter(File)
- PrintWriter(String)
- PrintWriter(OutputStream)
- PrintWriter(Writer)
- flush()
- close()
- format(...)
- write(...)
- print(...)
- printf(...)
- println(...)
- append(...)
Nota : Só o mkdir() cria a directoria. Ao contrário do que ocorre com os ficheiros, as directorias não são criadas automaticamente pelos Writers (dá excepção).
Métodos principais da classe java.io.FileReader
- FileReader(File)
- FileReader(String)
- int read(char[])
- BufferedReader(Reader)
- String readLine()
- read()
- String readLine(mascaraStr, promptStr)
- char[] readPassword(mascaraStr, promptStr)
- format(mascaraStr, ...) - escreve na consola
- format(String, ...) - escreve na consola
Obter o objecto Console: System.console(); - Pode retornar null se a mesma não existir.
Métodos principais na classe java.io.ObjectOutputStream
- ObjectOutputStream(OutputStream) - OutputSteam é geralmente FileOutputStream
- writeObject(Object)
Métodos principais na classe java.io.ObjectInputStream
- ObjectInputStream(InputStream) - InputStream é geralmente FileInputStream
- Object readObject()
- FileInputStream(String)
Métodos principais da classe java.io.FileOutputStream
- FileOutputStream(String)
Serialização
Para serem serializáveis as classes têm de implementar Serializable.
Se um objecto não serializável (que não implementa Serializable) for tentado ser serializado ocorre a excepção: java.ioNotSerializableException.
Se todos os objectos do grafo de serialização forem serializáveis, não é preciso fazer nada. Caso contrário poderá ser necessário ajudar na serialização com estes dois métodos:
- private void writeObject(ObjectOutputStream) - pode lançar IOException
- deve-se invocar na primeira linha do método: os.defaultWriteObject
- private void readObject(ObjectInputStream) - pode lançar IOException e
ClassNotFoundException - deve-se invocar na primeira linha do método: os.defaultReadObject
Criação de novos objectos e Serialização
Eventos que ocorrem quando se usa new para criar um novo objecto:
- Todas as variáveis de instância da classe têm atribuído os valores por defeito
- O construtor é invocado e, imediatamente, é chamado o construtor da superclasse
- Os construtores da superclasse completam (correm e terminam)
- As variáveis de instância que são inicializadas como fazendo parte da sua declaração vêm atribuído o seu valor inicial
- O construtor completa-se (corre e termina)
Esta ordem de eventos não ocorre quando um objecto é desserializado! Quando uma instância de uma classe serializável, é desserializada:
- O construtor não corre
- Se uma classe serializável estender outra que não o é, o construtor da classe serializável não corre (como indicado no ponto anterior), mas o da superclasse irá correr, tal como todos os construtores de todas as superclasses acima da superclasse!
- As variáveis de instância não têm os seus valores iniciais atribuídos
- Só os valores que foram salvos (o estado do objecto na altura da serialização) serão reatribuídos
- As variáveis que não estão no estado do objecto terão os valores por defeito do tipo da variável
Métodos principais na classe java.util.Date
- Date()
- Date(long) - em milissegundos
- setTime(long) - em milissegundos
- long getTime() - em milissegundos
- Calendar getInstance()
- Calendar getInstance(Locale)
- add(...)
- setTime(Date)
- get(CALENDAR_CONSTANT)
- roll(...)
- Date getTime()
- set(int year, int month, int day) - month começa em 0
- CALENDAR_CONSTANT getFirstDayOfWeek()
- DateFormat getInstance()
- DateFormat getDateInstance()
- DateFormat getDateInstance(int style)
- DateFormat getDateInstance(int style, Locale locale)
- String format(Date)
- Date parse(String)
- DateFormat.SHORT
- DateFormat.MEDIUM
- DateFormat.LONG
- DateFormat.FULL
- NumberFormat getInstance()
- NumberFormat getInstance(Locale)
- NumberFormat getNumberInstance()
- NumberFormat getNumberInstance(Locale)
- NumberFormat getCurrencyInstance()
- NumberFormat getCurrencyInstance(Locale)
- String format(Number)
- Number parse(String)
- int getMaximumFractionDigits()
- setMaximumFractionDigits(int) - Só se aplica na formatação
- setParseIntegerOnly(boolean)
- Locale(String language)
- Locale(String language, String country)
- Locale getDefault()
- String getDisplayCountry()
- String getDisplayCountry(Locale)
- String getDisplayLanguage()
- String getDisplayLanguage(Locale)
Expressões Regulares (regex)
Métodos principais da classe java.util.regex.Pattern
- Pattern Pattern.compile(String regex)
- Matcher matcher(String)
- String pattern() - String Regex
- boolean find() - Verifica se há um match/procura no próximo resultado
- int start() - Indices na String fonte onde começam os emparelhamentos
- Pattern pattern() - String regex. Só deve ser invocado se o método find retornar true.
- String group() - Resultado que encontrou. Só deve ser invocado se o método find retornar true.
- boolean matches() - Indica se toda a String fonte corresponde à expressão regular indicada.
Metacaracteres
- \s - Um carácter whitespace
- \w - Um carácter palavra (letras, dígitos ou _ )
Para se usar quantificadores em conjuntos [....] tem de se colocar o conjunto entre parêntesis. Por exemplo: ([....])+
- ?, * e + são gananciosos. Basicamente lê a fonte toda e trabalha da direita para a esquerda. Assim que encontrar pára. Dá o resultado mais longo.
- ??, *? e +? são relutantes. Encontra o resultado mínimo.
- Depois do último carácter da fonte
- Entre carácteres depois de um resultado ter sido encontrado
- No início da fonte
- No início de uma fonte com tamanho zero
Usado para tokenização on-the-fly. Por defeito o delimitador é o espaço em branco.
Métodos principais
- Scanner(InputStream)
- Scanner(String)
- Scanner(File)
- String findInLine(String regex) - Usado em loops. Retorna null se não encontrar nada. Chamadas sucessivas encontram o próximo match.
- boolean hasNext() - Usado em loops. Não avança.
- String next() - Usado em loops. Obtém e avança para o próximo.
- boolena hasNextInt() - Usado em loops. Não avança.
- int nextInt() - Usado em loops. Obtém e avança para o próximo.
- boolean hasNextBoolean() - Usado em loops. Não avança.
- boolean nextBoolean() - Usado em loops. Obtém e avança para o próximo.
- useDelimiter(String regex)
Os métodos nextXXX só devem ser chamados se o método correspondente hasXXX retornar true. Caso contrário pode dar excepção.
String e Tokenizing
- String[] split(String regex) - Deve ser usado em Strings relativamente pequenas.
Formatação com printf e format da classe java.io.PrintStream
Ambos os métodos funcionam com os mesmos parâmetros: printf(String format, Object... argumentos).
O parâmetro format pode conter simultaneamente informação normal de literais String que não estão associados a quaisquer argumentos e dados de formatação específicos de argumentos.
Explicação da parte format:
%[arg_index$][flags][width][.precision] conversion
Nota: entre [] são opcionais
arg_index$ - Um inteiro imediatamente seguido de $. Indica qual argumento deve ser impresso nessa posição.
flag:
- - -> Alinhar à esquerda
- + -> Incluir o sinal (+ ou -)
- 0 -> Preencher com zeros
- , -> Usar separadores específicos do Locale
- ( -> Colocar entre parêntesis os números negativos
precision - Usado em números de vírgula flutuante e indica o número de dígitos depois da vírgula.
conversion -O tipo de argumento a formatar:
- b - Booleano
- c - Carácter (char)
- d -Inteiro
- f - Vírgula flutuante
- s - String
Métodos principais da classe java.lang.Object
- boolean equals(Object) - Este método, se não for overrided, apenas usa o operador == para as comparações. Se este método não for overrided, então o objecto não será usável, por exemplo, como chave em Hashtables, pois a não ser que ainda se tenha referência para a chave, nunca a mesma será encontrada. Fazendo override a este método então deve-se fazer override ao método hashcode (por causa do contrato do equals e do hashcode).
- int hashCode() - O overriding deste método deve usar as mesmas variáveis de instância usadas no overriding do método equals. Por esta razão se for efectuado o override deste método então deve-se fazer também o overriding do método equals (contrato do hashcode e do equals).
- String toString() - Se não for overrided, retorna o nome_da_classe@hashcode do objecto (hexadecimal sem sinal).
- final void notify()
- final void notifyAll()
- final void wait()
- void finalize()
- Reflexivo: x.equals(x) deve retornar true
- Simétrico: x.equals(y) = true se e só se y.equals(x) = true
- Transitivo: x.equals(y) = true e y.equals(z) = true => x.equals(z) = true
- Consistente: Múltiplas invocações de x.equals(y) consistentemente retornam true ou consistentemente retornam false, desde que os objectos não sejam modificados na informação usada no equals.
- x.equals(null) = false
- Se x.equals(y) = true => x.hashcode() = y.hashcode()
- Consistente: Múltiplas invocações no mesmo objecto, durante a execução de uma mesma aplicação Java, retornam o mesmo inteiro, desde que nenhuma informação usada na comparação equals seja alterada.
- Se x.equals(y) = true => x.hashcode() = y.hashcode()
- Se x.equals(y) = false não implica que x.hashcode() <> y.hascode()
- Se x.hascode() = y.hashcode não implica que x.equals(y) = true
Ordem Natural dos Caracteres
Espaço em branco < UPPERCASE < lowercase
Collections
Propriedades principais das colecções
- ArrayList e Vector - Iteração rápida e acesso aleatório rápido.
- LinkedList - Iteração rápida e remoção rápida. Boa para adicionar elementos ao início ou ao fim. Serve para concretizar uma pilha ou fila.
- HashSet - Acesso rápido. Sem duplicados e sem ordem.
- LinkedHashSet - Sem duplicados e com ordem de iteração pela a de inserção.
- TreeSet - Sem duplicados. Por defeito a ordenação é feita pela ordem natural (ascendente).
- EnumMap - A chave tem de ser um enum e tem de pertencer ao tipo indicado. Chaves null não são permitidas (dá NullPointerException). Valores null são permitidos.
- HashMap - Actualizações rápidas. Só uma chave null e múltiplos valores null.
- Hashtable - Actualizações rápidas. null não é permitido em lado nenhum.
- LinkedHashMap - Iteração rápida. Mantém a ordem de inserção. Itera pela ordem de inserção ou último acesso.
- TreeMap - Por defeito, a ordenação é feita pela ordem natural ascendente.
- ConcurrentSkipListMap - log(n). null não permitidos em lado nenhum. Ordem natural.
- PriorityQueue - Priority-in, Priority-out. Os elementos são ordenados pela sua prioridade relativa. O construtor pode levar um comparador no 2º argumento.
Classe | Map | Set | List | Queue | Ordered | Sorted | Identificadores | Duplicados |
---|---|---|---|---|---|---|---|---|
HashMap | X | Não | Não | Únicos(chave) | Sim (valores) | |||
Hashtable | X | Não | Não | Únicos(chave) | Sim (valores) | |||
TreeMap | X | Sim | Ordem Natural ou Costumizável | Únicos(chave) | Sim (valores) | |||
LinkedHashMap | X | Por Ordem de Inserção ou por Último Acesso | Não | Únicos(chave) | Sim (valores) | |||
ConcurrentSkipListMap | X | Ordem Natural | Não | NA | Sim (valores) | |||
EnumMap | X | Sim | Não | Únicos(chave) | Sim (valores) | |||
HashSet | X | Não | Não | NA | Não | |||
TreeSet | X | Sim | Ordem Natural ou Costumizável | NA | Não | |||
LinkedHashSet | X | Por Ordem de Inserção | Não | NA | Não | |||
ArrayList | X | Por Índice | Não | NA | Sim | |||
Vector | X | Por Índice | Não | NA | Sim | |||
LinkedList | X | X | Por Índice | Não | NA | Sim | ||
PriorityQueue | X | Sim | Por Prioridades ou Ordem Natural | NA | Sim |
Métodos principais da interface java.util.Set
- boolean add(Object)
- boolean remove(Object)
- int size()
- boolean contains(Object)
- Iterator iterator()
- Object[] toArray()
- Object[] toArray(Object[])
- boolean add(int, Object)
- boolean add(Object)
- Object get(int)
- boolean remove(int)
- boolean remove(Object)
- int size()
- boolean contains(Object)
- int indexOf(Object)
- Iterator iterator()
- Object[] toArray()
- Object[] toArray(Object[])
- Object peek() - Retorna o primeiro elemento da fila sem o remover
- Object pool() - Retorna o primeiro elemento da fila removendo-o
- boolean add(Object) - Adiciona o elemento à fila
- boolean offer(Object) - Adiciona o elemento à fila
- Object put(Object key, Object value)
- Object get(Object key)
- Object remove(Object key)
- int size()
- boolean contains(Object key)
- boolean contains(Object value)
- Set keySet()
Não esquecer que os Maps funcionam em dois passos:
- Usam o método hashCode() para encontrar o balde certo (se o hashCode do objecto usado como chave mudar, o Map irá procurar o objecto no local errado!)
- Usam o método equals() para encontrar o objecto no balde
Métodos principais da classe java.util.Collections
- int Collections.binarySearch(List, Object)- Os objectos na lista têm de implementar Comparable!
- int Collections.binarySearch(List, Object, Comparator)
- void Collections.sort(List) - Os objectos na lista têm de implementar Comparable!
- void Collections.sort(List, Comparator)
- Comparator Collections.reverseOrder(List) - Os objectos na lista têm de implementar Comparable!
- Comparator Collections.reverseOrder(Comparator)
- void Collections.reverse(List)
- int Arrays.binarySearch(Object[], Object)
- int Arrays.binarySearch(Object[], Object, Comparator)
- void Arrays.sort(Object[]) - Os objectos no Object[] têm de implementar Comparable!
- void Arrays.sort(Object[], Comparator)
- List Arrays.asList(Object[]) - A lista e o array ficam ligados um ao outro. O Object[] não pode ser um array de primitivos
- boolean equals(Object[], Object[])
- String toString(Object[])
- Object ceiling(Object) - Elemento mais pequeno, maior ou igual ao objecto
- Object heigher(Object) - Elemento mais pequeno, maior que o objecto
- Object floor(Object) - Elemento maior, menor ou igual ao objecto
- Object lower(Object) - Elemento maior, menor que o objecto
- Object poolFirst() - Remove e devolve a primeira entrada
- Object poolLast() - Remove e devolve a última entrada
- NavigableSet descendingSet() - Retorna um NavigableSet por ordem inversa
- NavigableSet/SortedSet headSet(Object, Boolean) - Retorna o subconjunto que termina no elemento Object (*)
- NavigableSet/SortedSet tailSet(Object, Boolean) - Retorna o subconjunto que começa no elemento Object (*)
- NavigableSet/SortedSet subSet(Object start, Boolean, Object end, Boolean) - Retorna o subconjunto que começa no elemento Object start e termina no elemento Object end (*)
Métodos importantes na classe java.util.TreeMap
- Object firstKey() - Retorna a primeira chave
- Object ceilingKey(Key) - Retorna a menor chave, maior ou igual a Key
- Object heigherKey(Key) - Retorna a menor chave, maior que Key
- Object floorKey(Key) -Retorna a maior chave, menor ou igual a Key
- Object lowerKey(Key) -Retorna a maior chave, menor que Key
- Object poolFirstEntry() - Retorna e remove o primeiro par chave-valor
- Object poolLastEntry() - Retorna e remove o último par chave-valor
- Map.entry lastEntry() -Maior chave no Map ou null se vazio.
- NavigableMap descendingMap() -Retorna um NavigableMap na ordem inversa
- NavigableMap/SortedMap headMap(Key, Boolean) - Submapa terminado em Key (*)
- NavigableMap/SortedMap tailMap(Key, Boolean) - Submapa começado em Key inclusivé (*)
- NavigableMap/SortedMap subMap(Key start, Boolean, Key end, Boolean) - Retorna o submapa começado em start e terminado em end (*)
Os seis métodos de TreeSet e TreeMap que retornam subconjuntos, retornam subconjuntos que estão ligados aos conjuntos originais. Pode-se efectuar operações no subconjunto que irão afectar também o conjunto original. Se se adicionar/remover elementos ao conjunto original, estes serão igualmente adicionados/removidos do subconjunto se os elementos estiveram dentro do intervalo. Se se adicionar um elemento ao subconjunto que esteja fora do intervalo deste, irá atirar uma excepção. O mesmo não acontece se este mesmo elemento for adicionado ao conjunto original!
No TreeSet e no TreeMap os seus elementos têm de implementar Comparable.
Collections e Código Legado
Na invocação de código legado com colecções que usam genéricos, se o código legado inserir algo na colecção que seja diferente do tipo especificado no genérico, não irá dar erro de Runtime (embora se se usar o tipo guardado numa operação supostamente de outro tipo irá dar excepção). Contudo, em tempo de compilação, chamadas a métodos legados com colecções que usam genéricos e que inserem elementos nas colecções (se a inserção for invocada do código não legado) irá dar um aviso (warning) do género: A classe usa operações não seguras ou não checadas. Usar -Xlint para ver detalhes.
Tomar em atenção que os métodos "get" das colecções retornam Object. Se a colecção não usar generics, então é obrigatório o uso de casts, inclusive para primitivos e respectivos wrappers. Não há autoboxing automático. No "add" já há autoboxing.
Pesquisa nas classes Arrays e Collections
O método binarySearch das classes Arrays e Collections retorna:
- >= 0 - Índice do elemento procurado
- < 0 - Índice que presenta o ponto de inserção. Para calcular devidamente: ABS(ponto de inserção -1)
Os Arrays/Collections têm de ser procurados com o mesmo tipo de ordenação que foi usado na ordenação dos mesmos (ordem natural ou usando um Comparator).
Em tudo o que envolva ordenação (Collections, Arrays, Sets ordenados, etc), os objectos têm de ser mutuamente comparáveis (do mesmo tipo)!
Interface java.lang.Comparable - (implements Comparable
- int compareTo(Object) - O Object pode ser implementado com o próprio tipo da classe (por causa dos generics)
- int compare(Object, Object) - Os Objects podem ser implementados com o próprio tipo da classe (por causa dos generics)
Métodos principais da classe java.util.Iterator
- boolean hasNext()
- Object next()
Generics
A informação de typing (do genérico) não existe em tempo de execução. Só em tempo de compilação. Todo o código "generics" é apenas para compilação.
Com generics, atribuir a uma referência de um supertipo, um objecto de um subtipo (ou do mesmo tipo) mas com um generic diferente do declarado, nunca irá compilar com generics. O tipo de uma declaração de variável tem de ser igual ao tipo que se passa. Não funciona nem com super nem subtipos.
Ou seja, o tipo de genérico da referência e o tipo de genérico do objecto ao qual se refere têm de ser idênticos. O polimorfismo aplica-se apenas ao tipo base.
Tipo_Base <Tipo_Genérico> = Tipo_Base<Tipo_Genérico>;
O mesmo acontece na invocação de métodos. Não há polimorfismo com generics.
O polimorfismo é permitido nos arrays. Em runtime a JVM sabe o tipo dos arrays, mas não sabe o tipo das colecções (por causa do compilador apagar o tipo - Type Erasure).
O uso de Tipo1, indica ao compilador que se pode aceitar qualquer subtipo (?) de genérico do tipo de argumento declarado (Tipo2). Esta indicação implica que nenhum objecto possa ser adicionado à colecção. Se tal suceder um erro de compilação ocorre. Esta indicação é uma excepção à regra do não polimorfismo dos generics.
? extends - Usa-se quer para classes quer para interfaces.
O uso de Tipo1, indica ao compilador que se pode aceitar qualquer tipo (?) genérico do indicado (Tipo2) e também qualquer supertipo do Tipo2. Ou seja, toda a hierarquia superior do Tipo2 e o próprio Tipo2 são aceites. Isto permite adicionar elementos à colecção.
O uso de Tipo1, indica ao compilador que se pode aceitar qualquer tipo (?) genérico. Contudo não se pode adicionar elementos à colecção.
Não se pode usar a notação ? (wildcard) na criação de objectos. Apenas é possível nas referências.
Criando classes genéricas (exemplos com classe genérica):
- public class Xpto
{... - Qualquer identificador Java é válido - private List
xpto2; -Usar o tipo da classe para o tipo da lista - public Xpto (List
x){... -Construtor que recebe uma lista do tipo da classe - public T getXpto(){... -Retorna-se T
- public void returnX(T qq)... -Recebe-se T como parâmetro
- T instânciaDeClasse - Como tipo de variável de classe
- T[] array - Como tipo de array
- public class useTwo
{ -Dois tipo parametrizados - public class Bla
{... -Género de limitador de tipo
- public
void make(T t){... - public
doda(T t){... - public
Radio(T t){... - Construtor
Convenções na documentação de API's:
- Element (colecções)
Type (usado em tudo excepto colecções)
Inner Classes
O código na Inner Class pode aceder aos membros da enclosing (outer) class, como se a inner class fosse parte da outer class. Uma instância da inner class tem acesso a todos os membros da outer class, incluindo aqueles marcados como private.
As inner classes são definidas dentro das {} da outer class.
Uma inner class não pode ter quaisquer declarações static.
Para se aceder à inner class tem de ser ter uma instância da outer class.
Exemplos:
Instanciar uma inner class de dentro da outer class: new InnerClass();
Instanciar uma inner class de fora da outer class: MyOuter.MyInner x = MyOuter.new MyInner(); (*)
Referenciar a inner class dentro dela própria: this
Referenciar a instância da outer class dentro da inner class: MyOuter.this
(*) Tem mesmo de se usar o nome da classe. Não se pode usar a instância.
Method-Local Inner Classes
Definida dentro de um método. Só pode ser instanciada dentro do método onde é declarada mas depois da declaração. Pode aceder a todos os membros da outer class (mesmo os privados). Contudo não consegue ver as variáveis locais do método a não ser que sejam marcadas como final. Este tipo de classes pode ser criada dentro de métodos estáticos (com as mesmas restrições aplicáveis a métodos estáticos).
Anonymous Inner Classes
Declaram uma nova classe que não tem nome, mas que é uma subclasse do tipo de declarado no new.
Ex: Popcorn p = new Popcorn(){....};
Também pode implementar uma interface.
Tomar em atenção que só faz sentido implementar ou fazer overriding a métodos da superclasse, pois a variável de referência é sempre a da interface/superclasse (no exemplo acima: Popcorn). Contudo é possível fazer overloading ou criar novos métodos. Estes nunca poderão é ser invocados de fora.
Aplicam-se as mesmas regras das inner classes.
Argument-Defined Anonymous Inner Classes
Definida mesmo dentro de uma chamada a um método como argumento.
Aplicam-se as mesmas regras das inner classes.
Static Nested Classes
É pura e simplesmente um membro estático da enclosing class. Aplicam-se todas as restrições dos métodos static.
Instanciação de fora: Outer,Nest x = new Outer.Nest();
Instanciação dentro da Outer é feita de modo normal.
Nota: Tomar em atenção que nas Anonymous Inner Classes e Argument-Defined Anonymous Inner Classes os construtores são invocados! Ex: new Popcorn() - Invoca o construtor vazio. new Popcorn(10) - O construtor recebe um int, etc.
Métodos Principais da classe java.lang.Thread (implements java.lang.Runnable)
- Thread()
- Thread(String name)
- Thread(Runnable) - Neste caso o método run() invocado é o da instância passada.
- Thread(Runnable, String name) - Neste caso o método run() invocado é o da instância passada.
- public void run() - A classe Thread espera que exista o método run() sem argumentos, e executa este método numa chamada separada (numa stack diferente) depois da thread começar. Este método é invocado pelo start().
- start() - Invoca o método run(). Começa a nova thread de execução. A thread passa para o estado Runnable. Assim que poder executar invoca o run(). O método start() apenas pode ser invocado uma vez. Uma IllegalThreadStateException (não checada) é atirada se o método for invocado mais do que uma vez.
- boolean isAlive() - true se o método start() já foi invocado; false caso start() ainda não tenha sido invocado ou se o método run() já terminou.
- public final void join() throws InterruptedException - Faz com que uma thread espere até que a outra entre no estado Dead.
- String getName() - Devolve o nome da thread
- static Thread currentThread() - Devolve a corrente thread de execução
- void setName(String)
- long getId() - Devolve o id da thread
- static void sleep(long milis) throws InterruptedException - (*)
- static void yeld() - Faz com que a thread passe do estado Running para o estado Runnable. Nada é garantido [dependa da JVM] (*)
- public final setPriority(int) - Inteiro entre 1 e 10 (depende a JVM).
Métodos Principais da Interface java.lang.Runnable
- public void run() - Comportamento igual ao método run() da classe Thread. É invocado pelo start().
- Criar a classe que implementa Runnable
- Passar a instância para dentro de uma nova Thread (new Thread(Runnable))
Nota : Tomar em atenção que a invocação directa do método run() (sem ser pelo start()) não cria um nova thread de execução!