Prévia do material em texto
Linguagem Java: conceitos essenciais de desenvolvimento para dispositivos móveis Apresentação Para o desenvolvimento de aplicativos Android é utilizada a linguagem de programação Java que, não por acaso, é uma das linguagens de programação mais utilizada no mundo. De certa forma foi uma escolha lógica para a plataforma Android, levando em conta que Java é uma linguagem de programação poderosa, gratuita, com o código-fonte aberto e milhões de desenvolvedores já conhecem a linguagem. A linguagem Java é orientada a objetos e conta com uma ampla biblioteca de classes, que ajuda o desenvolvedor a construir aplicações poderosas em menor tempo, visto que fornece recursos prontos para o desenvolvedor configurá-las e utilizá-las da forma que achar adequado. Nesta Unidade de Aprendizagem, você vai conhecer a linguagem Java, seu conceito de classes e seus principais tipos de dados. Também irá estudar o conceito de orientação a objetos em Java, analisando vários recursos disponíveis na linguagem, visando a desenvolver uma visão sólida da linguagem Java aplicada ao desenvolvimento de aplicativos Android. Bons estudos. Ao final desta Unidade de Aprendizagem, você deve apresentar os seguintes aprendizados: Descrever as características da linguagem Java: classes e tipos de dados.• Identificar os principais conceitos de programação orientada a objetos com Java.• Operacionalizar a utilização do Java como linguagem-base para o desenvolvimento de aplicações Android. • Infográfico Recursos em um dispositivo móvel atualmente podem não ser extremamente limitados como no passado. Porém, o seu uso consciente é recomendável por vários motivos. Um exemplo é o consumo de bateria que, normalmente, é um recurso crítico do dispositivo móvel. Logo, alto processamento e grandes quantidades de memoria RAM em uso consomem quantidades substanciais de bateria do dispositivo, limitando o seu tempo útil sem a necessidade de recarregar a bateria. Confira, no Infográfico, mais informações sobre como minimizar o uso de processamento e memória RAM consumidos por seu aplicativo Android, utilizando de forma consciente os tipos de dados disponíveis no Java. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. https://statics-marketplace.plataforma.grupoa.education/sagah/d815ba0b-e6ce-4fc8-aa80-454eee539694/8a9c9250-7b01-455b-80d8-07b7f7d6e45e.jpg Conteúdo do livro Existem diversas linguagens de programação disponíveis no mercado, cada uma com suas características e funcionalidades. Dentre todas as possibilidades, o Android selecionou o Java como a linguagem indicada para o desenvolvimento de seus aplicativos. É possível elencar diversos motivos para isso. Antes mesmo do Android existir, o Java já era uma das linguagens de programação mais utilizadas no mundo e já tinha versões destinadas às mais diversas áreas, inclusive dispositivos móveis. Logo, a escolha do Java para o Android foi um ponto chave para a plataforma, uma vez que já era uma linguagem madura, utilizada na área em que o Android iria atuar e tinha as características de uma linguagem de programação moderna, possibilitando, por exemplo, a orientação a objetos. Java já tinha uma ampla quantidade de bibliotecas, fornecendo recursos e funcionalidades para o desenvolvedor criar aplicações complexas em um curto espaço de tempo. No capítulo Linguagem Java: conceitos iniciais, da obra Desenvolvimento para dispositivos móveis, você vai conhecer as características da linguagem de programação Java, identificando as funcionalidades de suas classes e os seus diversos tipos de dados disponíveis para utilização. Também irá compreender, por meio de exemplos práticos, o conceito de linguagem de programação orientada a objetos, bem como as funcionalidades que tais características disponibilizam ao desenvolvedor. Verá ainda as funções presentes na linguagem para realização de operações, tomada de decisão e diversos outros recursos imprescindíveis para o desenvolvimento de um aplicativo Android. Boa Leitura. DESENVOLVIMENTO PARA DISPOSITIVOS MÓVEIS Diego Bittencourt de Oliveira Linguagem Java: conceitos essenciais Objetivos de aprendizagem Ao final deste texto, você deve apresentar os seguintes aprendizados: � Descrever as características da linguagem Java, como suas classes e tipos de dados. � Identificar os principais conceitos de programação orientada a objetos com Java. � Operacionalizar a utilização do Java como linguagem base para o desenvolvimento de aplicações Android. Introdução Neste capítulo você conhecerá a linguagem de programação Java, que é a linguagem de programação nativa da plataforma Android. Por ser muito popular, esta linguagem foi a escolha mais adequada como lin- guagem de programação padrão da plataforma. Isso se deve ao fato de existirem muitos desenvolvedores experientes nesta linguagem. Assim, a plataforma já inicia com milhões de desenvolvedores especializados em sua linguagem de programação base. O Java também é uma linguagem de programação potente, sendo totalmente orientada a objetos, além de possuir uma enorme biblioteca de classes muito sólida e atualizada de forma regular. No decorrer deste capítulo, conheceremos melhor as características das classes Java, bem como os tipos de dados que a linguagem de programação disponibiliza para o seu desenvolvedor. Veremos, também, os conceitos de programação orientada a objetos com Java e aprenderemos, ainda, a utilizar Java como linguagem padrão para o desenvolvimento de aplicações para Android. Linguagem Java: classes e tipos de dados Segundo Deitel, Deitel e Deitel (2015), a linguagem Java para aplicativos Android é semelhante e, ao mesmo tempo, muito diferente de outras aplicações desenvolvidas nesta linguagem. Um desenvolvedor com experiência em Java terá facilidade em desenvolver aplicativos para Android, mas compreenderá a diferença mencionada. Já um desenvolvedor com pouca experiência nesta linguagem deve buscar se familiarizar. Como já mencionado, Java é uma linguagem de programação orientada a objetos, ou seja, baseada na modelagem de objetos e na comunicação que estes possuem entre si. Em uma situação de analogia a um objeto real, pode-se definir o objeto caneca, algumas de suas propriedades seriam a cor, a capacidade máxima e a quantidade de café que possui. Em uma linguagem orientada a objetos, podemos definir objetos canecas e acessar suas propriedades. Poderíamos também enviar mensagens para os objetos, questionando- -os sobre a quantidade de café existente em cada caneca. Assim, é possível observar que é possível criar e manipular qualquer objeto, fazendo com que estes realizem diversas funções em um aplicativo. Em uma situação mais cotidiana da plataforma Android, temos o objeto câmera, que representa a câmera física do dispositivo. Por meio deste objeto, podemos manipular a câmera para que tire uma foto com base nas propriedades que definimos e nos métodos que chamamos para configurá-la. Antes de criarmos uma classe que represente um objeto, temos de estudar os tipos de dados disponíveis, uma vez que a programação é basicamente um trabalho com dados. Segundo Goodrich e Tamassia (2013), Java possui basicamente dois grupos de tipos de dados: � tipos primitivos — correspondem a dados mais simples ou escalares; � tipos por referência — correspondem a tipos de dados representados por classes, ou seja, todos os outros tipos de dados não primitivos. Na Figura 1, podemos observar os tipos primitivos de dados existentes na linguagem Java, bem como os limites de valores que estes tipos podem armazenar. Por exemplo, uma variável do tipo byte não pode armazenar o valor 400, visto que esta só armazena dados até 127 positivo. Linguagem Java: conceitos essenciais2 Figura 1. Tipos primitivos de dados. Fonte: Schützer e Massago (2008, documento on-line). Os tipos por referência são classes, conforme já citamos e, por convenção denomenclatura, as classes em Java são nomeadas com a primeira letra do nome em maiúsculo. Por exemplo, Goodrich e Tamassia (2013) relatam que String é um dos tipos de dados por referência mais comuns da linguagem Java, sendo que a String é basicamente uma lista de elementos char. Ou seja, podemos armazenar a frase “Android é uma boa plataforma” em uma variável do tipo String, em que cada uma das letras seria um char. 3Linguagem Java: conceitos essenciais Na linguagem Java você pode inserir frases e comentários junto ao código do seu aplicativo, sem que estas informações realizem qualquer interferência no fluxo do programa. Abaixo temos um exemplo: //Este é um comentário de uma linha O texto após as // não é interpretado pelo compilador do Java, ou seja, serve para que os desenvolvedores escrevam informações pertinentes no código, seja para identificar o que um determinado trecho de código faz ou outra informação qualquer. Também podemos criar comentários de várias linhas em Java. Neste caso, o comentário é realizado utilizando um bloco, conforme exemplo abaixo (o comentário inicia com /* e é finalizado com */): /* Início do comentário, Segunda linha do comentário e o Final do comentário */ Uma variável é basicamente um recipiente que possui um determinado tipo, sendo que este define o tipo de dado que a variável irá armazenar. Isso se deve ao fato de a linguagem Java ser estaticamente “tipada”, ou seja, devemos informar ao Java o tipo da variável que estamos definindo. Abaixo temos um exemplo: String Cliente = "Alberto Ribeiro"; No exemplo acima, criamos uma variável do tipo String, cujo nome é Cliente. Ainda podemos identificar o operador de atribuição = (veremos adiante outros operadores, sendo o operador de atribuição = um dos mais básicos da linguagem Java) e o valor que está sendo atribuído Alberto Ribeiro, no final temos o identificador do final do comando ;. Ou seja, na variável Cliente temos o texto indicado, sendo o valor armazenado na variável que criamos. Linguagem Java: conceitos essenciais4 O conceito básico de uma classe é apresentado abaixo, em que temos uma classe Pessoa com um atributo do tipo String chamado nome e um construtor (void Pessoa(String nome)) que inicializa o atributo nome com o valor, passado no construtor: class Pessoa { String nome; Pessoa(String nome) { this.nome = nome; } } Observe, no exemplo acima, a declaração this. Quando utilizamos essa declaração, estamos informando que o atributo utilizado está declarado na classe. Logo, this.nome pertence à classe e nome se refere ao parâmetro passado ao construtor. Abaixo, podemos observar um modelo conceitual de classes, [class|abstract|interface] [Nome da Classe] { [Construtor] [Atributos ou Variáveis] [Métodos] } em que: � [class|abstract|interface] — refere-se ao tipo, que pode ser class, ou seja, uma classe do tipo class, ou uma interface, sendo que este define uma espécie de padrão ou interface padrão que uma classe deve implementar. Ainda possuímos a abstract class, que é uma classe abstrata, sendo que esta pode conter métodos implementados e não implementados (os conceitos de interface e classe abstrata serão desenvolvidos no decorrer deste capitulo); � [Nome da Classe] — deve ser único no pacote atual e seguir as mesmas regras de nomenclatura dos métodos; 5Linguagem Java: conceitos essenciais � [Construtor] — um método que é chamado por padrão ao utilizar (instanciar) uma classe, sendo que este método pode inicializar os atributos da classe ou simplesmente não conter implementação alguma. Deve possuir o mesmo nome da classe e sua existência é obrigatória, mesmo que não contenha implementação, no caso de se tratar de uma interface que não possui nenhum construtor; � [Métodos] — segue o padrão já mencionado anteriormente para métodos, com a diferença de que, em interfaces, não temos a imple- mentação do método, apenas sua definição. Os exemplos ficariam void Calcula ();, float ValorPI(); e float Total (int Qtd, flota Preco); e a classe que implementar essa interface deve também realizar a implementação destes métodos. As classes em Java, além das variáveis e dos atributos, possuem ainda métodos, sendo que os métodos podem realizar diversos comandos. A estrutura de um método pode ser observada abaixo: [retorno] [nome do método]([tipo dos dados] [nome do parâme- tro], …) { [código do método] [return] [valor do retorno] } Observe, a seguir, o que significa cada termo da estrutura de um método, como vimos acima: � [retorno] — é o tipo de dado (seja ele primitivo ou do tipo referência) que o método irá retornar. Uma vez informado, é obrigatório que seja retornado um valor. Para não retornar nenhum valor, informamos ao invés do tipo da variável a palavra void, que significa que nada será retornado; � [nome do método] — nome que remeta à funcionalidade do método. As únicas ressalvas ao nomear o método são que caracteres especiais e espaços não devem ser utilizados e o nome do método não pode conter espaços. Neste caso, podemos utilizar o caractere underline (por exemplo, Nome _ Pessoa); � [tipo dos dados] [nome do parâmetro] — um método pode não possuir parâmetros. Neste caso, utilizam-se os ( ), sem nenhuma informação entre os parênteses. Porém, podemos informar um ou mais Linguagem Java: conceitos essenciais6 parâmetros, em que o tipo de dados deve ser informado logo após o nome do parâmetro, que segue a mesma regra de nomenclatura do método, sendo que as várias declarações de parâmetros devem ser separadas por ,. Observe que os parâmetros devem receber diferentes nomes; � [código do método] — conjunto de códigos que o método realiza; � [return] [valor do retorno] — esta linha pode não existir se o retorno do método for void. Porém, caso um retorno seja informado, o comando return seguido do valor ou da variável do mesmo tipo do retorno deve ser também informado. Exemplo 1 Exemplo 2 Exemplo 3 class Area { float area; float lado; void Calcula (){ this.Area = this.Lado * this.Lado } } class Valores { float ValorPI(){ return 3.14f; } } class Produto { float Total (int Qtd, float Preco){ return Qtd * Preco; } } Quadro 1. Exemplos de métodos No Quadro 1 observamos três exemplos de possíveis métodos: � exemplo 1 — o this indica que as variáveis do método pertencem à classe a qual o método também pertence e, no caso, o método está atribuindo ao atributo area o resultado da operação de multiplicação (representada pelo operador de multiplicação *) do atributo lado por ele mesmo (possivelmente seria a área de um quadrado, portanto os lados seriam iguais, assim basta armazenar o tamanho de um lado); � exemplo 2 — método que retorna um valor do tipo float, no qual temos o retorno do valor 3.14f , em que f indica que o valor é do tipo float; � exemplo 3 — o método Total recebe dois parâmetros Qtd e Preco, realizando a multiplicação desses valores, retornando o resultado deste cálculo. 7Linguagem Java: conceitos essenciais Conceitos e modificadores Segundo Deitel, Deitel e Wald (2016), na linguagem Java está disponível um recurso muito importante para o desenvolvimento e a estruturação de um pro- jeto: os moderadores de acesso. Estes são empregados para restringir o acesso a um método, atributo ou até a uma classe. Entretanto, independentemente do moderador escolhido, um atributo ou método é sempre acessível, isto é, pode ser chamado, a partir de qualquer outro método contido na mesma classe. Os moderadores de acesso mais comuns do Java são os seguintes: � public — um atributo ou método que utiliza este moderador é público e pode ser chamado a partir de métodos contidos em qualquer outra classe, sendo esta a condição de menor restrição da linguagem; � protected — utilizando este moderador, o atributo ou método pro- tegido pode ser chamado por todas as classes existentes no pacote da classeem questão; � private — quando um atributo ou um método é privativo na classe que o contém e seu uso é vedado a qualquer outra classe, ou seja, so- mente métodos da própria classe podem executar uma chamada a este. Java é uma linguagem amplamente utilizada em diversas áreas, não somente para programação Android, mas também em desenvolvimentos para desktops, Web e outros. Nos links a seguir você pode acessar o site oficial do Java, além da página com a documentação da linguagem e outras informações. https://qrgo.page.link/E4PEm https://qrgo.page.link/yaAq8 Além dos moderadores de acesso, os métodos e atributos ainda possuem outros modificadores, voltados a outras características. Um destes modifica- dores é o modificador static, que pode ser utilizado em classes, métodos e atributos. Uma vez utilizado em um método, este poderá ser acessado por qualquer classe (observando o moderador de acesso) sem a necessidade de instanciá-la. Um método static não pode acessar qualquer variável decla- Linguagem Java: conceitos essenciais8 rada dentro de uma classe, exceto no caso de a variável também ser declarada como static. Mas a situação contrária é permitida: um método comum pode acessar métodos e atributos static. Abaixo, temos um exemplo de método do tipo static com o nome getPI. Observe que não instanciamos a classe Area: public class Area { public static float getPI(){ return 3.14f; } } // Podemos utilizá-lo da seguinte maneira: Area.getPI(); Outro detalhe sobre o modificador static é que, uma vez utilizado em uma classe (static class), obrigatoriamente toda a classe (incluindo métodos e atributos) deve ser declarada com o modificador static. Segundo Goodrich e Tamassia (2013), alguns dos conceitos mais importan- tes da linguagem Java são o encapsulamento, a herança e o polimorfismo. O encapsulamento é uma característica muito importante que trata da capacidade de isolar informações do restante do programa. Assim, uma vez construída uma determinada classe, o desenvolvedor não precisa mais se preocupar com suas características internas, já que realiza as chamadas dos métodos. Caso seja necessário realizar alguma alteração em um método, ao realizar esta alteração todos os pontos que o utilizam automaticamente irão receber tais alterações. Dessa forma, o desenvolvedor pode garantir que a informação não será corrompida acidentalmente pelo resto do programa, tornando-a robusta e confiável. Para um desenvolvedor experiente, o conceito de modificadores pode ser muito simples, mas para desenvolvedores sem tanta experiência, o uso de modificadores pode ser bem confuso. Ao iniciar a programação de aplicativos sem conhecer a fundo a linguagem de programação, procure utilizar modificadores mais simples, como o public e o private. À medida que for adquirindo experiência, aventure-se a utilizar modificadores mais complexos. 9Linguagem Java: conceitos essenciais A herança é um conceito importante da linguagem Java. Nesse processo, uma classe que implementa ou é estendida a outra herda todos os seus métodos e atributos. Na Figura 2 temos um exemplo clássico de herança, em que a classe Animal é estendida à classe Mamífero, que por sua vez é estendida à classe Cachorro. Ao instanciar uma classe Cachorro, este poderá utilizar os métodos nascer, morrer e mamar, pois estes serão herdados das classes Animal (métodos nascer e morrer) e Mamífero (método mamar). Para criar uma classe Gato, por exemplo, seria necessário apenas estendê-la à classe Mamífero e implementar o método miar. Figura 2. Exemplo de classes Java, demonstrando o conceito de herança. Linguagem Java: conceitos essenciais10 Temos, ainda, o modificador abstract, no qual é possível declarar um método sem o implementar. Dessa forma, uma classe que implementa a classe que contém métodos abstract deve repetir sua declaração abstrata, imple- mentando-a ou não; porém, em algum momento ela deve ser implementada. Funciona como uma espécie de lembrete para que alguma classe derivada complete a declaração fornecendo um corpo. Na Figura 3 temos um exemplo de classe abstrata, em que a classe Animal é do tipo abstract e já possui os métodos nascer e mamar implemen- tados. No entanto, os métodos voz e alimentar são abstratos e devem ser implementados em classes que forem estendidas à classe Animal. No caso, a classe Cachorro foi estendida à classe Animal e implementou os métodos abstratos voz e alimentar com a implementação adequada. Figura 3. Exemplo de classes Java, demonstrando o conceito de classe abstrata. 11Linguagem Java: conceitos essenciais O modificador final identifica que nenhuma classe derivada pode alterar ou redefinir este método ou atributo. Dessa forma, um método declarado como final deve ser obrigatoriamente implementado. No exemplo abaixo, uma classe estendida à classe Area não poderá criar uma nova implementação para o método getPI. public class Area { public final float getPI(){ return 3.14f; } } Segundo Deitel, Deitel e Deitel (2015), a interface é uma funcionalidade da orientação ao objeto utilizado em Java que define ações que devem ser obrigatoriamente executadas, mas que cada classe pode executar de forma diferente. As interfaces contém valores constantes ou assinaturas de métodos que devem ser implementados dentro de uma classe. No caso da Figura 4, podemos observar ainda uma utilização prática das interfaces, em que a interface InterfacePessoa prevê todos os métodos necessários para uma determinada implementação, sendo que esta interface foi implementada pela classe abstrata Pessoa, que implementou os métodos getIdade e setIdade, visto que em uma implementação das classes Mulher e Homem os métodos indicados teriam uma implementação idêntica para ambos os objetos, podendo, dessa forma, serem herdados por estes. Uma peculiaridade está no método getSexo, cuja implementação se deu na classe Mulher e Homem, em virtude dessa informação ser diferente em ambos os casos. Linguagem Java: conceitos essenciais12 Figura 4. Exemplo de classes Java, demonstrando a utilização de interfaces. Um dos conceitos mais utilizados da linguagem Java é o polimorfismo, que promove a reutilização contínua dos códigos, ou seja, possibilita que algo assuma várias formas. No contexto da programação orientada a objetos (sendo o Java, conforme já mencionado, uma linguagem totalmente orientada a objetos), ele nos mostra como um método pode assumir formas diferentes das inicialmente implementadas e agir de modo que possa ser utilizado por outra classe. Na Figura 2, em que observamos o conceito de herança (os conceitos de herança e polimorfismo trabalham lado a lado na linguagem Java), podemos observar o conceito de polimorfismo também quando a classe Pessoa assume a forma das classes Homem e Mulher. 13Linguagem Java: conceitos essenciais Na Figura 5 podemos identificar outra face do polimorfismo. No exemplo, os métodos ImprimeIdade, ImprimeSexo e ImprimeSexoIdade recebem, por parâmetro, uma classe Pessoa, sendo que esta pode ser do tipo Mulher ou Homem e, de acordo com essa passagem de parâmetros, podemos ter a impressão do respectivo sexo e idade (a idade, no caso, depende do valor atribuído à variável Idade, presente na classe Pessoa). Essa passagem de parâmetro genérica se dá pelo fato de que uma mulher ou um homem são pessoas, caracterizando um conceito do polimorfismo. Figura 5. Exemplo de classes Java, demonstrando o conceito de polimorfismo. Outro conceito do polimorfismo presente na Figura 5 é a sobrecarga, em que possuímos na classe Auxiliar três métodos imprime e somente é possível possuir estes três métodos com o mesmo nome, em virtude dos métodos possuírem parâmetros diferentes. No caso, o método imprime, que realiza a impressão da idade, recebe um parâmetro do tipo int, enquanto o método que realiza a impressão do sexo recebe um parâmetro do tipo String. Frente à Linguagem Java: conceitos essenciais14sobrecarga prevista no polimorfismo, eles são diferentes; logo, são permitidos. Ainda temos o caso do método Imprime, que recebe dois parâmetros que se diferenciam ainda mais dos outros e, com isso, também se tornam válidos. Java na prática: operadores, condicionais, laços de repetição Na linguagem Java é muito comum a realização de cálculos matemáticos ou uma comparação entre variáveis, assim como a repetição de uma determinada rotina até que uma condição seja atingida. Para que isso seja possível, o Java possui operadores. Na Figura 6 podemos observar esses operadores disponíveis na lingua- gem Java (na ilustração eles estão divididos em grupos, conforme suas funções). Figura 6. Tipos de operadores disponíveis na linguagem Java. Fonte: Schützer e Massago (2008, documento on-line). Segundo Deitel, Deitel e Deitel (2015), os operadores de atribuição, como o próprio nome sugere, são capazes de atribuir um determinado valor a algo, normalmente uma variável. Um exemplo seria uma variável x do tipo inteiro (no caso int), à qual podemos atribuir o valor 10 utilizando a simples ex- pressão x = 10. Aliado a este operador de atribuição, temos os operadores de adição, subtração e divisão. Na Figura 7 é possível observar operações de adição (operador +), subtração (operador -), multiplicação (operador *) e divisão (operador /), além de uma operação envolvendo duas variáveis. Existe, ainda, o operador módulo %, que calcula o resto de uma divisão. Por exemplo, x = 5 % 2, em que x ao final da operação será igual a 1, visto que este é o resto da divisão. 15Linguagem Java: conceitos essenciais Podemos, ainda, utilizar o operador de atribuição = combinado aos ope- radores matemáticos, resultando em expressões mais simples. Por exemplo, a expressão de soma x = x + 10 (operação de soma existente na Figura 7) poderia ser codificada utilizando o operador de soma combinado ao operador de atribuição, gerando a expressão x += 10, que é exatamente o mesmo que x = x + 10, sendo que este pode ser realizado com as demais operações matemáticas. Figura 7. Operador de atribuição = em operações matemáticas. Também temos operações de atribuição que não utilizam o operador =. Neste caso, estamos falando dos operadores de incremento e decremento. Por exemplo, a operação x = x + 1, que também é idêntica à operação x += 1, pode ser escrita de forma ainda mais simplificada, utilizando o operador unário de incremento, resultando em x++. Em todos os exemplos citados serão somados 1 ao valor já existente em x. Os sinais unários são utilizados para identificar se um número é positivo (sinal unário +) ou negativo (sinal unário -), sendo que ao não informar o sinal unário de um número, o programa irá entender que se trata de um nú- mero positivo. Vamos imaginar a variável do tipo byte recebendo o valor 10 negativo. Neste caso, teríamos o código byte z = -10, ou seja, a variável z será igual a 10 negativo. Linguagem Java: conceitos essenciais16 Ao declarar os nomes de variáveis e classes, você deve tomar cuidado para não uti- lizar as palavras reservadas da linguagem Java. Por exemplo, a palavra int deve ser utilizada somente em seu propósito original, ou seja, declarar uma variável deste tipo. Portanto, você não pode colocar o nome de uma variável como int. A seguir, temos uma lista de palavras reservadas da linguagem: abstract, continue, for, new, switch, assert, default, goto, package, synchronized, boolean, do, if, private, this, break, double, implements, protected, throw, byte, else, import, public, throws, case, enum, instanceof, return, transient, catch, extends, int, short, try, char, final, interface, static, void, class, finally, long, strictfp(2), volatile, const, float, native, super e while. Deitel, Deitel e Deitel (2015) definem os operadores de comparação como ferramentas de suma importância para o desenvolvimento de qualquer software, seja ele um aplicativo Android ou outro. Essa afirmação se deve ao fato de que estes operadores fornecem a linguagem o poder de dar ao código a to- mada de decisão. Por exemplo, se você deseja comprar um produto que custa R$ 12,00 mas possui apenas R$ 10,00 na carteira, a compra não pode ser concluída, visto que você não possui dinheiro suficiente. Para inserirmos essa tomada de decisão em um código Java, utilizamos a cláusula condicional if, que significa “se”. Assim, em uma linguagem formal, já podemos escrever o exemplo, ficando “se o dinheiro na carteira for maior ou igual ao valor do produto, então a compra pode ser realizada; caso contrário, você não possui dinheiro suficiente”. Em Java, teríamos: float produto = 12f; float carteira = 10f; if (carteira >= produto) { // Entao você possui dinheiro suficiente } else { //Você não pode comprar, dinheiro insuficiente } //Segue o fluxo do programa 17Linguagem Java: conceitos essenciais Dessa forma, já introduzimos também o operador de comparação maior ou igual >=. Podemos utilizar também os demais operadores de comparação: � >: compara se um valor é maior que outro; � <: compara se um valor é menor que outro; � <=: compara se um valor é menor ou igual a outro; � ==: comparação simples entre dois valores, verificando se ambos são iguais e apenas iguais; � !=: comparação simples entre dois valores, verificando se ambos são diferentes. A cláusula if pode possuir várias operações de comparação utilizando a cláusula elseif(comparação), ou seja, podemos ter o if(comparação 1) com a sua comparação, seguido de quantos elseif(comparação2..3..4) forem necessários para a lógica do programa, podendo finalizar com o else, que significando que caso nenhuma comparação seja satisfeita, o código da cláusula else será executado, observando também que somente o if é obrigatório. Portanto, podemos utilizar o elseif e o else apenas se na lógica da rotina for necessário. Dentro das cláusulas condicionais, ainda possuímos a cláusula switch, que pode simplificar a execução de várias comparações de uma variável. No link a seguir você pode obter mais informações sobre a cláusula switch. https://qrgo.page.link/ungAZ Para completar este conjunto de operações visto até então, temos os laços de repetição, sendo o mais simples deles o while, que em uma linguagem formal seria “enquanto uma comparação for satisfeita, repete um conjunto de código”. Linguagem Java: conceitos essenciais18 Figura 8. Exemplos de operação de “while” e de “do...while”. Fonte: Schützer e Massago (2008, documento on-line). Na Figura 8, encontramos alguns exemplos do bloco de repetição while, sendo: � exemplo 1 — a rotina presente no while é executada enquanto o valor de k for menor que 10, ou seja, será executado até que k seja incrementado pelo operador unário ++ e atingir o valor 10; � exemplo 2 — nesta rotina, h é inicializado com zero e a rotina presente no while será executada até que h mude para outro valor, sendo que, no caso, isso ocorrerá somente quando o teste if for satisfeito; � exemplo 3 — a variável i é inicializada com o valor 10 e, assim, o bloco while não é executado, pois somente seria executado caso i fosse menor ou igual a cinco. Dessa forma, o programa segue seu fluxo normal após o while; � exemplo 4 — no do while, a rotina presente neste bloco é executada pelo menos uma vez, podendo repetir novamente se ao final da primeira execução o teste do while for satisfeito. No exemplo, a rotina será executada apenas uma vez. 19Linguagem Java: conceitos essenciais O laço de repetição for tem uma complexidade um pouco maior. Na Figura 9 temos um exemplo ilustrado de uma implementação do laço for. Para um melhor entendimento, vejamos mais informações abaixo: � int x = 0; — este código é executado apenas uma vez e é chamado de inicialização. Nesta inicialização temos a declaração da variável x e sua inicialização com o valor zero, sendo que ela não será executada novamente. Observe que a variável x poderia estar declarada em outro locale, neste caso, ela poderia ser inicializada apenas com x = 0; ou nem ser inicializada, contando apenas com a presença do ;; � x <= 10; — esta é a condição que verifica se o laço deve ser repetido. Após a inicialização ele é verificado e, caso seja satisfeito, a rotina do laço é executada uma vez; � x++ — este é o incremento (poderia ser decrementado, também utili- zando -- ou outros operadores, como o += 10) ao final da execução da rotina do laço de repetição. A variável x é incrementada e após o seu incremento a condição (x <= 10) é verificada, ou seja, quando x atingir o valor 11, o laço de repetição não será repetido e o programa seguirá seu fluxo. Figura 9. Ilustração do uso do for. Fonte: Schützer e Massago (2008, documento on-line). É importante salientar que os laços de repetição while e for também podem ser interrompidos a qualquer momento, executando o comando break;. Linguagem Java: conceitos essenciais20 DEITEL, P.; DEITEL, H.; DEITEL, A. Android: como programar. 2. ed. Porto Alegre: Book- man, 2015. 690 p. DEITEL, P.; DEITEL, H.; WALD, A. Android 6 para programadores: uma abordagem baseada em aplicativos. 3. ed. Porto Alegre: Bookman, 2016. 618 p. GOODRICH, M. T.; TAMASSIA, R. Estruturas de dados e algoritmos em Java. 5. ed. Porto Alegre: Bookman, 2013. 736 p. SCHÜTZER, W.; MASSAGO, S. Tipos de dados. In: SCHÜTZER, W.; MASSAGO, S. Tutorial de programação Java. São Carlos: Departamento de Matemática, Universidade Federal de São Carlos, 2008. Disponível em: https://www.dm.ufscar.br/profs/waldeck/curso/ java/part22.html. Acesso em: 16 jun. 2019. Leitura recomendada SCHILDT, H. Java para iniciantes: crie, compile e execute programas Java rapidamente. 6. ed. Porto Alegre: Bookman, 2015. 704 p. 21Linguagem Java: conceitos essenciais Dica do professor Conhecer todas as funcionalidades da linguagem de programação é muito imporante para o desenvolvedor. Porém, alguns aspectos também devem ser levados em consideração como, por exemplo, a organização do código desenvolvido, além da escrita de informações que ajudam os desenvolvedores envolvidos no projeto a compreenderem o código-fonte que compõe o projeto. Confira, na Dica do Professor, informações para organizar o código, inserir informações pertinentes do seu desenvolvimento, além de práticas que podem ajudar o iniciante em linguagem de programação a minimizar problemas desnecessários, aumentando a velocidade da sua curva de aprendizagem. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. https://fast.player.liquidplatform.com/pApiv2/embed/cee29914fad5b594d8f5918df1e801fd/e3dd43e1e6c8f51b534518475c365526 Saiba + Para ampliar o seu conhecimento a respeito desse assunto, veja abaixo as sugestões do professor: Polimorfismo Você sabe o que é o polimorfismo? Se não sabe ou caso queira saber mais, então não deixe de acessar este conteúdo e compreender esse conceito essencial para desenvolver códigos Java com qualidade. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Vetores em Java No artigo a seguir você irá saber mais sobre vetores em Java, recursos essencial para se trabalhar com listas, arrays, além de fornecer muitas possibilidades de aplicação. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. Boas práticas de programação Em programação, boas práticas sempre são bem-vindas, uma vez que elas tendem a facilitar a vida do desenvolvedor de softwares. Confira no artigo a seguir algumas boas práticas de programação voltadas à linguagem Java. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. http://www.dsc.ufcg.edu.br/~jacques/cursos/p2/html/oo/o_que_e_polimorfismo.htm https://www.devmedia.com.br/vetores-em-java/21449 https://www.devmedia.com.br/boas-praticas-de-programacao/21137 Programação orientada a objetos: Java, C++ e C# Apresentação Assim como a linguagem natural, que permite expressar por meio da fala os anseios, os sentimentos e os objetivos, a linguagem de programação surgiu para que fosse possível padronizar a comunicação de instruções para um computador. Por meio dela, o programador especifica precisamente onde o computador vai atuar, o que ele vai armazenar e transmitir a partir dos comandos do usuário. A competitividade do mercado atual exige um conhecimento funcional muito elevado por parte dos desenvolvedores. De acordo com a comunidade de programação TIOBE, que avalia a popularidade das linguagens de programação, as linguagens Java, C e C++ foram as três linguagens mais populares no ano de 2008. De lá para cá, diversas outras surgiram, inclusive a C#, que é uma continuação da C++, com melhorias voltadas para performance e experiência do usuário, o que não extingue a importância das três mencionadas anteriormente, tendo em vista características importantes que as fazem continuar entre as mais funcionais e robustas no mercado do desenvolvimento (SEBESTA, 2011, p. 24). Nesta Unidade de Aprendizagem, você irá conhecer as linguagens de programação Java e as suas características e também irá acompanhar a análise e o funcionamento das linguagens C++ e C#. Bons estudos. Ao final desta Unidade de Aprendizagem, você deve apresentar os seguintes aprendizados: Identificar as principais características da linguagem Java.• Analisar a Linguagem C++.• Descrever a linguagem C# e as suas particularidades.• Infográfico Java é uma linguagem de programação orientada a objetos criada por um grupo de engenheiros na década de 1990. No ano de 2008, ela foi adquirida pela empresa Oracle e, atualmente, é a linguagem mais utilizada entre os desenvolvedores, pois Java não é apenas uma linguagem, ela é uma plataforma, ou seja, um ambiente computacional que permite o desenvolvimento de aplicações na linguagem Java. Neste Infográfico, veja algumas características traduzidas para um fácil entendimento dessa importante linguagem de programação. Conteúdo do livro As linguagens de programação, de um modo geral, expressam de forma escrita instruções que precisam ser realizadas pelo computador. Cada uma é apropriada para determinados tipos de aplicação, permitindo que cada vez mais problemas sejam resolvidos por meio desse tipo de construção. Quando uma nova linguagem surge, é muito comum que os seus criadores tenham se baseado em uma linguagem já existente para essa nova construção. Isso aconteceu com o Java e o C#, que se valeram da linguagem C e C++ para criá-las. No capítulo Programação orientada a objetos: Java, C++ e C#w, da obra Paradigmas de programação, você estudará sobre essas três linguagens, o que permitirá que você tenha uma pequena noção desse vasto universo, trazendo o conhecimento e a curiosidade para você dar continuidade na busca do conhecimento no que diz respeito ao desenvolvimento de sistemas. PARADIGMAS DE PROGRAMAÇÃO Marcia Cristina Domingues Leite Programação orientada a objetos: Java, C++ e C# Objetivos de aprendizagem Ao final deste texto, você deve apresentar os seguintes aprendizados: � Identificar as principais características da linguagem Java. � Analisar a linguagem C++. � Descrever a linguagem C# e suas particularidades. Introdução De modo geral, uma linguagem de programação (LP) é um conjunto de regras sintáticas e semânticas que definem o que um computador deverá fazer. Historicamente, a primeira LP para computadores pessoais (chamada linguagem de alto nível) foi Fortran, criada em 1954. Desde então, muitas outras linguagens surgiram, algumas ainda continuam sendo utilizadas, pois suas características as mantêm no mercado do desenvolvimento por fatores como segurança, multiplataformas, tipagem e orientação a objetos (OO). Outras, deram origem ou influenciaram as linguagens conhecidas atualmente. A linguagem C, por exemplo, influenciou linguagens como Java e C#. Esta última, incorpora a OO à linguagem C que,por sua vez, é basicamente procedural, baseada em rotinas, métodos e funções. Neste capítulo, você conhecerá um pouco sobre essas três impor- tantes LPs, suas características, particularidades e de que forma elas influenciaram grande parte das linguagens de programação utilizadas hoje no mercado mundial de desenvolvimento. Paradigma da orientação a objetos Machado, Franco e Bertagnolli (2016) explicam que a OO trata de conceitos cujo objetivo principal é a resolução de problemas por meio da sua decomposição em partes menores, utilizando métodos como abstração e modularização. Quando os primeiros computadores surgiram, buscava-se uma maior eficiência, sem que isso tomasse grande parte da memória, em razão das limitações de hardware daquela época. Os programadores da época dividiam seus programas em blocos, de modo a realizar essa economia de recursos. A partir disso, foram criadas técnicas para resolução de problemas, divi- dindo um grande problema em diversos problemas menores. Essa técnica é realizada por meio da modularização, que permite resolver e entender proble- mas complexos e reutilizar códigos. Para que se possa a OO é importante saber que esse tipo de programação atende a quatro aspectos principais, descritos nos itens a seguir. Abstração É o aproveitamento de aspectos relevantes de cada um dos “problemas” resol- vidos dentro de um código. Portanto, cada módulo representa uma abstração existente no todo do problema. Sabemos que a OO trata de representações de um objeto real, mas é im- portante entender o que esse objeto irá realizar nessa abstração. Em geral, objeto é a representação de algo que existe. No desenvolvimento, os objetos possuem as seguintes características: identidade, estado e comportamento. Encapsulamento Dentro do contexto da OO, o encapsulamento é utilizado a todo momento, conforme se trabalha com propriedades e métodos de alguns componentes, sem ver como está implementado. Um exemplo disso é a utilização de application programming interface (API), utilizadas para requisitar informações sobre uma página Web, por exemplo, ou um banco de dados. Grande parte das linguagens que utilizam a OO encapsulam seu código em propriedades privadas, com métodos chamados getters e setters. Esses métodos, respectivamente, retornam e definem o valor da propriedade adicionando uma camada de segurança à aplicação, evitando, assim, o acesso direto ao objeto. Programação orientada a objetos: Java, C++ e C#2 Métodos nada mais são do que instruções que damos ao objeto, por exemplo: criar um cliente. Na prática, os métodos get ou set trabalham da seguinte forma: a aplicação faz uma requisição utilizando qualquer um deles. Por exemplo, um usuário busca seu cadastro em determinada aplicação, como isso é feito não pode ser visualizado, mas está acontecendo por trás da interface. Herança Permite que se utilize uma classe com suas propriedades e métodos, incluindo outras propriedades e métodos existentes em outra classe que está sendo criada. A herança é uma das grandes vantagens da programação OO, pois ela otimiza em muito o projeto do software, tanto no que diz respeito ao tempo, como em linhas de código. Polimorfismo Podemos tratar um objeto A que herdou características de outro objeto B como se ele fosse o próprio objeto B, ou seja, um objeto pode se comportar como se fosse outro objeto, do qual ele herdou atributos e métodos. Toda e qualquer alteração de um método herdado de um objeto pai caracteriza o polimorfismo. Outro aspecto importante em OO, é que algumas partes do objeto são privadas e outras, públicas. Geralmente, utiliza-se métodos públicos na in- terface do usuário. No escopo de um software, a classe descreve que propriedades ou atributos o objeto terá. A definição de uma classe descreve o comportamento que o objeto terá e de que forma ele funcionará na aplicação. � Atributos: são propriedades que compõe uma classe, como nome, tipo, valor e visibilidade (público, privado ou protegido). � Métodos: são as funcionalidades da classe, como nome, tipo, argumentos e visibilidade. A Figura 1 demonstra a construção de uma classe bem como a declaração de variáveis dentro dela. 3Programação orientada a objetos: Java, C++ e C# Figura 1. Exemplo de classe em Java. Linguagem Java e seu histórico Historicamente, a LP Java foi criada em 1991 pelos engenheiros da Sun Microsystems, que tinham como missão criar uma linguagem que pudesse ser utilizada em pequenos equipamentos domésticos, como telefones, geladeiras, controles de TV, etc. A intenção era que esses aparelhos pudessem se comunicar entre si (MACHADO; FRANCO; BERTAGNOLLI, 2016). Com o advento da World Wide Web (WWW), os engenheiros da Sun passaram a investir em novos conceitos para essa linguagem, que atualmente lidera o ranking das LP mais utilizadas no mundo do desenvolvimento. A LP Java é OO, e os programas são compilados, interpretados e trans- formados em uma linguagem intermediária chamada bytecode. O bytecode é multiplataforma e passa por um interpretador Java todas as vezes que o programa é executado. Isso se deve em razão da máquina virtual Java vir- tual machine (JVM) que permite que todos os produtos consigam executar programas em Java, basta que a plataforma possua a JVM. A Figura 2 demonstra com a JVM funciona na execução dos programas em Java nas mais diversas plataformas. Programação orientada a objetos: Java, C++ e C#4 Figura 2. JVM. Fonte: Adaptada de DreamStockIcons/Shutterstock.com. Class OláMundo{ public static void main (string args){ system.out.printin(*Olá Mundo!*) } } Programa Java Compilador JVM JVM JVM Olá Mundo! Olá Mundo! Olá Mundo! MacOS Android Windows Linguagem C++ No escopo da programação, a linguagem C++ é uma evolução da linguagem C e, assim como a primeira, influenciou muitas outras linguagens presentes no dia a dia dos usuários, desde a linguagem JavaScript que é executada no navegador a cada página acessada, ou ainda na linguagem Java que é executada nos smartphones. Muitas linguagens que são utilizadas hoje foram construídas com C++ no que se refere à sintaxe ou ao compilador. A linguagem C++ é composta por bibliotecas estáveis, que servem de base para diversas outras linguagens. Sua influência pode ser notada nos maiores sistemas operacionais e programas do mundo, o que permite concluir que entender a linguagem C++ é o primeiro passo para entender muitas outras linguagens atuais. Horstmann (2005) explica que a linguagem C++ ultrapassou a linguagem C com o acréscimo da programação OO e não procedural, como era C. Ele explica também que a linguagem C++ é sensível a letras maiúsculas e minúsculas, entretanto, espaços e quebras de linha não fazem diferença na estrutura do código, podendo o programa ser escrito em uma única linha. Outro detalhe importante é que cada linha de comando precisa terminar em ponto e vírgula, caso contrário o código não irá rodar. 5Programação orientada a objetos: Java, C++ e C# A seguir, veja algumas das características da linguagem C++. � Melhoramento da linguagem C — a linguagem C++ é uma continuação da linguagem C, com melhorias e novos recursos que otimizaram ainda mais a linguagem. � Estaticamente tipada — nesse caso é necessário definir o tipo de cada variável de forma explícita. Por exemplo, caso seja necessário declarar uma variável que irá armazenar números, é preciso dizer que é do tipo inteiro (int); ou se a variável for armazenar caracteres, será necessário dizer que ela é do tipo caracter (char). � Compilada — significa que o código é verificado quanto à sintaxe, passa por um processo de parsing, que verifica a estrutura gramatical do código, para somente, então, ser compilado. Feito isso é gerado o código assembler, no qual todas as instruções são traduzidas para o código de máquina. � Multiparadigma — é possível programar OO, ou utilizar a programação funcional. Com essa linguagem é possível fazerprogramas embarcados que trabalham diretamente com a comunicação com o hardware. Por isso, dizemos que a linguagem C++ trabalha tanto com a programação de alto como com a programação de baixo nível, sendo esta última, a mais próxima do hardware. � OO — esse é o seu grande diferencial em relação à linguagem C, pois essa linguagem utiliza recursos como abstração, herança, encapsula- mento e polimorfismo para construção do software. A programação OO recomenda que um objeto tenha sua estrutura e seus métodos tão privativos quanto for possível. Isso significa conhecer a especificação do método sem ter os detalhes de como a execução realizada por ele é implementada. Programação orientada a objetos: Java, C++ e C#6 Variáveis Em C++ é possível declarar uma variável em qualquer momento do código, dentro de uma instrução ou entre duas instruções. Quanto à visibilidade, existem duas abordagens possíveis para uma variável: local ou global. � Variáveis locais: podem ser acessadas apenas dentro do bloco de ins- truções no qual estão declaradas. Cada bloco compreende instruções dentro de duas chaves {...}. � Variáveis globais: podem ser acessadas em qualquer parte do código ou arquivo. Para isso, basta que seja declarada onde se desejar. Quando uma variável é global, dizem que está inserida no escopo do arquivo, pois pode ser acessada em qualquer parte do todo. Biblioteca stream Para possibilitar a entrada (input) e a saída (output) de dados utilizando a linguagem C++, é necessária a inclusão da biblioteca iostream.h, conforme exemplo a seguir: #include <iostream.h> Para imprimir uma variável na tela, por exemplo podemos dizer da seguinte forma: #include <iostream.h> int x = 20; cout << "x é igual a " << x << endl; A saída na sua tela será: x é igual a 20. A linguagem C++ utiliza o cin para o comando de entrada de dados pelo teclado e cout para a saída de dados na tela. 7Programação orientada a objetos: Java, C++ e C# Constantes É possível declarar uma constante dentro de um projeto C++. Você pode tornar constantes: valores, ponteiros, conteúdo de um ponteiro e parâmetros de uma função. Vale lembrar que, ao declarar um valor como constante não é possível alterá-lo. Exemplo: const float pi = 3,1415926. Para montar seu ambiente de desenvolvimento, recomenda-se a utilização de integrated development enviroment (IDE) — ou ambientes de desenvolvimento integrado, que facilitam a rotina do projeto. Manusear arquivos grandes via prompt de comando ou editor de textos não é uma tarefa aconselhável. Nesses casos, você pode contar com algumas ferramentas que auxiliam nesse sentido. Uma delas é o CodeBlocks, cujo link para instalação encontra-se a seguir. Um detalhe importante é que ao instalar a IDE CodeBlocks, o compilador é instalado automaticamente. Para instalar no Linux, basta escrever o seguinte comando no seu terminal: $ sudo apt install codeblocks https://bit.ly/2ejIyqR Conhecendo a linguagem C# Assim, como a linguagem C++, a LP C# é baseada na linguagem C, com melhorias e características que unem a linguagem original com novos con- ceitos e recursos. Trata-se de uma linguagem fortemente tipada, imperativa, declarativa e OO. A linguagem C# foi desenvolvida por Anders Hejlsberg e, atualmente, pode ser encontrada na versão 8.0. É utilizada dentro do ambiente de desen- volvimento .NET da Microsoft e tem muita aceitação no mercado, pois atende diversas especificações para criação de softwares, como desenvolvimento Web, mobile, metodologias ágeis como information technology infrastructure library (ITIL) e até mesmo machine learning (aprendizado de máquina) que trata de questões de mineração de dados em grandes bases, conhecidas como Big Data. Programação orientada a objetos: Java, C++ e C#8 Deitel et al. (2007) explicam que C# é uma LP projetada para ser utilizada na plataforma .NET e que, por ser baseada nas linguagens C, C++ e Java, torna a migração dos desenvolvedores mais fácil, ao passo que seus recursos se adaptam a cada uma das linguagens citadas e ainda acrescentam suas capacidades próprias. Essa plataforma é uma API feita para quem utiliza o sistema operacional Windows. Já em sistemas operacionais Unix, é possível desenvolver por meio do terminal ou de ferramentas como o Visual Studio Code e outras plataformas. Sharp (2011) compara a adaptabilidade da LP C# a componentes quando afirma que, enquanto a linguagem C desempenha importante papel no desen- volvimento UNIX, devido a sua compatibilidade, a linguagem C# também é compatível com diversos outros formatos, como eXtensible Makup Language (XML) e o eXtensible Application Markup Language (XAML). O Microsoft Visual Studio é um dos principais pacotes de programas de desenvolvi- mento da plataforma .NET. Trata-se de um conjunto de ferramentas, utilizadas para o desenvolvimento de aplicações móveis, para desktop, servidores Web e aplicações Web. Você pode fazer o download dessa importante ferramenta para auxiliar na sua experiência com o desenvolvimento utilizando C# no link a seguir. https://qrgo.page.link/s8UrU Plataforma ASP.NET A plataforma ASP.NET foi criada pela Microsoft para solucionar problemas de compilação e execução de aplicativos Web, além de fornecer ferramentas que facilitassem o desenvolvimento de aplicações Web (SANTANA FILHO; ZARA, 2002). A plataforma ASP.NET permite também a criação de diversos tipos de web services (serviços Web), que são aplicações que podem ser utilizadas na internet. O usuário tem a sua disposição uma interface com métodos definidos, na qual ele faz requisições a esses métodos a partir de protocolos da internet. A Microsoft define web service como uma classe escrita em uma linguagem 9Programação orientada a objetos: Java, C++ e C# suportada pela plataforma .NET, que é acessada via hypertext transfer protocol (HTTP) (HADDAD, 2008). Declaração de variáveis em C# A declaração de variáveis nessa LP se assemelha à linguagem C e C++, con- forme podemos ver no exemplo: � Tipo + nome da variável = int MinhaVariável. Deve-se sempre inicializar uma variável, atribuindo um valor inicial a ela, assim: � int MinhaVariável = 0; As variáveis alocam determinadas quantidades de espaço na memória para que seja possível armazenar os valores. O gerenciamento da memória nessa linguagem é feito em duas áreas, como segue: � stack — compreende um pequeno espaço de memória e funciona em formato de pilha, o que em estrutura de dados significa que a inserção e a remoção ocorrem em formato de pilha, o último elemento a entrar é o primeiro a sair; � heap — compreende uma área de memória bem grande e seu tamanho muda de forma dinâmica, de acordo com o que está sendo utilizado. Laços de repetição No contexto da lógica de programação, laços de repetição são estruturas de decisão que estão presentes em todas as linguagens de programação que conhecemos. Possuem variações sintáticas, mas, de forma geral, fazem com que um bloco de instruções se repita até que uma condição seja satisfeita. Cada uma delas é utilizada conforme a necessidade dentro do código. Para um melhor entendimento, você verá a seguir alguns tipos e em quais situações podem ser utilizados. Programação orientada a objetos: Java, C++ e C#10 Laço for Nesta estrutura de repetição a lógica funciona da seguinte forma: for (int i = 0; i <= 100; i++) { MessageBox.Show ("A variável alcançou o valor " + i.ToString()); } Esse bloco de repetição diz o seguinte: � Para cada i (inteiro), enquanto a variável i for menor que 100, acrescente 1 até que i seja igual a 100. Quando o valor de i for 100, mostre na tela a mensagem: “A variável alcançou o valor 100”. Laço while Essa estrutura basicamente diz que, enquanto a condição esperada não ocorrer, o loop continuará a ser executado. É muito comum ocorrerem erros de sintaxe durante a escrita do código que resultam no chamado loop infinito, ou seja, a condição ficará sendo executado de modo contínuoe não irá satisfazer a premissa determinada. Laço do while É semelhante ao laço while, porém, nessa estrutura, a condição é testada no fim do laço. A diferença essencial entre os dois é o que se deseja fazer dentro do código. 11Programação orientada a objetos: Java, C++ e C# Laço for each Sua principal função é varrer um array e todos os objetos que nele estão contidos. O laço for each recebe em cada loop um elemento do array. A Microsoft disponibiliza treinamento para todos os seus produtos, inclusive sobre a plataforma .NET, bem como outros serviços, por exemplo a hospedagem de aplicações Web por meio do Azure. Clique no link a seguir e confira. https://qrgo.page.link/z6wbj DEITEL, H. M. et al. C#: como programar. São Paulo: Pearson Education; Makron Books, 2007. 1153 p. HADDAD, R. Web Services. Microsoft Docs, Redmond, 9 set. 2008. Disponível em: https:// docs.microsoft.com/pt-br/previous-versions/technical-articles/cc564893(v=msdn.10). Acesso em: 28 ago. 2019. HORSTMANN, C. Conceitos de computação com o essencial de C++. 3. ed. Porto Alegre: Bookman, 2005. 712 p. MACHADO, R. P.; FRANCO, M. H. I.; BERTAGNOLLI, S. C. Desenvolvimento de software III: programação de sistemas web orientada a objetos em Java. Porto Alegre: Bookman, 2016. 220 p. (Série Tekne; Eixo Informação e Comunicação). SANTANA FILHO, O. V.; ZARA, P. M. Microsoft .net: uma visão geral para programadores. São Paulo: Senac, 2002. 124 p. SHARP, J. Microsoft Visual C# 2010. Porto Alegre: Bookman, 2011. 776 p. (Série Passo a Passo). Leituras recomendadas PERRY, J. S. Construções para aplicativos do mundo real: recursos de linguagem Java mais avançados. IBM Developer, Armonk, 22 fev. 2016. Disponível em: https://www.ibm.com/ developerworks/br/java/tutorials/j-introtojava2/index.html. Acesso em: 28 ago. 2019. PERRY, J. S. Fundamentos da Linguagem Java: programação orientada a objetos na pla- taforma Java. IBM Developer, Armonk, 22 jan. 2016. Disponível em: https://www.ibm.com/ developerworks/br/java/tutorials/j-introtojava1/index.html. Acesso em: 28 ago. 2019. Programação orientada a objetos: Java, C++ e C#12 Dica do professor Mais do que conhecer as diversas linguagens de programação, bem como a orientação a objetos, é importante entender que durante a vida profissional serão encontrados os mais diversos programas e que eles precisam, de certa forma, comunicar-se entre si. Neste sentido, o Web Service é importantíssimo, pois, por meio desse tipo de implementação, o profissional de Tecnologia conseguirá permitir que todo o arranjo de sistemas que constituem uma organização troque informações. Na Dica do Professor, você poderá entender um pouco sobre Web Services, conceitos, padrões e exemplos práticos. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. https://fast.player.liquidplatform.com/pApiv2/embed/cee29914fad5b594d8f5918df1e801fd/a0175d9bd8e8681968fa72f463f9f3d1 Saiba + Para ampliar o seu conhecimento a respeito desse assunto, veja abaixo as sugestões do professor: ARM REHABILITATION: serious game para apoio à reabilitação utilizando interfaces naturais Atualmente, a tecnologia e o desenvolvimento não estão somente ligados ao entretenimento e às situações de felicidade. O link a seguir demonstra o desenvolvimento de um jogo sério para auxiliar pessoas que necessitam usar próteses a estimularem a prática. A ferramenta foi desenvolvida utilizando a linguagem C#. Confira no link. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. GUJ: debates e discussões sobre programações Você conhece o GUJ??? Este é uma das maiores comunidades virtuais quando o assunto é Java. Lá, você encontra debates, discussões e suporte de conhecimento sobre a linguagem. Clique para conferir. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. The RedMonk Programming Language Rankings A empresa de análise de dados RedMonk mantém o mercado de desenvolvimento atualizado sobre o ranking das linguagens de programação mais populares. Confira a colocação das linguagens estudadas nesta Unidade de Aprendizagem. https://docplayer.com.br/45002408-Arm-rehabilitation-serious-game-para-apoio-a-reabilitacao-utilizando-interfaces-naturais.html https://www.guj.com.br/ Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. A programação orientada a objetos como ferramenta para o aprendizado e auxílio em projetos de engenharia Clique para conhecer este estudo, que denota a importância da orientação a objetos não somente para o profissional da TI, mas para outras grandes áreas. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. https://redmonk.com/sogrady/2019/07/18/language-rankings-6-19/?utm_source=rss&utm_medium=rss&utm_campaign=language-rankings-6-19 http://meusite.mackenzie.com.br/edsonbarros/publicacoes/COBENGE_2005_Galerias.pdf Testes de caixa-preta Apresentação Sempre em busca de entregas de produtos de software com maior qualidade final para evitar retrabalho relacionado a operações de correções sobre defeitos, empresas por todo o mundo usam as técnicas de testes de software como crivo obrigatório para garantir a correta entrega de seus projetos. Isso prova que a etapa de testes de software é de fundamental importância tanto para a sua qualidade como um todo quanto para o aspecto econômico de um projeto. Nesta Unidade de Aprendizagem, você aprenderá sobre a técnica de teste de software do tipo caixa-preta. Essa é uma técnica de abordagem tradicional largamente utilizada na área de testes de software e que tem por objetivo descobrir os defeitos relacionados às funcionalidades do software antes de seu uso em produção. Bons estudos. Ao final desta Unidade de Aprendizagem, você deve apresentar os seguintes aprendizados: Definir teste de caixa-preta e suas características.• Demonstrar um teste de caixa-preta.• Aplicar testes de caixa-preta utilizando Java.• Infográfico O teste de software é uma disciplina da engenharia de software que tem como objetivo avaliar se um programa está funcionando corretamente de acordo com as suas especificações. No Infográfico a seguir, você irá conhecer o fluxo comum da criação de casos de testes para um sistema e suas características, juntamente com os critérios utilizados em sua composição. Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar. https://statics-marketplace.plataforma.grupoa.education/sagah/0670ec10-26ad-43fd-ad8c-ba4fca2460a6/65a112ad-98c4-4c8d-a41a-9024da489034.png Conteúdo do livro Quando se fala em testes de software, sabe-se que existem técnicas de abordagem para vários modelos de projeto. Os testes de caixa-preta, também chamados de testes funcionais, são muito conhecidos e aplicados atualmente. Na obra Testes de software e gerência de configuração, base teórica para esta Unidade de Aprendizagem, leia o capítulo Testes de caixa-preta e conheça mais sobre esse teste, suas características e seus critérios de aplicação. TESTES DE SOFTWARE E GERÊNCIA DE CONFIGURAÇÃO Breno Cristóvão Rocha Testes de caixa-preta Objetivos de aprendizagem Ao final deste texto, você deve apresentar os seguintes aprendizados: Definir teste de caixa-preta e suas características. Demonstrar um teste de caixa-preta. Aplicar testes de caixa-preta utilizando Java. Introdução O teste de caixa-preta é uma técnica de teste conhecida e amplamente utilizada por fábricas de software para realizar avaliações sobre o sistema. A ideia é garantir que os comportamentos resultantes de ações imputadas sejam consonantes com os objetivos das especificações. Também conhecido como teste funcional, o teste de caixa-preta tem como base as especificações do sistema, que são elementos do projeto que alimentam o projeto de teste. Existem critérios de aplicação dos testes adequados para cadacaso. Isso quer dizer que os testes de caixa-preta têm uma amplitude razoável para que o software atinja a qualidade desejada e o funcionamento adequado. Por isso, é muito importante conhecer os detalhes de cada critério e entender a aplicação no mundo real. Neste capítulo, você vai conhecer as características do teste de caixa-preta e também os critérios utilizados para a aplicação em cada caso de teste. Teste de caixa-preta e suas características O teste de caixa-preta também é conhecido como teste funcional ou teste baseado em especifi cação. Afi nal, o seu principal objetivo é assegurar que as funcionalidades do sistema sejam atendidas da maneira correta após o seu desenvolvimento e se comportem como previsto nas especifi cações dos requisitos. É comum que os testes de caixa-preta sejam projetados com informações extraídas a partir da própria base de especificação do sistema, como: manuais do sistema; diagramas de caso de uso; documento de requisitos funcionais e não funcionais. Para se garantir a qualidade que determina um bom projeto de testes, é essencial haver uma fonte de requisitos adequada. Posteriormente, são necessárias a análise e a interpretação corretas do analista de testes que vai projetar os casos de teste. Enganos na interpretação das especificações e/ou má qualidade do material sobre o sistema, bem como falta de atualização diante de mudanças, podem resultar em não conformidades e falhas. Nesse sentido, a cobertura dos testes pode ser impactada caso alguma funcionalidade esteja ausente. Dessa forma, parte do sistema pode ficar “descoberta”. Para o teste de caixa-preta, não interessa como acontece o funcionamento interno ou a forma como foi feita a implementação do sistema. Isso ocorre porque a técnica analisa o funcionamento do sistema e não o que está dentro da “caixa” da qual não se conhecem os detalhes. Na Figura 1, a seguir, você pode ver como acontece a entrada e a saída na caixa-preta. Figura 1. Demonstração de entrada e saída em caixa-preta. O desconhecimento do funcionamento interno é um dos motivos pelos quais os testes relacionados às funcionalidades mais críticas do sistema devem ser priorizados pela equipe de testes junto aos analistas de requisitos e stakeholders. Afinal, os critérios do teste não identificam o que é crítico ou não. Os testes de caixa-preta são independentes da linguagem de programação ou do paradigma utilizado para o desenvolvimento da aplicação. Eles seguem um Testes de caixa-preta2 roteiro específico projetado para cada funcionalidade, que pode ser executado de modo manual ou com ferramentas de automação. Além disso, as técnicas de testes caixa-preta permitem derivar séries de condições de entrada que utilizarão completamente todos os requisitos funcionais para um programa (PRESSMAN; MAXIM, 2016). O teste de caixa-preta é mais comumente aplicado em nível de sistema, mas pode ser utilizado também em outros níveis, como unidade, integração e sistema. Veja na Figura 2, a seguir. Figura 2. Níveis de aplicação de testes. O projeto de testes, que também pode ser considerado um roteiro de testes, consiste na elaboração de casos de teste e no agrupamento por funcionalidades. Um roteiro de teste pode incluir vários casos de teste que verificam uma parte do sistema. Por sua vez, um caso de teste é um subconjunto planejado de en- tradas e saídas predefinidas, que são executadas em um ambiente controlado de modo a se observar o resultado da ação. Os testes de caixa-preta utilizam critérios para determinar quais casos de teste são necessários. Esses critérios são: 1. partição de equivalência; 2. análise de valor limite; 3. tabela de decisão; 4. grafo de causa e efeito; 5. teste de caso de uso. 3Testes de caixa-preta A seguir, veja como cada um deles implementa as regras do caso de teste. Partição de equivalência A partição de equivalência consiste em dividir as entradas de dados para o sistema em grupos ou classes de dados similares que podem ser tratados da mesma forma. Isso possibilita a redução do número de testes a serem escritos, já que um único teste nesse grupo de dados permite descobrir se o proces- samento está correto ou incorreto para todo o restante. Nesse sentido, há a partição válida e a partição inválida, que agrupa os valores de entrada para o teste. Como exemplo, considere uma entrada de valor para informação do mês, sendo que a faixa permitida é de 1 até 12. Veja a seguir. Partição válida: ■ valores maiores que 0; ■ valor 1; ■ valor 12. Partição inválida: ■ valores menores que 1. ■ valores maiores que 12. Partição inválida: ■ números reais. ■ caracteres não numéricos. Portanto, não é necessário testar todos os dias do mês para descobrir se o processamento do valor informado está correto ou incorreto. Basta realizar o teste com o grupo de entrada de valores da partição válida e da partição inválida nesse caso em que a condição de entrada especifica um intervalo de valores. Para identificar as classes de equivalência, considere o seguinte: exigência de uma entrada por intervalo de valores — definir uma classe de equivalência válida e duas inválidas; exigência de uma entrada específica de valor — definir uma classe de equivalência válida e duas inválidas; exigência de uma entrada de um membro de um conjunto — definir uma classe de equivalência válida e uma inválida; exigência de uma entrada booleana — definir uma classe de equivalência válida e uma inválida. Testes de caixa-preta4 Análise de valor limite A técnica de análise de valor limite para os projetos de testes complementa a técnica de partição de equivalência. Ela conduz o teste selecionando dados nos limites de um intervalo da partição de equivalência. Observe a Figura 3, a seguir. Figura 3. Limites da borda nas partições de equivalência. A análise do valor limite pode ser aplicada em vários níveis de teste e é considerada uma técnica relativamente fácil de se utilizar, com alta capacidade para encontrar defeitos. Como exemplo, considere uma entrada de valor no sistema, sendo que a faixa permitida é de 1 até 12. Veja a seguir. Entradas válidas: 1 até 12; Fronteiras válidas: 1 como menor número e 12 como maior; Fronteiras não válidas: 0 no limite inferior e 13 no limite superior. Existe ainda uma variação da técnica que testa três valores na fronteira definida. No exemplo que você acabou de ver, essa busca seria para o limite inferior 0, 1, 2 e para o limite superior 11, 12, 13. Portanto, a técnica de análise de valor limite se concentra nas fronteiras em que existe maior probabilidade de ocorrerem defeitos. 5Testes de caixa-preta Tabela de decisão O critério por tabela de decisão é uma boa alternativa para avaliar requisitos de sistema que trabalham com condições lógicas em regras de negócio mais complexas. As condições de entrada e saída são determinadas na tabela de decisão, que dispara a combinação de verdadeira ou falsa para obter o resul- tado da ação. Cada coluna da tabela pode representar uma regra de negócio diferente. Observe o Quadro 1, a seguir. Condição Cenário 1 Cenário 2 Cenário 3 Cenário 4 Cenário 5 Cenário 6 Cenário 7 Idade <18 18 >18 0 Vazio Negativo Acima do limite Resultado esperado Menor Maior Maior Inválido Inválido Inválido Inválido Quadro 1. Tabela de decisão Transição de estados O critério de teste por transição de estados é utilizado para validar as transições que acontecem dentro de um sistema ao se aplicar uma ação que depende do estado atual ou do estado anterior. Os testes podem ser elaborados para validar se uma sequência típica de estados está ocorrendo de forma correta ou se alguma transição inválida pode acontecer no fl uxo. Um exemplo muito comum é a transição de estados quando um sistema de banco é acessado por um usuário que realiza uma compra e deseja pagar com um cartão de crédito. Na Figura 4, a seguir, veja um fluxo simples que demonstra astransições de estado. Testes de caixa-preta6 Figura 4. Fluxo de transição de estado simples. Teste de caso de uso Os testes que utilizam o critério caso de uso são geralmente especifi cados a partir de casos de uso e/ou cenários de negócio. Os casos de uso, por exem- plo, representam a interação do ator com o sistema. O resultado é bastante relevante para o usuário. Dessa forma, os testes derivados de casos de uso são muito importantes na descoberta de defeitos no fluxo de utilização do sistema no mundo real. Eles podem contribuir para o aceite do produto pelo usuário final e, em casos de integração, revelar problemas por interferência de outros componentes que um teste individual de componente não detectou. 7Testes de caixa-preta Demonstração de um teste de caixa-preta Partição de equivalência O modelo de caso com critério baseado em partição de equivalência usa grupos ou classes de dados para validar o processamento de uma faixa de valores sem a necessidade de testar todos os valores. Assim, é possível testar a partição válida e a partição inválida para assegurar o resultado esperado. Segundo Pressman e Maxim (2016), o particionamento por equivalência é um método de teste que divide o domínio de entrada de um programa em classes de dados. A partir dessa divisão, é possível criar os casos de teste. Para compreender melhor, observe o Quadro 2, a seguir. Caso de teste Validar mês selecionado Passo Ação Resultado esperado 1 Inserir o valor “8” O mês de agosto foi selecionado. 2 Inserir o valor “0” O número inserido para o mês é inválido. 3 Inserir o valor “13” O número inserido para o mês é inválido. 4 Inserir o valor “XPTO” Somente é permitido número inteiro. Quadro 2. Partição de equivalência Limite de valor O modelo de caso de teste baseado em critério de valor limite valida se o sistema identifi ca corretamente o mês digitado pelo usuário. Além disso, valida se a regra de negócio para essa função tem tratativa para outros valores fora da faixa defi nida de 1 a 12. Como você pode ver no Quadro 3, foi usada a técnica de três valores nas bordas do limite, pois dessa forma é possível validar os valores dentro, na borda e fora dela. Testes de caixa-preta8 Caso de teste Validar mês selecionado Passo Ação Resultado esperado 1 Inserir o valor “0” O número inserido para o mês é inválido. 2 Inserir o valor “1” O mês de janeiro foi selecionado. 3 Inserir o valor “2” O mês de fevereiro foi selecionado. 4 Inserir o valor “11” O mês de novembro foi selecionado. 5 Inserir o valor “12” O mês de dezembro foi selecionado. 6 Inserir o valor “13” O número inserido para o mês é inválido. Quadro 3. Limite de valor Tabela de decisão O modelo de caso de teste baseado no critério de tabela de decisão utiliza, como o próprio nome já diz, uma tabela contendo as combinações necessárias para que o sistema apresente um comportamento determinado de acordo com o que a regra de negócio especifi ca. Veja no Quadro 4. Caso de teste Validar maioridade Passo Ação Resultado esperado 1 Inserir o valor “–1” Inválido 2 Deixar o valor vazio Inválido 3 Inserir o valor “0” Inválido 4 Inserir o valor “15” Menor de idade 5 Inserir o valor “18” Maior de idade 6 Inserir o valor “42” Maior de idade 7 Inserir o valor “170” Inválido Quadro 4. Tabela de decisão 9Testes de caixa-preta Transição de estados O teste baseado no critério de transição de estados pode ser escrito também com uma estrutura de tabela que aponta os estados após determinada ação no sistema. Dessa forma, você pode realizar a ação e observar se o resultado é compatível com o estado determinado como requisito. Veja o Quadro 5. Caso de teste Autorizar pagamento Estados Transições Insere cartão Senha válida Senha inválida ES1 — Iniciar ES2 — — ES2 — Esperar — — — ES3 — Tentativa 1 — ES6 ES4 ES4 — Tentativa 2 — ES6 ES5 ES5 — Tentativa 3 — ES6 ES7 ES6 — Aprovar — — — ES7 — Bloquear ES1 — — Quadro 5. Transição de estados Caso de teste por caso de uso Os testes que usam critério por caso de uso derivam dos casos de uso e são relativamente simples de escrever, uma vez que a especifi cação já fornece praticamente o modelo parecido. Veja no Quadro 6, a seguir. Testes de caixa-preta10 Caso de teste Cadastrar cliente Pré-condição O usuário deve estar autenticado no sistema. Pós-condição A transferência deve ser efetivada. Fluxo principal Passo Ação Resultado esperado 1 Consultar saldo em conta Exibição de saldo em conta 2 Cadastrar beneficiário Beneficiário cadastrado 3 Realizar transferência de valor Emitir recibo de confirma- ção de transferência Fluxo alternativo Passo Ação Resultado esperado 1 Cadastrar beneficiário Beneficiário cadastrado 2 Realizar transferência Emitir recibo de confirma- ção de transferência Quadro 6. Caso de teste por caso de uso As técnicas de teste por partição de equivalência e valor limite podem ser combinadas para um teste mais efetivo. Por um lado, você define os grupos de equivalência e dessa forma elimina a necessidade de testes extensivos. Por outro, você testa os limites para identificar de forma mais crítica se existem defeitos. Aplicação de testes de caixa-preta com Java Os testes de caixa-preta podem ser programados também em Java e executados por softwares automatizados. Esses softwares têm a capacidade de executar comandos 11Testes de caixa-preta para testar uma aplicação web, por exemplo, de maneira automática. O analista ou desenvolvedor pode programar um teste na linguagem Java e facilmente executar esse teste para obter os resultados esperados. Também é possível executar um caso de teste manualmente e usar os softwares de automação para gravar os testes. Esses testes podem ser salvos em código e versionados juntamente aos requisitos. Essa versatilidade abre um leque de possibilidades para os testes e aprimora o teste de caixa-preta, pois, via programação, comandos mais avançados podem ser escritos. Também é possível usar JavaScript, por exemplo, e frameworks open source, além de aplicar uma pré-condição ou uma pós-condição, executar algum código de limpeza de dados e aplicar determinado estado em um banco de dados para preparação do ambiente simulado ou remoção de cookies. A seguir, observe a Figura 5. Ela mostra um exemplo de código Java que é capaz de abrir o navegador Firefox, acessar o Google e realizar a busca dos termos “Teste de busca no Google”. Figura 5. Código Java. Testes de caixa-preta12 Para executar esse código, é necessário instalar o Selenium WebDriver e o Geckodriver, que vão executar o código, aplicar o teste e retornar com os resultados. Existem outros softwares que também possuem agentes de testes que trabalham de forma automática. São robôs programados para executar testes como o demonstrado na Figura 5 de forma totalmente automática. Isso possibilita, por exemplo, uma automação baseada em liberações, de modo que o software é testado funcionalmente de forma automática sempre que uma nova versão é publicada no servidor. Esse sistema é muito útil para testes de regressão em que uma massa muito grande de testes é executada para validar o impacto de novas mudanças ou melhorias sobre o restante do sistema. PRESSMAN, R. S.; MAXIM, B. R. Engenharia de software: uma abordagem profissional. 8. ed. Porto Alegre: AMGH, 2016. Leituras recomendadas DELAMARO, M. E.; MALDONADO, J. C.; JINO, M. Introdução ao teste de software. 2. ed. São Paulo: Elsevier, 2016. IEEE COMPUTER SOCIETY. Guide to the software engineering body of knowledge. 2004. Disponível em: https://www.computer.org/web/swebok/. Acesso em: 24 fev. 2019. MOLINARU, L. Testes funcionais de software. São Paulo: Visual Books, 2008. PFLEEGER, S. L. Engenharia de software: teoria e prática. 2. ed. São Paulo: Prentice Hall, 2004. SOUZA, E. et al. Base de conhecimento em testes de software. São Paulo: Martins Fontes, 2007. Referência 13Testes de caixa-preta Dica do professor O teste de