0% found this document useful (0 votes)
30 views

CMP 202

Uploaded by

Akorede Bashir
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views

CMP 202

Uploaded by

Akorede Bashir
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 201

CMP 202- COMPUTER PROGRAMMING II

LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
Principles of Good Programming
• There are certain universal laws and principles in software development
that guide architects, programmers, and anyone needing to design a
working software. These slides lists quite a few of those principles,
although it's far from complete.
• Programming is difficult (like many activities that are useful and
worthwhile—and like most of those activities, it can also be rewarding and
a lot of fun).
• When you write a program, you have to tell the computer every small
detail of what to do. And you have to get everything exactly right, since the
computer will blindly follow your program exactly as written.
• How, then, do people write any but the most simple programs? It’s not a
big mystery, actually. It’s a matter of learning to think in the right way.
How to start
• A program is an expression of an idea.
• A programmer starts with a general idea of a task for the computer to
perform.
• Presumably, the programmer has some idea of how to perform the task by
hand, at least in general outline.
• Programming in the small, which is sometimes called coding, would
then refer to filling in the details of that design.
• The details are the explicit, step-by-step instructions for performing fairly
small-scale tasks.
• When you do coding, you are working fairly “close to the machine,”
with some of the same concepts that you might use in machine
language:
• memory locations, arithmetic operations, loops and branches
What are Programming principles?
• Programming is the process of coding, testing, troubleshooting,
debugging and maintaining a system. Programming principles help
you to write excellent quality of code and maintain a good coding
practice.
• A personal Recount:
• Programming principles have helped me over the years in becoming a better
programmer, and I believe, this will help any developer become more
efficient and able to produce code which is easier to maintain.
• By following these coding principles, you can save development and
maintenance time, and conquer lots of other bottlenecks which generally
arise in later development phases.
Why should a developer follow the principles?
• When I started my adventure with programming in Java, I wrote
complete spaghetti code.
• It means each file had many responsibilities, no abstraction, and it was
difficult to debug and fix issues.
• I am not only one person working on applications; my team is working on the
same. Later, I started thinking how to improve quality of the code. And the
answer is Coding Principles.
• Actually, writing programs is often a matter of personal taste but
there are certain principles or guidelines that should be followed
within your own style in order to make programs easy to maintain
and understand by both, you and others, and also principles guide the
creation of stable, scalable, and robust code.
What are the benefits if developer followed it?
• Readability
All developers were in a team able to understand the code.
• Extensibility
In the software world, we should not blame the change requests;
it’ll come at any time. So our code is always easy to extend without
breaking existing business rules.
• Maintainability
It’s easy to maintain by the development team and the
production support team too because the application is loosely
coupled.
• Modularity
Divide a program into reusable pieces: functions, modules,
libraries.
Keep things DRY
• DRY means Don’t-Repeat-Yourself

Duplication can lead to maintenance nightmares, poor factoring, and


logical contradictions. "Every piece of knowledge must have a single,
unambiguous, authoritative representation within a system". In other
words, a piece of logic should only be represented once in an
application.
• Duplication is the root of all software evils.
• Duplication is a waste.

DRY is also known as Duplication is Evil (DIE) or Once And Only Once.
Every piece of knowledge must have a single, unambiguous, authoritative
representation within a system.
---DRY
• Each significant piece of functionality in a program should be implemented in
just one place in the source code. Where similar functions are carried out by
distinct pieces of code, it is generally beneficial to combine them into one by
abstracting out the varying parts.
• Why
• Duplication (inadvertent or purposeful duplication) can lead to maintenance
nightmares, poor factoring, and logical contradictions.
• A modification of any single element of a system does not require a change in
other logically unrelated elements.
• Additionally, elements that are logically related all change predictably and
uniformly, and are thus kept in sync.
• How
• Put business rules, long expressions, if statements, math formulas, metadata,
etc. in only one place.
• Identify the single, definitive source of every piece of knowledge used in
your system, and then use that source to generate applicable instances of that
You’re NOT Gonna Need It!
• YAGNI stands for "you aren't gonna need it": don't implement something
until it is necessary.
• As developers, we'll always think a lot about the future usability of the
project and try to do some extra features coding in a mind that “just in case
we need them” or “we will eventually need them”. Just one word… Wrong!
I’ll repeat it this way: You didn’t need it, you don’t need it, and in most of
the cases… “You Aren’t Gonna Need It”.
Why
• Any work that's only used for a feature that's needed tomorrow, means losing
effort from features that need to be done for the current iteration.
• It leads to code bloat; the software becomes larger and more complicated.
• How
• Always implement things when you actually need them, never when you just
foresee that you need them.
KISS Principle - Keep It Simple, Stupid
• Nowadays programming languages, frameworks, and APIs have
powerful means to create sophisticated solutions for various kinds of
problems. Sometimes developers might feel tempted to write
“clever” solutions that use all these complex features.

The KISS principle states that most systems work best if they are kept
simple rather than making them complex; therefore simplicity should
be a key goal in design and unnecessary complexity should be
avoided.

This principle can be applied to any scenario, including many business


activities, such as planning, designing, and development.
---KISS
• Most systems work best if they are kept simple rather than made
complex.
• Why
• Less code takes less time to write, has less bugs, and is easier to modify.
• Simplicity is the ultimate sophistication.
• It seems that perfection is reached not when there is nothing left to add, but
when there is nothing left to take away.
Do The Simplest Thing That Could Possibly Work
• Why
• Real progress against the real problem is maximized if we just work on what
the problem really is.
• How
• Ask yourself: "What is the simplest thing that could possibly work?"
Separation of Concerns
• Separation of concerns is a design principle for separating a computer program
into distinct sections, such that each section addresses a separate concern. For
example the business logic of the application is a concern and the user interface
is another concern. Changing the user interface should not require changes to
business logic and vice versa.
• It is what I sometimes have called "the separation of concerns", which,even
if not perfectly possible, is yet the only available technique for effective
ordering of one's thoughts, that I know of. This is what I mean by "focusing
one's attention upon some aspect": it does not mean ignoring the other
aspects, it is just doing justice to the fact that from this aspect's point of
view, the other is irrelevant (Edsger. 1974)
• Why
• Simplify development and maintenance of software applications.
• When concerns are well-separated, individual sections can be reused, as well
as developed and updated independently.
• How
• Break program functionality into separate modules that overlap as little as
possible.
Code For The Maintainer
• The software maintainer always says ---Don’t make think!
• Why
• Maintenance is by far the most expensive phase of any project.
• How
• Be the maintainer.
• Always code as if the person who ends up maintaining your code is a violent
psychopath who knows where you live.
• Always code and comment in such a way that if someone a few notches junior
picks up the code, they will take pleasure in reading and learning from it.
Avoid Premature Optimization
• Programmers waste enormous amounts of time thinking about, or
worrying about,
the speed of noncritical parts of their programs, and these attempts at
efficiency actually have a strong negative impact when debugging and
maintenance are considered. We should forget about small efficiencies, say
about 97% of the time: premature optimization is the root of all evil. Yet
we
should not pass up our opportunities in that critical 3%.
• Understanding what is and isn’t "premature" is critical of course.
• Why
• It is unknown upfront where the bottlenecks will be.
• After optimization, it might be harder to read and thus maintain.
• How
• Make t work, make it right, make it fast!
• Don't optimize until you need to, and only after profiling you discover a
bottleneck optimize that.
Minimize Coupling
• Coupling between modules/components is their degree of mutual
interdependence;
lower coupling is better. In other words, coupling is the probability that
code
unit "B" will "break" after an unknown change to code unit "A".
• Why
• A change in one module usually forces a ripple effect of changes in other
modules.
• Assembly of modules might require more effort and/or time due to the increased
inter-module dependency.
• A particular module might be harder to reuse and/or test because dependent
modules must be included.
• Developers might be afraid to change code because they aren't sure what might
be affected.
• How
• Eliminate, minimise, and reduce complexity of necessary relationships.
• By hiding implementation details, coupling is reduced.
Composition Over Inheritance
• Why
• Less coupling between classes.
• Using inheritance, subclasses easily make assumptions, and break LSP.
• How
• Test for LSP (substitutability) to decide when to inherit.
• Compose when there is a "has a" (or "uses a") relationship, inherit when "is
a".
Orthogonality
• The basic idea of orthogonality is that things that are not related
conceptually should not be related in the system.
• It is associated with simplicity; the more orthogonal the design, the
fewer
exceptions. This makes it easier to learn, read and write programs in a
programming language. The meaning of an orthogonal feature is
independent of
context; the key parameters are symmetry and consistency.
Robustness Principle
• Be conservative in what you do, be liberal in what you accept from others
• Collaborating services depend on each others interfaces. Often the
interfaces need to evolve causing the other end to receive unspecified
data. A naïve implementation refuses to collaborate if the received data
does not strictly follow the specification. A more sophisticated
implementation will still work ignoring the data it does not recognize.
• Why
• In order to be able to evolve services you need to ensure that a provider can
make changes to support new demands while causing minimal breakage to their
existing clients.
• How
• Code that sends commands or data to other machines (or to other programs on
the same machine) should conform completely to the specifications, but code
that receives input should accept non-conformant input as long as the meaning
is clear.
Inversion of Control
• Inversion of Control is also known as the Hollywood Principle, "Don't call us, we'll call
you". It is a design principle in which custom-written portions of a computer program
receive the flow of control from a generic framework. Inversion of control carries the
strong connotation that the reusable code and the problem-specific code are developed
independently even though they operate together in an application.
• Why
• Inversion of control is used to increase modularity of the program and make it
extensible.
• To decouple the execution of a task from implementation.
• To focus a module on the task it is designed for.
• To free modules from assumptions about how other systems do what they do and
instead rely on contracts.
• To prevent side effects when replacing a module.
• How
• Using Factory pattern
• Using Service Locator pattern
• Using Dependency Injection
• Using contextualized lookup
• Using Template Method pattern
• Using Strategy pattern
Maximize Cohesion
• Cohesion of a single module/component is the degree to which its
responsibilities form a meaningful unit; higher cohesion is better.
• Why
• Increased difficulty in understanding modules.
• Increased difficulty in maintaining a system, because logical changes in the
domain affect multiple modules, and because changes in one module require
changes in related modules.
• Increased difficulty in reusing a module because most applications won’t
need the random set of operations provided by a module.
• How
• Group related functionalities sharing a single responsibility (e.g. in a class).
Liskov Substitution Principle
• The LSP is all about expected behavior of objects:
• Objects in a program should be replaceable with instances of their subtypes
without altering the correctness of that program.
Open/Closed Principle
• Software entities (e.g. classes) should be open for extension, but
closed for modification. I.e. such an entity can allow its behavior to be
modified without altering its source code.
• Why
• Improve maintainability and stability by minimizing changes to existing code.
• How
• Write classes that can be extended (as opposed to classes that can be
modified).
• Expose only the moving parts that need to change, hide everything else.
Single Responsibility Principle
• A class should never have more than one reason to change.
• Long version: Every class should have a single responsibility, and that
responsibility should be entirely encapsulated by the class.
Responsibility can be defined as a reason to change, so a class or
module should have one, and only one, reason to change.
• Why
• Maintainability: changes should be necessary only in one module or class.
• How
• Apply Curly’s law
Hide Implementation Details
• A software module hides information (i.e. implementation details) by
providing an interface, and not leak any unnecessary information.
• Why
• When the implementation changes, the interface clients are using does not
have to change.
• How
• Minimize accessibility of classes and members.
• Don’t expose member data in public.
• Avoid putting private implementation details into a class’s interface.
• Decrease coupling to hide more implementation details.
Curly's Law
• Curly's Law is about choosing a single, clearly defined goal for any
particular bit of code: Do One Thing.
Encapsulate What Changes
• A good design identifies the hotspots that are most likely to change
and encapsulates them behind an API. When an anticipated change
then occurs, the modifications are kept local.
• Why
• To minimize required modifications when a change occurs
• How
• Encapsulate the concept that varies behind an API
• Possibly separate the varying concept into its own module
Interface Segregation Principle
• Reduce fat interfaces into multiple smaller and more specific client
specific interfaces. An interface should be more dependent on the
code that calls it than the code that implements it.
• Why
• If a class implements methods that are not needed the caller needs to know
about the method implementation of that class. For example if a class
implements a method but simply throws then the caller will need to know
that this method shouldn't actually be called.
• How
• Avoid fat interfaces. Classes should never have to implement methods that
violates the single responsibility principle
Boy-Scout Rule
• The Boy Scouts of America have a simple rule that we can apply to
our
profession: "Leave the campground cleaner than you found it". The
boy-scout rule states that we should always leave the code cleaner
than we found it.
• Why
• When making changes to an existing codebase the code quality tends to
degrade, accumulating technical debt. Following the boyscout rule, we should
mind the quality with each commit. Technical debt is resisted by continuous
refactoring, no matter how small.
• How
• With each commit make sure it does not degrade the codebase quality.
• Any time someone sees some code that isn't as clear as it should be, they
should take the opportunity to fix it right there and then.
Command Query Separation
• The Command Query Separation principle states that each method
should be either a command that performs an action or a query that
returns data to the caller but not both. Asking a question should not
modify the answer.
• With this principle applied the programmer can code with much more
confidence. The query methods can be used anywhere and in any
order since they do not mutate the state. With commands one has to
be more careful.
• Why
• By clearly separating methods into queries and commands the programmer
can code with additional confidence without knowing each method's
implementation details.
• How
• Implement each method as either a query or a command
• Apply naming convention to method names that implies whether the method
Murphy's Law
• Anything that can go wrong will go wrong.
• It seems to be a universal law that when there is even the smallest
possibility of something going wrong, it eventually will go wrong. It
makes total sense when we think about probabilities and an infinite
amount of trials. The law also applies to software development.
Brooks's Law
• Adding manpower to a late software project makes it later.
• The law is related to software project management and was
introduced by Fred Brooks in his famous book 'The Mythical Man-
Month'. The essence of the law is that adding new developers to a
software project does not make them productive immediately but
conversely takes time from the other team members due to
communication overhead.
Linus's Law
• Given enough eyeballs, all bugs are shallow.
• The law is originating from the book 'The Cathedral and the Bazaar' by
Eric S. Raymond and was named in honor of the famous Finnish
inventor of Linux operating system, Linus Torvalds. It's basically a
praise to software reviewing process where multiple developers
inspect the piece of code before it's accepted and merged.
CMP 202- COMPUTER PROGRAMMING II
LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
Structured Programming Concepts
• The concept of structured programming started in the late 1960’s
with an article by Edsger Dijkstra.
• He proposed a “go to less” method of planning programming logic
that eliminated the need for the branching category of control
structures.
• The topic was debated for about 20 years.
• But ultimately – “By the end of the 20th century nearly all computer
scientists were convinced that it is useful to learn and apply the
concepts of structured programming.”
What is Structured Programming?
• Structured programming is a programming paradigm aimed at
improving the clarity, quality, and development time of a computer
program
• By making extensive use of the structured control flow constructs of

• selection (if/then/else) and


• repetition (while and for),
• block structures, and
• subroutines
• In contrast to using simple tests and jumps such as the go to
statement, which can lead to “spaghetti code” that is potentially
difficult to follow and maintain.
• One of the most important concepts of programming is the ability to
control a program so that different lines of code are executed or that
some lines of code are executed many times.
• The mechanisms that allow us to control the flow of execution are
called control structures.
• Flowcharting is a method of documenting (charting) the flow (or
paths) that a program would execute.
• There are three main categories of control structures:
• Sequence – Very boring. Simply do one instruction then the next and the
next. Just do them in a given sequence or in the order listed. Most lines of
code are this.
• Selection – This is where you select or choose between two or more flows.
The choice is decided by asking some sort of question. The answer
determines the path (or which lines of code) will be executed.
• Iteration – Also known as repetition, it allows some code (one to many lines)
to be executed (or repeated) several times. The code might not be executed
at all (repeat it zero times), executed a fixed number of times or executed
indefinitely until some condition has been met. Also known as looping
because the flowcharting shows the flow looping back to repeat the task.
• A fourth category describes unstructured code.
• Branching – An uncontrolled structure that allows the flow of execution to
jump to a different part of the program. This category is rarely used in
modular structured programming.
• All high-level programming languages have control structures. All languages have
the first three categories of control structures (sequence, selection, and
iteration). Most have the if then else structure (which belongs to the selection
category) and the while structure (which belongs to the iteration category). After
these two basic structures, there are usually language variations.
• In structured programming, we sub-divide the whole program into small modules
so that the program becomes easy to understand. The purpose of structured
programming is to linearize control flow through a computer program so that the
execution sequence follows the sequence in which the code is written.
• The dynamic structure of the program than resemble the static structure of the
program.
• This enhances the readability, testability, and modifiability of the program. This linear flow of
control can be managed by restricting the set of allowed applications construct to a single
entry, single exit formats.
Why we use Structured Programming?
• We use structured programming because it allows the programmer to
understand the program easily.
• If a program consists of thousands of instructions and an error occurs
then it is complicated to find that error in the whole program, but in
structured programming, we can easily detect the error and then go
to that location and correct it.
• This saves a lot of time.

• The following are rules in structured programming:


Structured Rule One: Code Block
• If the entry conditions are correct, but the exit conditions are wrong, the
error must be in the block.
• This is not true if the execution is allowed to jump into a block. The error
might be anywhere in the program. Debugging under these circumstances is
much harder.
• A code block is structured, as shown in the figure. In flow-charting condition,
a box with a single entry point and single exit point are structured. Structured
programming is a method of making it evident that the program is correct.
Structure Rule Two: Sequence

• A sequence of blocks is correct if the exit conditions of each block


match the entry conditions of the following block.
• Execution enters each block at the block's entry point and leaves through the
block's exit point.
• The whole series can be regarded as a single block, with an entry point and an
exit point.
• Two or more code blocks in the sequence are structured, as shown in
the figure.
Structured Rule Three: Alternation
• If-then-else is frequently called alternation (because there are
alternative options).
• In structured programming, each choice is a code block.
• If alternation is organized as in the flowchart at right, then there is one entry
point (at the top) and one exit point (at the bottom).
• The structure should be coded so that if the entry conditions are fulfilled,
then the exit conditions are satisfied (just like a code block).
• The alternation of two code blocks is structured, as shown in the
figure.
Structured Rule 4: Iteration
• Iteration (while-loop) is organized as at right. It also has one entry
point and one exit point.
• The entry point has conditions that must be satisfied, and the exit
point has requirements that will be fulfilled.
• There are no jumps into the form from external points of the code.
• The iteration of a code block is structured, as shown in the figure.
Structured Rule 5: Nested Structures
• In flowcharting conditions, any code block can be spread into any of
the structures.
• If there is a portion of the flowchart that has a single entry point and
a single exit point, it can be summarized as a single code block.
• A structure (of any size) that has a single entry point and a single exit
point is equivalent to a code block.
• For example, we are designing a program to go through a list of
signed integers calculating the absolute value of each one.
• We may
• (1) first regard the program as one block, then
• (2) sketch in the iteration required, and finally
• (3) put in the details of the loop body, as shown in the figure.
------ Structured Rule 5: Nested Structures

• The other control structures are the case, do-until, do-while, and for
are not needed. However, they are sometimes convenient and are
usually regarded as part of structured programming. In assembly
language, they add little convenience.
Steps in a Programming Project
• In CMP201, the importance of a clear, structured programming style
has been emphasized. Because of the importance of these principles,
we will dive much into this concepts as it is worth reviewing them
here before we continue with the main part of CMP202.
• Any programming project, no matter how simple, should be divided
into several main sections:
1. Make sure you understand the problem you are trying to solve. This
may seem obvious, but many later problems in coding can be traced
back to your lack of a complete understanding of just what it is the
program is supposed to do
Steps in a Programming Project
• 2. Once you have a clear picture in your mind of the problem, you should
write out the specifications that the program is to satisfy.
• As a simple example, suppose you wish to write a program that sorts a list
of numbers into ascending order. Even for such a simple program, you need
to consider the specifications before you put finger to keyboard.
• For example, how are the numbers to be input into the program?
• Will they be typed in from the keyboard or read from a file?
• Will the quantity of numbers be known in advance, or should this quantity be
requested from the user before the numbers are read, or should the program count
the numbers as they are read in?
• Where is the sorted list to be output (on screen or in a file)?
• If files are used for input and/or output, are the filenames to be constant,
or should the program request the filenames from the user?
• Should the program be able to sort integers or real numbers as well?
Steps in a Programming Project
• You should have made up your mind on all these points before you
even sit down in front of the computer.
• Failing to think things through at this stage can mean a lot of
chopping and changing in the program later, which leads to jumbled
code that is full of errors, and difficult to debug, as well as a lot of
wasted time.

3. Having decided exactly what the specifications of the program are,


you must now consider the coding of it. There are two aspects to be
solved here. First, you must decide what data structures are to be used
to represent the entities in the program. Second, you must decide what
algorithm you are going to use to do the calculations.
Steps in a Programming Project
• Example: In coding a sorting program, for example, you must decide how
you are going to store the numbers to be sorted.
• If the maximum quantity of numbers is known in advance, an array may be the best
way.
• If the quantity varies a lot from one run to the next, a linked list (a data structure in
which space is allocated for data as it is needed, not reserved in advance as in an
array) may be more appropriate.
• If the numbers are associated with other data, it might be better to use an array or
linked list of records, in which one field represents the number which is used as the
sorting key.
• If you have considered the specifications properly, the choice of data
structure is usually a lot easier.
• The choice of which algorithm to use is often closely linked with the
specifications and the choice of data structures. There are a great many
sorting algorithms around (insertion sort, bubble sort, quicksort,
mergesort, etc.).
Steps in a Programming Project
• Different algorithms work best in different situations-some sorting
algorithms are more efficient when the list to sort is short, others are
better when the list is long.
• Some algorithms move the data around less than others, so if each
chunk of data is fairly large, meaning that moving it is expensive in
computer time, it would be better to use one of the former
algorithms.
• If each datum is only a single integer, so that moving it is fairly cheap,
one of the other algorithms may be better. If the program will be
handling lists of different sizes, it may even be worthwhile to include
more than one sorting algorithm, and choose the right one for the
length of list currently being sorted.
Steps in a Programming Project
• The steps up to now could all be done away from the computer, but
you must now write the actual code. There are many guidelines which
are appropriate here, but we will consider these in a moment.
Overall, the goal is to write clear, well documented, easy to read code
that will be easy for both you and someone else to understand and
update at some time in the future.
• Once the program is written, it must be tested against its
specifications. Actually, it is a good idea to make testing an integral
part of the code writing process. Since properly written code uses the
top-down (stepwise refinement) process, you will be writing
individual functions and procedures to do separate tasks. You should
test each of these modules as you write it
Steps in a Programming Project
• If a module calls other modules which you haven't written yet, create a dummy or
stub module with a simple writeln statement in it so that your module has
something to call. If you make sure that each module works as you write it, you
ease the task of debugging things later on.
• Once the entire program is complete, though, you must perform a set of
comprehensive tests on it to make sure it lives up to its specifications.
• Try it first with all forms of acceptable input for which it was designed and make
sure it behaves correctly.
• However, one aspect (the most difficult one) of testing is to try to anticipate all
the forms of incorrect input that users will feed your program. For example,
suppose your array sorting program is only designed to handle lists of up to 100
numbers.
• What will it do if someone feeds in 200? Or, if the program is designed to read a
fixed quantity of numbers from a file with a fixed name, what will the program do
if the file contains too few numbers, or if the file doesn't exist at all?
• In most cases like this, the program will just crash with an obscure error message,
like 'Segmentation fault' or 'Trace-trap error', which will mean nothing to a naive
user.
Steps in a Programming Project
• You should try to anticipate as many of these problems as you can, and write your
program to catch these errors and print out friendly error messages that let the
user know exactly what is wrong.
• One of the best ways of doing this is have a friend (preferably a sadistic one)
consciously try to break your program by feeding it all sorts of garbage input.
• You will find that there are quite a few input errors that you haven't thought of.
• Although this sort of testing is very important when you write programs in a
commercial or industrial environment, you won't have enough expertise at
present to be able to correct all the possible incorrect input situations.
• For example, how do you guard against someone entering text characters when
your program expects numbers?
• To trap all these cases requires some fairly sophisticated techniques which you aren't
expected to know at this stage.
• However, you should be thinking about making your program as user-friendly as
possible by allowing for simple errors that you do know how to fix.
Steps in a Programming Project
• Test the program with values that produce calculations that are
simple enough to check by hand.
• Test the program with realistic values (ones that the program would
expect to use in practice).
• Test the extreme cases (when you use all the space allocated in an
array, the highest or lowest acceptable number, etc.).
• Test what happens when inadequate or no input is present, especially
from a file.
• Test what the program does for `garbage input'. Try to produce
sensible error messages and thus avoid the GIGO (garbage in, garbage
out) syndrome.
• Make sure that every module in your program is actually used in one
of the test situations.
CMP 202- COMPUTER PROGRAMMING II
LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
WHAT ARE ERRORS?
• Errors are the problems or the faults that occur in the program,
which makes the behavior of the program abnormal. Even
experienced developers can also make these faults.
• Programming errors are also known as the bugs or faults, and the
process of removing these bugs is known as debugging.
• Debugging is the process of finding and correcting existing and
potential errors in software code. Bugs can cause software code to
behave unexpectedly or crash.
• These errors are detected either during the time of compilation or
execution. Thus, the errors must be removed from the program for
the successful execution of the program.
TYPES OF ERRORS
• Syntax errors
• Runtime errors
• Logical errors
• Semantic errors
• Compilation errors
• Arithmetic errors
• Resource errors
• Interface Errors
. SYNTAX ERRORS
• Syntax errors occur when syntactical problems occur in a certain
programming language due to incorrect use syntax.
• When you first get started with coding, you will probably make lots of
syntax errors. These are errors that occur when you have not
followed the rules of the language, and they will be flagged by the
translator. A program with syntax errors will not run.
• Most IDEs (integrated development environments) highlight syntax
errors when you try to run your code
----- SYNTAX ERRORS
• Programming languages such as Python or java are very simple
compared to natural languages such as English, Spanish or Japanese.
However, they do have a lot of things in common:
• it matters what order the words are in;
• they both have syntax (that is, a grammar) that define how the words can be
combined together;
• you have to spell words correctly;
• you can translate between one programming language and another;
• they both use punctuation to structure and organise words and sentences;
• there are multiple ways of writing the same code or “paragraph” to describe
the same thing.
---- SYNTAX ERRORS
• These syntactical problems may be:
• Missing semicolons,
• Missing brackets,
• Misspelled keywords,
• Use of undeclared variables,
• Improperly named variable or function or class,
• Class not found,
• Missing double-quote in Strings, etc.
How Syntax errors are detected?
• Syntax errors are easy to spot and rectify because the Java compiler
finds them for you.
• The compiler will tell you which piece of code in the program got in
trouble and its best guess as to what you did wrong. Usually, the
compiler indicates the exact line where the error is, or sometimes the
line just before it.
• These errors are detected by the compiler at compile time of the
program which is why they are also known as compile-time errors.
• When the compiler encounters syntax errors in a program, it prevents
the code from compiling successfully and will not create a .class file
until errors are not corrected. An error message will be displayed on
the output screen.
Example of Syntax Error: Missing semicolon
Consider the following code.

In the above code, semicolon is missing at the end of the int b =


4b=4 statement.
Example of Syntax Error: Missing bracket
Consider the following code.

In the above code the closing curly bracket of the main() method is
missing.
Example of Syntax Error: Misspelled Keyword
Consider the following code.

• In the above code, the System keyword in System.out.println() name is


misspelled as a system.
• Lower cased!
Example of Syntax Error: Cannot find a symbol
Consider the following code.

• In the above code, we have not imported the java.util.Scanner package and
using Scanner to take integer input. This has caused the error.
Example of Syntax Error: Missing double-quote in String
Consider the following code.

• In the above code the Java compiler is throwing multiple errors because it
is not considering the "Hello World!" as a String as it is missing the double
quotes.
RUNTIME ERRORS
• Runtime errors occur when the program has successfully compiled without
giving any errors and creating a ".class" file.
• However, the program does not execute properly. These errors are
detected at runtime or at the time of execution of the program.
• The Java compiler does not detect runtime errors because the Java
compiler does not have any technique to catch these errors as it does not
have all the runtime information available to it. Runtime errors are caught
by Java Virtual Machine (JVM) when the program is running.
• These runtime errors are called exceptions and they terminate the
program abnormally, giving an error statement.
• Exceptions are errors thrown at runtime.
• We can use exception handling techniques in Java to handle these runtime errors.
• In exception handling, the piece of code the programmer thinks can produce the
error is put inside the try block and the programmer can catch the error inside
the catch block.
What causes Run time Errors?
• A runtime error can happen when:
• Dividing an integer by zero.
• Trying to store a value into an array that is not compatible type.
• Trying to access an element that is out of range of the array.
• Passing an argument that is not in a valid range or valid value for a method.
• Striving to use a negative size for an array.
• Attempting to convert an invalid string into a number.
Example of Run time error: Accessing array index that
does not exists
• Consider the following code:

• When we try to access an array index that is out of bounding of the


size of the array(in this case it's 5), we get runtime error of array out
of bound.
Example of Run time error: Dividing an integer by zero
• Consider the following code:

• We cannot divide anything from zero so when we try to do that we


get an arithmetic exception at runtime.
Example of Run time error: Using negative size of an
array
• Consider the following code:

• We cannot have a negative-sized array, it is just not possible. We get a


Negative array size exception when we try to do that.
LOGICAL ERRORS
• Logical errors are the hardest to identify and rectify.
• They are hardest to detect because they are neither identified by the
Java compiler nor by the JVM.
• The programmer is entirely responsible for them.
• The program with a logical error will get compiled and executed
successfully but will not give the expected result.
• Logical errors can be detected by application testers when they
compare the actual result with the program's expected result.
What causes Logical Errors
• These type of errors occur due to the following reasons:
• Not correctly understanding what the program needed to do
• Using the incorrect logical operator in a selection statement.
• Missing or incorrect positioning of brackets in mathematical calculations, which means
that incorrect result is returned.
• Loops that execute more or fewer times than intended.

• Debugging logic errors often involves tracking the values of variables,


as code is executed step by step.
• Many IDE’s offer a “Watch window” that allows the programmer to
specify one or more variables to watch.
• Dry running, which is where the programmer goes through the code
line by line using a trace table is a manual approach to the same task.
Example of Logical Errors: Program to print even
numbers
• Consider the following code:

• The programmer wants to print even numbers but, instead of using a


modulus operator (%) he/she uses a divide operator (/).
• The actual output and the expected output do not match which means the
programmer has committed a logical error somewhere in the program. We
wanted to print even numbers, but we got 0 and 1 because we were
using "/" and not "%".
SEMANTIC ERRORS
• A semantic error has to do with meaning. If a program contains this
kind of error, it will successfully run, but won’t output the correct
result. Debugging is not that easy with a semantic error.
• A semantic error occurs when a statement is syntactically valid, but
does not do what the programmer intended.
• Modern compilers have been getting better at detecting certain types
of common semantic errors (e.g. use of an uninitialized variable).
• The semantic error can arises using the wrong variable or using wrong
operator or doing operation in wrong order.
Example of Semantic Error: Use of a non-initialized
variable
• Consider the following code:

• The variable is not initialized, therefore cannot be incremented!


Example of Semantic Error: Type incompatibility
• Consider the following code:

• The variable is of type integer and a string is provided!


• Types String and int are not compatible!
Example of Semantic Error: Errors in expressions
• Consider the following code:

• The operation string to be subtracted from integer is incorrect!


Example of Semantic Error: Unknown references
• Consider the following code:
Example of Semantic Error: Array index out of
range
• Consider the following code:

• This kind of error is called dynamic semantic error


CMP 202- COMPUTER PROGRAMMING II
LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
PROGRAM TESTING
• A Recap of What a Program mean
• A computer program is a set of instructions that is used as a process
of creating a software program by using programming language. It is
simply the collection of instructions for a computer to perform a
specific function and achieve a particular result.
• It is developed and used by a single programmer or group of
programmers.
• A program includes fewer features and limited functionalities. The
functionality of a program is dependent on the compiler.
• The size of the program is small that exists between kilobytes (Kb) to
Megabytes (Mb).
What is a Software?
• Software is a set of programs that enables the hardware to perform a
specific task.
• All the programs that run the computer are software. It is a collection
of procedures, instructions, documentation that tells a computer
exactly what to do or allows users to interact with a computer.
• Unlike hardware, the software can be seen but cannot be touched as
it is virtual, not physical. It can be affected by viruses. The size of
software is large as compared to programs. It has more features and
functionalities.
• Unlike the programs, software requires more time to be developed.
Its features include safety, security, correctness, etc.
• Software is compiled, tested, and debugged in the development
phase. Every software has a user interface that may be in graphical
format or in the form of a command prompt.
WHAT IS TESTING?
• Testing is the process of executing a program to find errors. To make
our program/software perform well it should be error-free.
• If testing is done successfully it will remove all the errors from the
program/software.
• Software testing is the process of assessing the functionality of a
software program.
• The process checks for errors and gaps and whether the outcome of
the application matches desired expectations before the software is
installed and goes live.
TESTING TECHNIQUES
• There are two main methodologies of testing: white-box and black-
box testing.
• White-box testing examines the internal structure of a program and
attempts to test each logical case. White-box testing can be thought
of as "transparent" box testing: the tester can see and test a specific
section of code. For instance, in white-box testing, an IF-THEN-ELSE
statement would be tested with both a TRUE condition and a FALSE
condition. Unfortunately, there are a few problems with white-box
testing:
• the tester often does not have access to the source code
• white-box testing can be exponentially large (for n IF-THEN-ELSE statements,
there are 2n different combinations of values)
----TESTING TECHNIQUES
• These problems with white-box testing lead to the more practical
black-box testing methodology.
• Black-box testing (also known as data-driven or input/output-driven
testing) in which the tester views the program as a black box, and as
such, the inner workings of the program are unknown.
• The main tool used in black-box testing is the specification of the
program: that is, the tester attempts to determine what input causes
the output of the program to be different from what the
specifications would require.
----TESTING TECHNIQUES
• As a general rule within black-box testing, the tester should test the
"good" input (i.e. a positive integer), "bad" input (i.e. casual mistakes,
such as 04 instead of the integer 4), and the "ugly" input (i.e.
malicious mistakes, such as the string "Hello" instead of the integer
4).
• If you view "ugly" testing as unnecessary, and feel that that "Garbage
In, Garbage Out" (GIGO) should be the motto of testing, note that
others would strongly disagree: for instance, Beizer states "[GIGO] is
one of the worst cop-outs ever invented by the computer industry“. If
a program is designed to ensure that nuclear reactors run safely, and
the user happens to type "1.0" instead of "1" (Garbage In), it would
be disastrous to have a meltdown (Garbage Out).
• In summary the motto of proper programming should be: "Garbage
In, Nice-error-message Out."
WHY IS SOFTWARE TESTING IMPORTANT?
• Software testing is the culmination of application development
through which software testers evaluate code by questioning it.
• This evaluation can be brief or proceed until all stakeholders are satisfied.
• Software testing identifies bugs and issues in the development
process so they're fixed prior to product launch.
• This approach ensures that only quality products are distributed to
consumers, which in turn elevates customer satisfaction and trust.
REASONS FOR SOFTWARE TESTING
• The following are important reasons why software testing should be
incorporated into application development:
• Identifies defects early: Developing complex applications can leave room for
errors. Software testing is imperative, as it identifies any issues and defects
with the written code so they can be fixed before the software product is
delivered.
• Improves product quality: When it comes to customer appeal, delivering a
quality product is an important metric to consider. An exceptional product
can only be delivered if it's tested effectively before launch. Software testing
helps the product pass quality assurance and meet the criteria and
specifications defined by the users.
• Increases customer trust and satisfaction. Testing a product throughout its
development lifecycle builds customer trust and satisfaction, as it provides
visibility into the product's strong and weak points. By the time customers
---- REASONS FOR SOFTWARE TESTING
• Detects security vulnerabilities. Insecure application code can leave
vulnerabilities that attackers can exploit. Since most applications are
online today, they can be a leading vector for cyber attacks and
should be tested thoroughly during various stages of application
development.
• For example, a web application published without proper software
testing can easily fall victim to a cross-site scripting attack where the
attackers try to inject malicious code into the user's web browser by
gaining access through the vulnerable web application.
• The nontested application thus becomes the vehicle for delivering the
malicious code, which could have been prevented with proper
software testing.
---- REASONS FOR SOFTWARE TESTING
• Helps with scalability. A type of nonfunctional software testing
process, scalability testing is done to gauge how well an application
scales with increasing workloads, such as user traffic, data volume
and transaction counts. It can also identify the point where an
application might stop functioning and the reasons behind it, which
may include meeting or exceeding a certain threshold, such as the
total number of concurrent app users.
• Saves money. Software development issues that go unnoticed due to
a lack of software testing can haunt organizations later with a bigger
price tag. After the application launches, it can be more difficult to
trace and resolve the issues, as software patching is generally more
expensive than testing during the development stages.
STEPS IN SOFTWARE TESTING
• 1. Verification: it refers to the set of tasks that ensure that the
software correctly implements a specific function.
• “Are we building the product right?”
• 2. Validation: it refers to a different set of tasks that ensure that the
software that has been built is traceable to customer requirements.
• “Are we building the right product?”
CLASSIFICATION OF SOFTWARE TESTING
Software Testing can be broadly classified into two types:
• 1. Manual Testing: Manual testing includes testing software manually, i.e.,
without using any automation tool or any script. In this type, the tester takes over
the role of an end-user and tests the software to identify any unexpected
behavior or bug. There are different stages for manual testing such as unit
testing, integration testing, system testing, and user acceptance testing.
• Testers use test plans, test cases, or test scenarios to test software to ensure the
completeness of testing. Manual testing also includes exploratory testing, as
testers explore the software to identify errors in it.
• 2. Automation Testing: Automation testing, which is also known as Test
Automation, is when the tester writes scripts and uses another software to test
the product. This process involves the automation of a manual process.
Automation Testing is used to re-run the test scenarios quickly and repeatedly,
that were performed manually in manual testing.
• Apart from regression testing, automation testing is also used to test the
application from a load, performance, and stress point of view. It increases the
test coverage, improves accuracy, and saves time and money when compared to
manual testing.
LEVELS OF SOFTWARE TESTING
Software level testing can be majorly classified into 4 levels:
• Unit Testing: A level of the software testing process where individual
units/components of a software/system are tested. The purpose is to
validate that each unit of the software performs as designed.
• Example: For example, there is a straightforward calculator program.
The unit test can be written by the developer to determine whether
the user enters two numbers and obtains the correct total for the
additional capability.
---- LEVELS OF SOFTWARE TESTING
• Integration Testing: A level of the software testing process where
individual units are combined and tested as a group. The purpose of
this level of testing is to expose faults in the interaction between
integrated units.
• Example: When an airline's website is used by a user to purchase a
ticket, compatibility testing should be conducted when integrating an
airline website with a payment processing system.
---- LEVELS OF SOFTWARE TESTING
• System Testing: A level of the software testing process where a
complete, integrated system/software is tested. The purpose of this
test is to evaluate the system’s compliance with the specified
requirements.

• Acceptance Testing: A level of the software testing process where a


system is tested for acceptability. The purpose of this test is to
evaluate the system’s compliance with the business requirements and
assess whether it is acceptable for delivery.
How to Achieve Effective Software Testing
• Produce thorough bug reports - Document thorough bug reports of
the program after the testing process so that the bugs can be fixed
accordingly.
• Produce concise test cases - Work and produce concise test cases to
refer to them during future testing.
• Participate and talk - Participate in team discussions and meetings
and talk about your test findings to find easy solutions.
• Pose inquiries to yourself - Question yourself about certain doubts
and try to find answers for the same.
• Be optimistic - Always maintain a positive attitude and optimism
while finding a solution for the problems found in the programs.
CMP 202- COMPUTER PROGRAMMING II
LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
Text File I/O
• The java.io package contains nearly every class needed to perform input
and output (I/O) in Java. All these streams represent an input source and
an output destination.
• The stream in the java.io package supports many data such as primitives,
object, localized characters, etc.
• Stream
• A stream can be defined as a sequence of data. There are two kinds of
Streams:
• InPutStream: The InputStream is used to read data from a source. This stream is
used for reading data from the files.
• Objects can be created using the keyword new and there are several types of constructors
available.
• OutPutStream: The OutputStream is used for writing data to a destination. This
stream is used to create a file and write data into it.
• The stream would create a file, if it doesn't already exist, before opening it for output.
Stream

• Java provides strong but flexible support for I/O related to files.
• The Files can be classified into two major categories: Binary files and Text
files.
• A binary file is a file whose contents must be handled as a sequence of binary digits.
• A text file is a file whose contents are to be handled as a sequence of characters.
• Why use files for I/O?
• Files provide permanent storage of data.
• Files provide a convenient way to deal with large quantities of data.
What are Standard Streams?
• All the programming languages provide support for standard I/O where the
user's program can take input from a keyboard and then produce an output
on the computer screen.
• Recall that, in Java the I/O is handled by objects called streams. Java
provides the following three standard streams as described as follows:
• Standard Input: This is used to feed the data to user's program and usually
a keyboard is used as standard input stream and represented as System.in.
• Standard Output: This is used to output the data produced by the user's
program and usually a computer screen is used for standard output stream
and represented as System.out.
• Standard Error: This is used to output the error data produced by the
user's program and usually a computer screen is used for standard error
stream and represented as System.err.
Java BufferedReader Class
• Java BufferedReader class is used to read the text from a character-
based input stream.
• It can be used to read data line by line by readLine() method.
• It makes the performance fast. It inherits Reader class.
• Let's see the declaration for Java.io.BufferedReader class:
public class BufferedReader extends Reader
Java BufferedReader class constructors
• The following table summarizes the constructors and their description
Java BufferedReader class methods
Opening a text file for reading
• A stream of the class BufferedReader is created and connected to a text file
for reading as follows:
BufferedReader streamName = new BufferedReader(new FileReader(filename));
• Where, filename is a File object or a constant string or a String variable
containing the name or the full path of the file to be read.
• Example of valid filenames:
“myinput.txt”,“C:\\homework\\StudentTest.java”, “C:/homework/StudentTest.java”

• Both BufferedReader and FileReader classes belong to the java.io


package. The FileReader constructor throws a
FileNotFoundException, if the text file to be opened for reading does
not exist.
• The FileNotFoundException is a subclass of the class IOException.
Closing a stream
• When a program has finished writing to or reading from a file, it
should close the stream connected to that file by calling the close
method of the stream:
streamName.close();

• The close method is defined as:


public void close() throws IOException

• When a stream is closed, the system releases any resources used to


connect the stream to a file.
• If a program does not close a stream before the program terminates,
then the system will automatically close that stream.
Reading a text file
After a stream has been connected to a text-file for reading, the readLine or
read methods of the stream can be used to read from the file:
• public String readLine()throws IOException
• public int read()throws IOException
• The readLine method reads a line of input from the file and returns that
line as a string. If readLine attempts is to read beyond the end of file, null is
returned.
• The read method reads a single character from the file and returns that
character as an integer value.
• To obtain the character, a type cast is required:
char next=(char) inputStream.read();
• If read attempts is to read beyond the end of the file, -1 is returned.
• Note: A Type Casting is when a value of one primitive data type is assign to
another type such as int to double or double to int.
Reading a Text File: Example1
• The following program displays the contents of the file myinput.txt on
the screen by reading one character at a time:
Reading a text file: Example2
• The following program displays the ID, number of quizzes taken, and
average of each student in grades.txt:
Reading a text file: Example2 –Additional Explanation

• Note: A StringTokenizer class breaks a string into tokens. It uses the


following methods as shown in the program above:
• nextToken() - Returns the next token from the StringTokenizer object.

• countTokens() – Returns the total number of tokens.

• hasMoreTokens() – Checks if there are more tokens


Opening a text file for Writing
• A stream is created and connected to a text file for writing by a statement of
the form:
PrintWriter streamName =new PrintWriter(new FileWriter(filename));
• Any preexisting file by the same name and in the same folder is destroyed. If
the file does not exist it is created.
• A stream is created and connected to a text file for appending by a statement of
the form:
PrintWriter streamName = new PrintWriter(new FileWriter(filename , true));
• Any preexisting file by the same name is not destroyed. If the file does not exist
it is created.
• Both PrintWriter and FileWriter classes belong to java.io package. FileReader
uses FileInputStream and FileWriter uses FileOutputStream.
• But note that, the FileReader reads two bytes at a time and FileWriter writes
two bytes at a time.
Writing to a Text File
• The PrintWriter class has methods print and println.
• The print method prints output without generating a new line.
• The println method prints output, it then generates a new line.
• Each constructor of the FileWriter can throw an IOException:
public FileWriter(String filename) throws IOException
public FileWriter(String filename , boolean appendFlag)throws IOException
Example: Appending to a Text-file
The following program appends a message to the file datafile.txt
Example: Writing to a Text-file
The following program copies the first 200 non-blank characters from one file to another.
CMP 202- COMPUTER PROGRAMMING II
LECTURE SERIES
OVERVIEW OF THE COURSE OUTLINE
➢Principles of Good programming
➢Structured programming concepts
➢Errors and Debugging
➢Testing
➢Text Files and IO
➢Strings Processing
Strings Processing
• What is a String?
• A String is a sequence of characters enclosed in double quotes such
as “Salaam Alaikum””. Typically, “A” is a string but ‘A’ is a character.
String processing is a very frequent application. Thus, Java provides
special support for strings. A string is an instance of Java’s built in
String class.

• How to create a string object?


• Strings are objects. Like any object, a string object can be created in
two ways as follows:
• By string literal
• By new keyword
Creating String Object by String Literal
• Java String literal is created by using double quotes. For Example:
String s="Salaam Shabaab";

• Each time you create a string literal, the JVM checks the "string
constant pool" first. If the string already exists in the pool, a reference
to the pooled instance is returned. If the string doesn't exist in the
pool, a new string instance is created and placed in the pool. For
example:
String s1="Welcome";

String s2="Welcome";//It doesn't create a new instance


• Note: String objects are stored in a special memory area known as
the "string constant pool".
Creating String Object by new keyword

• Java String can also be created by using the new operator as in:
String greeting = new String(“Salaam Shabaab”);
//creates two objects and one reference variable
• In such case, JVM will create a new string object in normal (non-pool) heap
memory, and the literal "Salaam Shabaab" will be placed in the string constant
pool. The variable greeting will refer to the object in a heap (non-pool).
Internal Representation of Strings
• Internally, String objects are represented as a sequence of characters
indexed from 0. For example, the string object created by the statement:
String greeting = “Salaam Shabaab”; is represented as follows:

Many string methods return results based on this indexing:


char charAt(int index) Returns the char value for the particular index
• For example, the statement:
char letter = greeting.charAt(5);

• stores the character ‘m’ in the character variable letter.


---- Internal Representation of Strings
We can also ask a string object its length by calling its length()
method:
int length() Returns the length of this string.

• For example, the statement:


int charCount = greeting.length();

• stores 14 in the integer variable charCount.


Getting Substring from a String
A common operation on Strings is extracting a substring from a given string.
String substring(int start) Returns the substring from start to the end of the string
String substring(int start, int end) Returns the substring from start to end but not
including the character at end.

For example, the statement:


String sub2 = greeting.substring(7)
• Creates the substring “Shabaab” that is referred to by sub2.

• For example, the statement:


String sub1 = greeting.substring(0, 6);
• Creates the substring “Salaam” that is referred to by sub1.
Concatenating Strings
• Concatenation means joining two or more strings together. Java
allows two strings to be concatenated using the ‘+’ operator.
• For Example:
String firstName = “Amr”;
String lastName = “Al-Ibrahim”;
String fullName = lastName+” “+firstName;

fullName “Al-Ibrahim Amr”

• If one of the operands in an expression a string, Java automatically


converts the other to a string and concatenates them.
• For Example:
String course = “CMP”;
int code = 202;
String courseCode = course+code;
------ Concatenating Strings
• We frequently use the concatenation operator in println statements:
System.out.println(“The area =“+area);
• You need to be careful with concatenation operator. For example, what is the output of the
following statement?
System.out.println(“Sum =“+5+6);
• Example: The two strings can also be join in Java using the concat() method as follows:
Comparing Strings
• Strings are compared by comparing their characters left to right. Unicode codes
are used in the comparison.
• Note that lowercase letters are different from uppercase letters.
• The String class has the following methods for checking whether two strings are
equal:
Comparing Strings
The following table shows some examples of applying these methods. Assuming
the following declarations:
String s1 = “Salaam”;
String s2 = “Shabaab”;
String s3 = “SALAAM”;

Exercise: What is the result of s1.equalsIgnoreCase(s3) ?


Comparing Strings
Sometimes we need to know if a string is less than another. Accordingly, the
String class has the following additional comparison methods:
Comparing Strings
• Assuming the following declarations:
String s1 = “Salaam”;
String s2 = “Shabaab”;
String s3 = “SALAAM”;
• We have:

• Execercise: What is the result of s1.compareToIgnoreCase(s3)?


Comparing Strings
• Example: Consider the following program that compares 3 strings as follows
Finding the index of a character or substring
The following methods return an index given a character or substring:
Finding the index of a character or substring
Example 1: The program below finds the index of some strings
Finding the index of a character or substring
Example 2: The program below finds the substring of the “0123456789”string
Case conversion and Trimming of Strings
It can be useful to convert a string to upper or lower case

• For example, the statements:


String greeting = “Salaam Shabaab”;
String greeting2 = greeting.toUpperCase();
• Create two string objects. The object referenced by greeting2 stores “SALAAM
SHABAAB”
Case conversion and Trimming of Strings
• Example: The following program change “ABCDEF” to lower case

• Another useful method of String is trim():

• For example, the statement:


String s = “ Salaam “.trim();
Stores “Salaam” in the string referenced by s.
Case conversion and Trimming of Strings
• Note that, return ‘\r’, tab ‘\t’, new line ‘\n’ and space ‘ ’ are all white space
characters.
• All the methods of the String class can also be applied to anonymous string
objects (also called string literals) as shown in the above example.

• Example: This program returns a string whereby any leading and trailing
whitespaces will be removed.
Replace method in Strings
• Another useful String method is also replace() which replaces occurrences of
character with a specified new character.

• Example: Write a program that replaces ‘m’ and ‘M’.


Strings are Immutable!
• Another special feature of Strings is that they are immutable. That is, once a
string object is created, its content cannot be changed.
• Thus, all methods that appear to be modifying string objects are actually
creating and returning new string objects.
• For example, consider the following:
Strings are Immutable!
Instead of changing the greeting object, another object is created. The former is
garbage collected.

The fact that Strings are immutable makes string processing very efficiently in
Java.
More String Methods
We have discussed some of the most important methods of the string class.
For a complete list, check the Java SDK documentation.
Usmanu Danfodiyo University, Sokoto
Department of Computer Science

CMP 202: Computer Programming II

SEARCHING

1
CONTENTS

✓ What is Searching?

✓ Types of Searching

▪ Linear Search

▪ Binary Search

2
WHAT IS SEARCHING?

3
SEARCHING
❖ We know that today’s computers store a lot of information.
❖ To retrieve this information proficiently we need a very efficient way of
doing it and to make sure we are retrieving the right information.

❖ Searching is a method or procedure used to find a specific item or element


within a collection of data.
❖ These methods/procedures are widely used in computer science and are
crucial for tasks like:
✓ Searching for a particular record in a database,
✓ finding an element in a sorted list, or
✓ locating a file on a computer. 4
SEARCHING (Cont)…
❖ Searching is one of the most common actions performed in regular business
applications.
❖ This involves fetching data stored in structures like Arrays, List, Map, etc.
❖ More often than not, this search operation determines the responsiveness
of the application for the end-user.
❖ There are certain ways of organizing the data that improve the search
process.
❖ That means, if we keep the data in proper order, it is easy to search for the
required element.
❖ Sorting is one of the techniques for making the elements ordered
5
TYPES OF SEARCHING
❖ Here are some common types of search algorithms.
✓ Linear Search
✓ Binary Search
✓ Hashing
✓ Interpolation Search
✓ Tree-based Searching
✓ Ternary Search
✓ Jump Search
✓ Exponential Search
✓ Fibonacci Search
✓ Interpolation Search for Trees
✓ Hash-based Searching (e.g., Bloom Filter)
✓ String Searching Algorithms
6
LINEAR SEARCH

7
LINEAR SEARCH
✓ Linear or Sequential Search is the simplest of search algorithms.

✓ Linear Search has no pre-requisites for the state of the underlying data

structure.

✓ Linear Search involves sequential searching for an element in the given

data structure until either the element is found or the end of the structure is

reached.

✓ If the element is found, we usually just return its position in the data

structure.

✓ If not, we usually return -1


8
LINEAR SEARCH (CONT)...
✓ Let the element to be searched be x.
✓ Start from the leftmost element of arr[ ] and one by one compare x with
each element of arr[ ].
✓ If x matches with an element then return that index.
✓ If x doesn’t match with any of the elements then return -1.

9
LINEAR SEARCH (Example)
public static int linearSearch(int arr[], int elementToSearch) {

for (int index = 0; index < arr.length; index++) {

if (arr[index] == elementToSearch)

return index;

return -1;

}
10
LINEAR SEARCH (Example)...
To test it, we'll use a simple Array of integers: Here, we are searching for “67” in the below array

89 57 91 47 95 3 27 22 67 99

With a simple helper method to print the result:


public static void print(int elementToSearch, int index) {
if (index == -1){
System.out.println(elementToSearch + " not found.");
}
else {
System.out.println(elementToSearch + " found at index: " + index);
}
}
Output ➔ 67 found at index: 8
11
LINEAR SEARCH (Examples)…..
class linearSearch {
// Function for linear search
public static int search(int arr[ ], int x)
{
int n = arr.length;
// Traverse array arr[]
for (int i = 0; i < n; i++) {
// If element found then return that index
if (arr[i] == x)
return i;
}
return -1;
}
12
LINEAR SEARCH (Example)...
// Driver Code
public static void main(String args[])
{ 2 3 4 10 40
// Given arr[]
int arr[] = { 2, 3, 4, 10, 40 };
// Element to search
int x = 10;
// Function Call Output:
int result = search(arr, x);
Element is present at index 3
if (result == -1)
System.out.print("Element is not present in
array");
else
System.out.print("Element is present" + " at index
" + result);
}
} 13
APPLICATIONS OF LINEAR SEARCH
Linear search has several practical applications in computer science and beyond. Here are
some examples:

✓ Phonebook Search: Linear search can be used to search through a phonebook to find a
person’s name, given their phone number.
✓ Spell Checkers: The algorithm compares each word in the document to a dictionary of
correctly spelled words until a match is found.
✓ Finding Minimum and Maximum Values: Linear search can be used to find the minimum
and maximum values in an array or list.
✓ Searching through unsorted data: Linear search is useful for searching through unsorted
data.

14
ADVANTAGES OF LINEAR SEARCH
✓ Simplicity: Linear search is a very simple algorithm to understand and
implement.
✓ Works with unsorted data: Linear search works well with unsorted data. It
does not require any pre-processing or sorting of the data before
performing the search.
✓ Low memory usage: Linear search only requires a small amount of memory
to store the index of the current element being searched.
✓ Easy to debug: Because linear search is a simple algorithm, it is easy to
debug and troubleshoot any issues that may arise.
15
DISADVANTAGES OF LINEAR SEARCH
✓ Inefficient for large datasets: As the size of the dataset grows, the time
taken by linear search also increases proportionally.
✓ Limited applicability: Linear search is only suitable for datasets that are not
too large or not too complex.
✓ No early termination: Linear search does not have a mechanism to
terminate early once the target element is found.
✓ Inefficient for sorted data: When the data is already sorted, linear search is
not efficient because it needs to check each element one by one, even if
it has already passed the target element.
16
BINARY SEARCH

17
BINARY SEARCH
❖ Binary or Logarithmic Search is one of the most commonly used search
algorithms primarily due to its quick search time.

❖ This kind of search uses the Divide and Conquer methodology and requires
the data set to be sorted beforehand.
❖ If data is not sorted, then it to be sorted or we use Linear Search

❖ It divides the input collection into equal halves, and with each iteration
compares the target element with the element in the middle.

18
BINARY SEARCH (CONT)....
❖ If the element is found, the search ends.

❖ Else, we continue looking for the element by dividing and selecting the
appropriate partition of the array, based on if the target element is
smaller or bigger than the middle element.

❖ The search terminates when the firstIndex (our pointer) goes


past lastIndex (last element), which implies we have searched the whole
array and the element is not present.

19
BINARY SEARCH (CONT)....
Below are the steps:

✓ Compare x with the middle element.

✓ If x matches with middle element, we return the mid index.

✓ Else If x is greater than the mid element, then x can only lie in the right half
subarray after the mid element. So we recur for right half.

✓ Else (x is smaller) recur for the left half.

20
BINARY SEARCH (Example)...
Let’s use the below array

3 11 21 29 41 54 61 78 110 127

✓ Target element is 78.

✓ Divide the array index into 2 equal halves (9/2) = 4.5 = 4

✓ Element @ index 4 is not equal to 78 but it is less than 78

✓ Therefore we element the first half of the array:

54 61 78 110 127

✓ Divide the array into 2 equal halves (4/2) = 2

✓ Element @ index 2 is equal to 78

21
BINARY SEARCH (Example)...
public static int binarySearch(int arr[], int firstElement, int lastElement,
int elementToSearch) {

// termination condition

if (lastElement >= firstElement) {

int mid = firstElement + (lastElement - firstElement) / 2;

// if the middle element is our goal element, return its index

if (arr[mid] == elementToSearch)

return mid;

3 22 27 47 57 67 89 91 95 99
22
BINARY SEARCH (Example)...
// if the middle element is bigger than the goal element

if (arr[mid] > elementToSearch)

return binarySearch(arr, firstElement, mid - 1, elementToSearch);

// else, recursively call the method with narrowed data

return binarySearch(arr, mid + 1, lastElement, elementToSearch);

return -1;
Output:
} 67 found at index: 5
We can use this algorithm like this:

int index = binarySearch(new int[]{3, 22, 27, 47, 57, 67, 89, 91, 95, 99}
23
ADVANTAGES OF BINARY SEARCH

✓ Since it follows the technique to eliminate half of the array elements, it is


more efficient as compared to linear search for large data.

✓ Better time complexity and thus takes less compilation time.

✓ An improvement over linear search as it breaks the array down in half


rather than sequentially traversing through the array elements.

24
DISADVANTAGES OF BINARY SEARCH

✓ Binary Search algorithm could only be implemented over a sorted array.

✓ Small unsorted arrays would take considerate time in sorting and then
searching the desired element.

✓ So, binary search is not preferred in such cases.

✓ It has poor locality of reference compared to linear search algorithm


when comes to in-memory searching for short intervals.

25
APPLICATIONS OF BINARY SEARCH
❖ It is the most commonly used search algorithm in most of the libraries for searching.

❖ The Binary Search tree is used by many data structures as well which store sorted data.

26
Usmanu Danfodiyo University, Sokoto
Department of Computer Science

CMP 202: Computer Programming II

SORTING

1
CONTENTS

❖ What is Sorting?

❖ Types of Sorting Algorithms


✓ Bubble Sort
✓ Selection Sort

2
WHAT IS SORTING?

3
Introduction to Sorting
❖ While getting into the world of programming, many problems will include
working with multiple instances of similar types of data.
❖ Generally, these data will take the help of arrays for their storage.
❖ The bigger question is how to optimize the solution for a particular problem
to fit within a particular amount of time.
❖ The generalized answer is arranging the elements within the array in such a
way that an order is maintained.
❖ This is the process of sorting, used in many programming languages like
Java, Python, and other high-level programming languages.

4
Introduction to Sorting (Cont)…
❖ Sorting is a class of algorithms that are tasked with rearranging the positions of elements of
an array such that all of its elements are either in ascending or descending order.
❖ A good sorting algorithm also needs to ensure that elements having the same value don’t
change their locations in the sorted array.
❖ Sorting is necessary for getting a concrete understanding of data structures and
algorithms.
❖ There are different types of sorting algorithms which include:
✓ Bubble Sort
✓ Selection Sort
✓ Merge Sort
✓ Heap Sort
✓ Insertion Sort

5
BUBBLE SORT

6
Bubble Sort
❖ It is also called sinking sort
❖ While applying this sorting algorithm on an unsorted array, the largest element tends to sink
at the end of the array.
❖ It repeatedly compares a pair of adjacent elements and swaps them if they are in the
wrong order.
3 1 5 2 6 4
❖ First, compare 3 and 1, if the leftmost element is greater than the rightmost element, then
we swap the elements otherwise we will not swap.
❖ In this case, 3 is greater than 1, we then swap and the array will be:

1 3 5 2 6 4

7
Bubble Sort (Cont…)
❖ Then, we compare 3 and 5, if the leftmost element is greater than the rightmost element,
then we swap the elements otherwise we will not swap.
1 3 5 2 6 4
❖ The process will be repeated until we reach the end of 1st Pass and we have the array:

1 3 2 5 4 6
❖ Then we start the 2nd pass by comparing 1 and 3, then 3 and 2 ………
1 2 3 5 4 6

❖ Compare 3 and 5, there will be no swap…. Then compare 5 and 4, there will be a swap
1 2 3 4 5 6

❖ Then we move to the 3rd pass and compare 1 and 2, 2 and 3, 3 and 4 ………
❖ An array becomes sorted when no swap occurs in a given pass.
❖ In this case, after the second pass, we already have a sorted array because all elements
are in the correct position. 8
Bubble Sort (Cont…)
❖ Consider the array: 5 1 9 2 10 n = 5;
boolean isSwapped;
❖ isSwapped is a Boolean variable that keeps track to know if a
for (int i = 0; i < n-1; i++;
swap is done in a given iteration isSwapped = false;
for(int j=0; j<n-1-i; j++;
❖ j at line 4 will be 1 (index 1) at the first iteration.
if (arr[j] > arr[j+1]){
❖ After the first swap, it will be incremented to 2 (index 2). int temp = arr[j];
arr[j] = arr[j+1];
❖ j is incremented at the end of every iteration
arr[j+1] = temp;
❖ temp is used to store the element that will be moved from the isSwapped = true;
}
leftmost side, in this case, temp will hold 5 and after 1 has
}
been swapped into index 0, then the element in temp will be If (isSwapped == false)
break;
swapped to index 1
}
❖ The for loop exits when j=4 and that marks the end of 1st pass.
1 5 2 9 10
1 2 5 9 10
❖ Line 9 is true, meaning the array is not sorted.
❖ Once line 12 is true, then the array is sorted.
9
Bubble Sort (Java Implementation)
❖ The below code shows implementation of bubble sort in Java programming
public class Bubblesort{
public void printArray(int[] arr) { if (isSwapped ==false){
int n = arr.length; break;
for (int i=0; i<n; i++) { }
System.out.print(arr[i] + " "); }
} }
System.out.println();
} public static void main (String[] args) {
int[] arr = new int[] {5, 1, 2, 9, 10};
public void sort(int[] arr){ BubbleSort bs = newBubbleSort();
int n = arr.length; bs.printArray(arr);
boolean isSwapped; bs.sort(arr);
bs.printArray(arr);
for (i=0; i < n-1; i++){ }
isSwapped = false; }
for (int j=0; j < n-1-i; j++){
//compare adjacent elements
if (arr[j] > arr[j+1]){
//create a temp location to swap element at index j
int temp = arr[j]; Output:
arr[j] = arr[j+1];
arr[j+1] = temp;
5 1 2 9 10
isSwapped = true;
} 1 2 5 9 10
}
10
SELECTION SORT

11
Selection Sort
❖ In selection sort, we divide the given array into two parts – sorted and unsorted part.
❖ The algorithm sorts an array by repeatedly finding the minimum in an unsorted array and
making it part of the sorted array.
❖ From unsorted part, we pick minimum element and swap it with leftmost element of
unsorted part.
❖ After swap, the element now becomes part of the sorted array.
0 1 2 3 4
3 1 5 2 6
Sorted Unsorted
❖ It repeated till unsorted part is empty and all element are moved to the sorted part.
0
1 3 5 2 6
Sorted Unsorted

12
Selection Sort (Example)
❖ Lets use Selection sort to sort the below array
0 1 2 3 4 5 0 1 2 3 4 5
3 1 5 2 6 4 1 3 5 2 6 4
Sorted Unsorted
❖ After the 1st Pass, 1 is found to be the smallest element, then we swap and move 1 to the
unsorted part. 0
1 3 5 2 6 4

Sorted Unsorted

❖ Then, we move to the 2nd Pass, we found 2 to be the smallest, we swap it with the first
element in the unsorted part: 2 5 3 6 4
❖ We then move 2 to the sorted part of the array
0 1
1 2 5 3 6 4
Sorted Unsorted 13
Selection Sort (Example…)
❖ We move to the 3rd pass, we have the below after the pass
1 2 3 5 6 4

Sorted Unsorted

❖ Then we move to the 4th Pass, then we will have the below array
1 2 3 4 6 5

Sorted Unsorted
❖ At the end of the 5th Pass, we will have:

1 2 3 4 5 6

Sorted Unsorted
❖ Since, we only have one element left in the unsorted part, it means all elements are in their
correct position.
1 2 3 4 5 6

14
Selection Sort (Cont…)
❖ Consider the array: 5 1 10 2 9 n = 5;
Public void sort(int[]arr){
int n = arr.length;
❖ After 1st Pass 1 5 10 2 9
for(int i=0; i<n-1; i++){
int min = i;
for(int j=i+1; j<n; j++){
❖ After 2nd Pass 1 2 10 5 9 if(arr[j] < arr[min]){
min = j;
}
1 2 5 10 9 }
❖ After 3rd Pass
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
❖ After the 4th Pass 1 2 5 9 10
}
}

❖ The algorithm will terminate because when the condition


i<n-1 at line is tested, it will be true.
❖ The remaining element “10” is in its correct position 15
Selection Sort (Java Implementation)
❖ The below code shows implementation of bubble sort in Java programming

public class SelectionSort{ public static void main (String[] args) {


public void printArray(int[] arr) { int[] arr = new int[] {5, 1, 2, 9, 10};
int n = arr.length; SelectionSort ss = newSelectionSort();
for (int i=0; i<n; i++) { ss.printArray(arr);
System.out.print(arr[i] + " "); ss.sort(arr);
} ss.printArray(arr);
System.out.println(); }
} }

public void sort(int[] arr){


int n = arr.length;
for(int i=0; i<n-1; i++){
int min = i;
for(int j=i+1; i<n; j++){ Output:
if arr[j] < arr[min]{
min = j;
} 5 1 2 9 10
} 1 2 5 9 10
int temp = arr[min];
arr[min] = arr[i]
arr[i] = temp;
}
}

16
END OF SORTING

17
Usmanu Danfodiyo University, Sokoto
Department of Computer Science

CMP 202: Computer Programming II

RECURSION

1
CONTENTS

❖ What is Recursion?

❖ Examples

❖ Halting Condition

❖ Advantages & Disadvantages of Recursion

2
WHAT IS RECURSION?

3
Introduction to Recursion
❖ A process in which a function calls itself directly or indirectly is
called recursion and the corresponding function is called a
recursive function.

❖ Using a recursive algorithm, certain problems can be solved


quite easily

❖ This technique provides a way to break complicated problems


down into simple problems which are easier to solve.
4
Example
❖ A Method that prints Hi

public class RecursionMthd{


public static void main (String [] args){
sayHi();
}
private static void sayHi(){
System.out.print (“Hi!”);
sayHi();
}
}
❖ This will print Hi! Over 1000 times and the terminates the program with an error message.
❖ Whenever a java program is running, anytime it enters a new method, it puts all information such as
the name of the method, references to variables etc. for the method into a “call stack”
❖ When it finishes executing the method, it will take the information off the call stack.
❖ But, in this scenario, it will be putting and removing the information on the call stack until when the
stack overflow error occurs and the program stops.
5
Example (Cont)…
❖ We need a exit strategy that will make the program terminate.

public class RecursionMthd{


public static void main (String [] args){
sayHi(100);
}
private static void sayHi(int count){
System.out.print (“Hi!”);
if (count<=1){
return;
}
sayHi(count -1);
}
}
❖ This will print Hi 100 times and then terminates without any error.
❖ Base case is needed whenever you are using recursion in programming, if not used, the method will
call itself infinitely.
❖ A base case simply refers when a program should terminate or stop.
6
Example: Factorial using Recursion
❖ Calculating the Factorial of 5
❖ Factorial of a number is calculated by multiplying the number with all numbers it
preceded.
❖ The Factorial of 5 will be 5*4*3*2*1

public class Factorial{


public static void main (String [] args){
System.out.println(factorial(5));
}
private static int factorial(int n){
if (n==1){
return 1;
}
else {
return n* factorial(n-1);
}
}
❖ OUTPUT: 120 7
Example: Factorial using Recursion (Cont…)
public class Factorial{
public static void main (String [] args){
System.out.println(factorial(5));
}
private static int factorial(int n){
if (n==1){
System.out.println(“factorial(“+ n +”) = 1”);
return 1;
}
else {
System.out.println(“factorial(“+ n +”) = “ + n +” * factorial(“ + (n-1) +”)”);
return n* factorial(n-1);
}
}
}
OUTPUT
Factorial(5) = 5 * factorial(4)
Factorial(4) = 4 * factorial(3)
Factorial(3) = 3 * factorial(2)
Factorial(2) = 2 * factorial(1)
Factorial(1) = 1
120 8
Halting Condition
❖ Just as loops can run into the problem of infinite looping, recursive functions
can run into the problem of infinite recursion.
❖ Infinite recursion is when the function never stops calling itself.
❖ Every recursive function should have a halting condition (Base case), which
is the condition where the function stops calling itself.
❖ The developer should be very careful with recursion as it can be quite easy
to slip into writing a function which never terminates, or one that uses
excess amounts of memory or processor power.
❖ However, when written correctly recursion can be a very efficient and
mathematically-elegant approach to programming.
9
Advantages & Disadvantages of recursion
❖ Advantages

✓ Recursion provides a clean and simple way to write code.

✓ Some problems are inherently recursive like tree traversals, Tower of Hanoi, etc. For such
problems, it is preferred to write recursive code.

❖ Disadvantages

✓ The recursive program has greater space requirements than the iterative program as
all functions will remain in the stack until the base case is reached.

✓ It also has greater time requirements because of function calls and returns overhead.

Note: Both recursive and iterative programs have the same problem-solving powers, i.e.,
every recursive program can be written iteratively and vice versa is also true.
10
SNAP TEST

11
Snap Test

Write a recursive method to get the factorial of 3 and print the output

12
Solution
public class Factorial{
public static void main (String [] args){
System.out.println(factorial(3));
}
private static int factorial(int n){
if (n==1){
System.out.println(“factorial(“+ n +”) = 1”);
return 1;
}
else {
System.out.println(“factorial(“+ n +”) = “ + n +” * factorial(“ + (n-1) +”)”);
return n* factorial(n-1);
}
}
}
OUTPUT
Factorial(3) = 3 * factorial(2)
Factorial(2) = 2 * factorial(1)
Factorial(1) = 1
6
13

You might also like